Daniel Haehn PRO
Hi, I am a biomedical imaging and visualization researcher who investigates how computational methods can accelerate biological and medical research.
2023
Schedule a meeting!
@staff
more to come soon!
Play it here:
Due 10/15!
#help
@staff
Can you make it at 2pm?
Patrick Cozzi and Liz Dailey
Tuesday e-visit!
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(-10, 10, 0),
new THREE.Vector3(-10, -10, 0),
new THREE.Vector3(10, -10, 0)
);
geometry.faces.push( new THREE.Face3(0, 1, 2));
GPU
Vertex Shader
Fragment Shader
Viewport
From 3D..
..to 2D
vertex coordinates X Y Z
screenspace coordinates X Y
Vertices
Face
Rasterization
The Rendering Pipeline
XTK
X.renderer3D
X.cube
Three.js
THREE.WebGLRenderer
THREE.Scene
THREE.TrackballControls
THREE.PerspectiveCamera
THREE.AmbientLight
THREE.DirectionalLight
WebGL
gl.viewport
gl.createShader
gl.shaderSource
gl.compileShader
gl.getShaderInfoLog
gl.createProgram
gl.attachShader
gl.linkProgram
gl.useProgram
gl.createBuffer
gl.bindBuffer
gl.BufferData
gl.getAttribLocation
gl.vertexAttribPointer
gl.enableVertexAttribArray
gl.clearColor
gl.clear
gl.drawArrays
THREE.Geometry
THREE.Material
THREE.Mesh
1. Initialize WebGL
2. Shaders
3. Create Geometry
4. Connect Shader with Geometry
5. Draw!
setup Canvas
setup GL Context
compile vertex shader
compile fragment shader
attach and link shaders
create vertices
create and bind buffer
put data in
unbind buffer
bind buffer
find vertex attribute in shader source
configure vertex attribute
enable vertex attribute array
clear viewport
clear color buffer
draw vertex arrays
Rendering Primitives
V0
V1
V2
V3
V4
V5
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0 // 0
-0.5, -0.5, 0.0, // V1, V4 // 1
0.5, 0.5, 0.0, // V2, V3 // 2
0.5, -0.5, 0.0 // V5 // 3
] );
var indices = new Uint8Array( [ 0, 1, 2, // Triangle 1
2, 1, 3 ] ); // Triangle 2
0
1
2
3
Indexed Geometry
Before: 6 x 32 bits, Now: 4 x 32 bits
6 x 8 bits == 48 bits
We still save 16 bits.
We save 2 x 32 bits.
gl.ARRAY_BUFFER
gl.ELEMENT_ARRAY_BUFFER
Uniforms
createRectangle()
Rendering Loop
And, they move!
1. Initialize WebGL
2. Shaders
3. Create Geometry
4. Connect Shader with Geometry
5. Draw!
1 Frame
multiple Frames
animate()
1 Rectangle
multiple Rectangles
createRectangle()
createRectangle()
change Offsets!
Fragment Shader
Vertex Shader
attribute vec3 position;
different data for each vertex
uniform vec3 offset;
different data for each gl.drawArray or gl.drawElements call
uniform vec4 color;
Shaderprogram
createRectangle()
return [ v_buffer, i_buffer, color, offset ];
a =
objects = [];
objects.push( a );
objects.push( b );
createRectangle()
b =
return [ v_buffer, i_buffer, color, offset ];
[ a, b ]
[ [ v_buffer, i_buffer, color, offset ], [ v_buffer, i_buffer, color, offset ] ]
objects =
function animate() {
for(var o = 0; o < objects.length; o++) {
var current_object = objects[o];
var current_v_buffer = current_object[0];
var current_i_buffer = current_object[1];
var current_color = current_object[2];
var current_offset = current_object[3];
// pass data to shader
gl.drawElements( gl.TRIANGLES ... )
}
requestAnimationFrame( animate );
}
Transformation
Transformations
Translate
Rotate
Scale
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<title>Default WebGL!</title>
<style>
html, body {
background-color:#000;
margin: 0;
padding: 0;
height: 100%;
overflow: hidden !important;
}
#c {
width: 100%;
height: 100%;
}
</style>
</head>
<script type="text/javascript" src="https://cs460.org/js/glmatrix.js"></script>
<script id="vertexshader" type="glsl">
attribute vec3 a_position;
uniform vec3 u_offset;
void main(void) {
vec3 final_position = a_position;
final_position.x += u_offset.x;
final_position.y += u_offset.y;
final_position.z += u_offset.z;
gl_Position = vec4( final_position, 1.);
}
</script>
<script id="fragmentshader" type="glsl">
precision mediump float;
uniform vec4 u_color;
void main(void) {
gl_FragColor = u_color;
}
</script>
<script>
var c, gl;
var v_shader, f_shader, shaderprogram;
var vertices, indices, v_buffer, i_buffer;
window.onload = function() {
//************************************************************//
//
// INITIALIZE WEBGL
//
c = document.getElementById( 'c' ); // setup canvas
c.width = window.innerWidth;
c.height = window.innerHeight;
gl = c.getContext( 'webgl' ); // setup GL context
gl.viewport(0, 0, c.width, c.height );
//************************************************************//
//
// SHADERS
//
v_shader = gl.createShader( gl.VERTEX_SHADER );
f_shader = gl.createShader( gl.FRAGMENT_SHADER );
// compile vertex shader
gl.shaderSource( v_shader, document.getElementById( 'vertexshader' ).innerText );
gl.compileShader( v_shader );
if (!gl.getShaderParameter( v_shader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog( v_shader ));
}
// compile fragment shader
gl.shaderSource( f_shader, document.getElementById( 'fragmentshader' ).innerText );
gl.compileShader( f_shader );
if (!gl.getShaderParameter( f_shader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog( f_shader ));
}
// attach and link the shaders
shaderprogram = gl.createProgram();
gl.attachShader( shaderprogram, v_shader );
gl.attachShader( shaderprogram, f_shader );
gl.linkProgram( shaderprogram );
gl.useProgram( shaderprogram );
// create multiple rectangles
rectangles = [];
rectangles.push( createRectangle( new Float32Array([-.2,-.2,0]), new Float32Array([1.,1.,1.,1.]) ) );
rectangles.push( createRectangle( new Float32Array([0,0,0]), new Float32Array([1.,0.,0.,1.]) ) );
animate();
};
function createRectangle(offset, color) {
//************************************************************//
//
// CREATE GEOMETRY
//
var vertices = new Float32Array( [
-0.5, 0.5, 0.0, // 0: V0
-0.5, -0.5, 0.0, // 1: V1, V4
0.5, 0.5, 0.0, // 2: V2, V3
0.5, -0.5, 0.0 // 3: V5
] ); // 2 * 4 == 8 bytes
// now use indices
var indices = new Uint8Array( [ 0, 1, 2, 2, 1, 3 ] ); // 6 bytes
var v_buffer = gl.createBuffer(); // create
gl.bindBuffer( gl.ARRAY_BUFFER, v_buffer ); // bind
gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); // put data in
gl.bindBuffer( gl.ARRAY_BUFFER, null ); // unbind
var i_buffer = gl.createBuffer(); // create
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, i_buffer ); // bind
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW ); // put data in
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null ); // unbind
return [v_buffer, i_buffer, offset, color];
};
var step_x = .01;
var step_y = .01;
var direction = -1;
function animate() {
requestAnimationFrame(animate);
gl.clearColor( 0., 0., 0., 0.)
gl.clear( gl.COLOR_BUFFER_BIT );
for( var r = 0; r < rectangles.length; r++ ) {
// current_buffers is a list of [v_buffer, i_buffer]-pairs
var current_buffers = rectangles[r];
var current_v_buffer = current_buffers[0];
var current_i_buffer = current_buffers[1];
var current_offset = current_buffers[2];
var current_color = current_buffers[3];
// update offsets
if ( current_offset[0] <= -1. ) {
// bumped into left end of screen
direction = 1;
} else if ( current_offset[0] >= 1. ) {
// bumped into right end of screen
direction = -1;
}
current_offset[0] += direction*step_x;
if ( current_offset[1] <= -1. ) {
// bumped into left end of screen
direction = 1;
} else if ( current_offset[1] >= 1. ) {
// bumped into right end of screen
direction = -1;
}
current_offset[1] += direction*step_y;
//************************************************************//
//
// CONNECT SHADER WITH GEOMETRY
//
gl.bindBuffer( gl.ARRAY_BUFFER, current_v_buffer );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, current_i_buffer );
// find the attribute in the shader source
var a_position = gl.getAttribLocation( shaderprogram, 'a_position' );
gl.vertexAttribPointer( a_position, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray ( a_position );
// find the uniform in the shader source
var u_offset = gl.getUniformLocation( shaderprogram, 'u_offset' );
gl.uniform3fv( u_offset, current_offset)
var u_color = gl.getUniformLocation( shaderprogram, 'u_color' );
gl.uniform4fv( u_color, current_color );
//************************************************************//
//
// DRAW!
//
// gl.drawArrays( gl.TRIANGLES, 0, 6 );
gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
}
};
</script>
<body>
<canvas id="c"></canvas>
</body>
</html>
5-minute Bonus Opportunity!
createFish ( color, offset )
5-minute Bonus Opportunity!
createFish ( color, offset )
0,0
-.1, 0
.2, 0
0, .1
0, -.1
?, ?
?, ?
5-minute Bonus Opportunity!
createFish ( color, offset )
0,0
-.1, 0
.2, 0
0, .1
0, -.1
.3, -.05
.3, .05
0
1
2
3
4
5
Transformation!
Transformations
Translate
Rotate
Scale
Matrix
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
x, y, z
x, y, z
new
Identity
matrix multiplication
Matrix
1 0 0 t_x
0 1 0 t_y
0 0 1 t_z
0 0 0 1
x, y, z
x, y, z
new
Translation
Matrix
s_x 0 0 t_x
0 s_y 0 t_y
0 0 s_z t_z
0 0 0 1
x, y, z
x, y, z
new
Scaling
Matrix
r r r t_x
r r r t_y
r r r t_z
0 0 0 1
x, y, z
x, y, z
new
Rotation
Sheer!
matrix.set(..) uses row-major ordering!
Matrix
r r r t_x
r r r t_y
r r r t_z
0 0 0 1
x, y, z
x, y, z
new
var m = new Float32Array( [
r, r, r, 0,
r, r, r, 0,
r, r, r, 0,
t_x, t_y, t_z, 1
]);
column-major ordering!
Further Reading
Matrix
1 0 0 t_x
0 1 0 t_y
0 0 1 t_z
0 0 0 1
x, y, z
x, y, z
new
Translation
<script id="vertexshader" type="glsl">
attribute vec3 position;
uniform mat4 transform;
void main(void) {
vec4 final_position = transform * vec4( position, 1.);
gl_Position = final_position;
}
</script>
// ANIMATE..
var u_transform = gl.getUniformLocation( shaderprogram, 'transform' );
current_transform = new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
OFFSET[0], OFFSET[1], 0, 1
]);
gl.uniformMatrix4fv( u_transform, false, current_transform );
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<title>Vanilla WebGL!</title>
<style>
html, body {
background-color:#000;
margin: 0;
padding: 0;
height: 100%;
overflow: hidden !important;
}
#c {
width: 100%;
height: 100%;
}
</style>
</head>
<script type="text/javascript" src="https://cs460.org/js/glmatrix.js"></script>
<script id="vertexshader" type="glsl">
attribute vec3 position;
uniform mat4 transform;
void main(void) {
vec4 final_position = transform * vec4(position, 1.);
gl_Position = final_position;
gl_PointSize = 10.;
}
</script>
<script id="fragmentshader" type="glsl">
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color; //vec4(1., 1., 1., 1.);
}
</script>
<script>
// VARIABLE DECLARATIONS
var c, gl;
var v_shader, f_shader, shaderprogram;
// var vertices, v_buffer, indices, i_buffer;
var objects;
window.onload = function() {
//************************************************************//
//
// INITIALIZE WEBGL
//
c = document.getElementById( 'c' );
c.width = window.innerWidth;
c.height = window.innerHeight;
gl = c.getContext( 'webgl' );
gl.viewport(0, 0, c.width, c.height);
//************************************************************//
//
// SHADERS
//
v_shader = gl.createShader( gl.VERTEX_SHADER );
f_shader = gl.createShader( gl.FRAGMENT_SHADER );
// compile vertex shader
gl.shaderSource( v_shader, document.getElementById( 'vertexshader' ).innerText );
gl.compileShader( v_shader );
if (!gl.getShaderParameter( v_shader, gl.COMPILE_STATUS )) {
console.log(gl.getShaderInfoLog( v_shader ));
}
// compile fragment shader
gl.shaderSource( f_shader, document.getElementById( 'fragmentshader' ).innerText );
gl.compileShader( f_shader );
if (!gl.getShaderParameter( f_shader, gl.COMPILE_STATUS )) {
console.log(gl.getShaderInfoLog( f_shader ));
}
// attach and link the shaders
shaderprogram = gl.createProgram();
gl.attachShader( shaderprogram, v_shader );
gl.attachShader( shaderprogram, f_shader );
gl.linkProgram( shaderprogram );
gl.useProgram( shaderprogram );
// add objects
objects = [];
objects.push(createRectangle(new Float32Array( [1., 1., 0., 1.]),
new Float32Array( [-.3, -.2, 0 ] )));
objects.push(createRectangle(new Float32Array( [1., 0., 0., 1.]),
new Float32Array( [-.1, -.2, 0 ] )));
animate();
};
function createRectangle(color, offset) {
//************************************************************//
//
// CREATE GEOMETRY
//
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0. // 0
-0.5, -0.5, 0.0, // V1, V4. // 1
0.5, 0.5, 0.0, // V2, V3. // 2
0.5, -0.5, 0.0 // V5. // 3
] );
indices = new Uint8Array( [
0, 1, 2, 2, 1, 3
] );
var v_buffer = gl.createBuffer(); // create
gl.bindBuffer( gl.ARRAY_BUFFER, v_buffer ); // bind
gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); // put data in
gl.bindBuffer( gl.ARRAY_BUFFER, null ); // unbind
var i_buffer = gl.createBuffer(); // create
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, i_buffer ); // bind
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW ); // put data in
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null ); // unbind
return [v_buffer, i_buffer, color, offset];
};
function animate() {
gl.clearColor( 0., 0., 0., 0. );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
// loop through all objects in the scene
for (var o=0; o<objects.length; o++) {
var current_object = objects[o];
var v_buffer = current_object[0];
var i_buffer = current_object[1];
var current_color = current_object[2];
var current_offset = current_object[3];
// console.log(current_object);
//************************************************************//
//
// CONNECT SHADER WITH GEOMETRY
//
gl.bindBuffer( gl.ARRAY_BUFFER, v_buffer );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, i_buffer );
var a_position = gl.getAttribLocation( shaderprogram, 'position' );
gl.vertexAttribPointer( a_position, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( a_position );
var u_color = gl.getUniformLocation( shaderprogram, 'color' );
gl.uniform4fv( u_color, current_color );
current_offset[0] -= .01;
if (current_offset[0] < -1) {
current_offset[0] = 1;
}
var u_transform = gl.getUniformLocation( shaderprogram, 'transform' );
current_transform = new Float32Array([
.5, 0, 0, 0,
0, .5, 0, 0,
0, 0, .5, 0,
current_offset[0], current_offset[1], 0, 1
]);
gl.uniformMatrix4fv( u_transform, false, current_transform );
//************************************************************//
//
// DRAW!
//
// gl.drawArrays( gl.LINE_LOOP, 0, 6);
gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
}
// THIS IS OUR LOOP
requestAnimationFrame(animate);
};
</script>
<body>
<canvas id="c"></canvas>
</body>
</html>
submit your music
Quiz 6 coming soon!
By Daniel Haehn
Hi, I am a biomedical imaging and visualization researcher who investigates how computational methods can accelerate biological and medical research.