F 11/17 Volume Rendering
M 11/27 Atacama.bio Guest Lecture
F 12/01 WebGPU II
F 11/24 No class (Thanksgiving Recess)
W 11/29 Final Project Fast Forward (60 seconds each!)
M 11/20 Field Trip / Outside Lecture
W 11/22 glTF / WebGPU I
M 12/04 Final Project Presentations I
W 12/06 Final Project Presentations II
F 12/08 Skybox
M 12/11 Final Project Presentations III
W 12/13 Final Recap and Last Lecture!
F 12/22 Final Project Submission
How do we start?
<html>
<head>
<title>WebGPU Hello Triangle</title>
<style>
html, body { width: 100%; height: 100%; padding: 0; margin: 0; }
#c { width: 100%; height: 100%; }
</style>
</head>
<body>
<canvas id="c" width="600" height="600"></canvas>
<script>
async function initWebGPU() {
// Ensure WebGPU is supported
if (!navigator.gpu) {
console.error("WebGPU is not supported. Please use a compatible browser.");
return;
}
// Initialization
const canvas = document.getElementById("c");
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const context = canvas.getContext("webgpu");
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({
device: device,
format: format
});
// Shaders
const shaderCode = `
@vertex
fn vs_main(
@builtin(vertex_index) VertexIndex : u32
) -> @builtin(position) vec4<f32> {
var pos = array<vec2<f32>, 3>(
vec2(0.0, 0.5),
vec2(-0.5, -0.5),
vec2(0.5, -0.5)
);
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4<f32> {
return vec4(1.0, 0.0, 0.0, 1.0);
}
`;
const shaderModule = device.createShaderModule({ code: shaderCode });
// Pipeline Configuration
const pipeline = device.createRenderPipeline({
vertex: {
module: shaderModule,
entryPoint: "vs_main"
},
fragment: {
module: shaderModule,
entryPoint: "fs_main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list"
},
layout: "auto"
});
// Drawing
const commandEncoder = device.createCommandEncoder();
const textureView = context.getCurrentTexture().createView();
const renderPassDescriptor = {
colorAttachments: [{
view: textureView,
loadValue: { r: 0, g: 0, b: 0, a: 1 },
storeOp: 'store',
loadOp: 'clear'
}]
};
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.draw(3, 1, 0, 0);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);
}
window.onload = initWebGPU;
</script>
</body>
</html>
How do we start?
<html>
<head>
<title>Babylon.js</title>
<style>
html, body { width: 100%; height: 100%; padding: 0; margin: 0; }
#c { width: 100%; height: 100%; }
</style>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script>
window.onload = async function() {
var canvas = document.getElementById('c');
var engine = new BABYLON.WebGPUEngine(canvas);
await engine.initAsync();
var scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color3(0., 0., 0.);
var camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 5, 10), scene);
camera.setTarget(BABYLON.Vector3.Zero());
camera.attachControl(canvas, false);
var light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(1, 1, 0));
var customMesh = new BABYLON.Mesh("custom");
customMesh.color = new BABYLON.Color3(1., 0., 0.);
// Set the vertices for the triangle
var positions = [
0, 1, 0, // vertex 0: position (x, y, z)
1, 0, 0, // vertex 1
-1, 0, 0 // vertex 2
];
// Set the indices for the triangle
var indices = [0, 1, 2];
var colors = [1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1];
// Create a vertexData object
var vertexData = new BABYLON.VertexData();
vertexData.positions = positions;
vertexData.indices = indices;
vertexData.colors = colors;
vertexData.applyToMesh(customMesh);
engine.runRenderLoop(function () {
scene.render();
});
// Watch for browser/canvas resize events
window.addEventListener("resize", function () {
engine.resize();
});
};
</script>
</head>
<body>
<canvas id="c"></canvas>
</body>
</html>
How do we start?
<html>
<head>
<title>Taichi.js</title>
<style>
html, body { width: 100%; height: 100%; padding: 0; margin: 0; }
#c { width: 100%; height: 100%; }
</style>
<script src="https://unpkg.com/taichi.js/dist/taichi.umd.js"></script>
<script>
</script>
</head>
<body>
<canvas id="c"></canvas>
</body>
</html>
<html>
<head>
<title>Taichi.js</title>
<style>
html, body { width: 100%; height: 100%; padding: 0; margin: 0; }
#c { width: 100%; height: 100%; }
</style>
<script src="https://unpkg.com/taichi.js/dist/taichi.umd.js"></script>
<script>
window.onload = async function() {
await ti.init();
let htmlCanvas = document.getElementById('c');
htmlCanvas.width = 720;
htmlCanvas.height = 360;
let VBO = ti.field(ti.types.vector(ti.f32, 3), 3);
let IBO = ti.field(ti.i32, 3);
let aspectRatio = htmlCanvas.width / htmlCanvas.height;
let target = ti.canvasTexture(htmlCanvas);
let depth = ti.depthTexture([htmlCanvas.width, htmlCanvas.height]);
ti.addToKernelScope({ VBO, target, IBO, aspectRatio, depth });
await VBO.fromArray([
[-1, 0, 0],
[1, 0, 0],
[0, 1, 0]
]);
await IBO.fromArray([
0, 1, 2
]);
let render = ti.kernel(() => {
let center = [0., 0., 0.];
let eye = [0, 0, 3];
let view = ti.lookAt(eye, center, [0.0, 1.0, 0.0]);
let proj = ti.perspective(70.0, aspectRatio, 0.1, 100);
let mvp = proj.matmul(view);
ti.clearColor(target, [0., 0., 0., 1]);
ti.useDepth(depth);
for (let v of ti.inputVertices(VBO, IBO)) {
let pos = mvp.matmul([v.x, v.y, v.z, 1.0]);
ti.outputPosition(pos);
ti.outputVertex(v);
}
for (let f of ti.inputFragments()) {
ti.outputColor(target, [1.,0.,0.,1.]);
}
});
async function frame() {
render();
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
};
</script>
</head>
<body>
<canvas id="c"></canvas>
</body>
</html>
Sky Box
Sky Sphere
// ...
var geometry = new THREE.SphereGeometry( 500, 60, 40 );
// invert the geometry on the x-axis so that all of the faces point inward
geometry.scale( - 1, 1, 1 );
var texture = new THREE.TextureLoader().load( 'photo.jpg' );
var material = new THREE.MeshBasicMaterial( { map: texture } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
// ...
// ...
// ...
var geometry = new THREE.SphereGeometry( 500, 60, 40 );
var texture = new THREE.TextureLoader().load( 'photo.jpg' );
var material = new THREE.MeshBasicMaterial( { map: texture,
side: THREE.BackSide } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
// ...
Field Trip Footage
Let's code!
cs460student/360/
<html>
<head>
<style>
html, body {
background-color:#000;
margin: 0;
padding: 0;
height: 100%;
overflow: hidden !important;
}
</style>
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@latest/build/three.module.js",
"three/addons/": "https://unpkg.com/three@latest/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
var scene, camera, renderer, ambientLight, light, controls, sphere;
window.onload = function() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set( 0, 0, 500);
renderer = new THREE.WebGLRenderer({ });
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
ambientLight = new THREE.AmbientLight(0x000000);
scene.add( ambientLight );
light = new THREE.DirectionalLight( 0xffffff, 5.0 );
light.position.set( 10, 100, 10 );
scene.add( light );
// TODO
controls = new OrbitControls( camera, renderer.domElement );
animate();
};
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
};
</script>
</head>
<body>
</body>
</html>
Course Evaluations
Quiz 14 coming soon!
MEGAQUIZ too..
submit your music