- Start from a working WebGL library implementation scaffold (EIGHT).
- Replace parts of library (Geometry, Camera, Material, Geometric3, Matrix4).
- Restart from a working native WebGL implementation scaffold.
- Refactor into a modular API (library).
- Capstone project is to use own WebGL library in an application.
Last active
September 11, 2016 16:02
-
-
Save mathdoodle/9490a592182176417957a41468a94a11 to your computer and use it in GitHub Desktop.
WireCube Scaffold
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A camera scaffold. | |
*/ | |
export default class Camera implements EIGHT.Facet { | |
// | |
// Implementing the Facet interface provides uniform values. | |
// Implementing eye, look, up enables trackball controls. | |
// | |
/** | |
* The position of the camera. | |
*/ | |
eye = {x:0, y:0, z:0}; | |
/** | |
* A point along the direction in which te camera is looking. | |
*/ | |
look = {x:0, y:0, z:0}; | |
/** | |
* The approximate up direction. | |
*/ | |
up = {x:0, y:0, z:0}; | |
/** | |
* The projection transformation. | |
*/ | |
private uProjection: EIGHT.Matrix4 = EIGHT.Matrix4.one(); | |
/** | |
* The view transformation. | |
*/ | |
private uView: EIGHT.Matrix4 = EIGHT.Matrix4.one(); | |
/** | |
* | |
*/ | |
constructor() { | |
// Parameters may be required according to the type of projection. | |
} | |
setUniforms(visitor: EIGHT.FacetVisitor) { | |
console.log(`eye => ${this.eye}`); | |
console.log(`look => ${this.look}`); | |
console.log(`up => ${this.up}`); | |
// The matrics must be updated (efficiently) based upon eye, look, up. | |
visitor.matrix4fv('uProjection', this.uProjection.elements, false); | |
visitor.matrix4fv('uView', this.uView.elements, false); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Displays an exception by writing it to a <pre> element. | |
*/ | |
export default function displayError(e: any) { | |
const stderr = <HTMLPreElement>document.getElementById('errors') | |
stderr.style.color = "#FF0000" | |
stderr.innerHTML = `${e}` | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* vec(x, y, z) corresponds to x * e1 + y * e2 + z * e3 | |
*/ | |
export function vec(x: number, y: number, z: number): EIGHT.VectorE3 { | |
const that: EIGHT.VectorE3 = { | |
get x(): number { | |
return x; | |
}, | |
get y(): number { | |
return y; | |
}, | |
get z(): number { | |
return z; | |
} | |
}; | |
return that; | |
} | |
/** | |
* The magnitude of the vector argument. | |
*/ | |
export function magnitude(v: EIGHT.VectorE3): number { | |
// Exercise: Complete this function. | |
// Hint: Use Math.sqrt | |
return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); | |
} | |
/** | |
* The direction of the vector argument. | |
*/ | |
export function direction(v: EIGHT.VectorE3): EIGHT.VectorE3 { | |
// Exercise: Complete this function. | |
const m = magnitude(v); | |
const x = v.x / m; | |
const y = v.y / m; | |
const z = v.z / m; | |
return vec(x, y, z); | |
} | |
/** | |
* The projection of vector b onto the line given by vector a. | |
* This is defined to be the closest point on the line to the point | |
* with coordinates [b.x, b.y. b.z] | |
*/ | |
export function proj(b: EIGHT.VectorE3, a: EIGHT.VectorE3): EIGHT.VectorE3 { | |
// Exercise, using the definition given, compute the projection vector. | |
// You may assume that the space is Euclidean. | |
a = direction(a); | |
const dot = a.x * b.x + a.y * b.y + a.z * b.z; | |
const denom = a.x * a.x + a.y * a.y + a.z * a.z; | |
const f = dot /denom; | |
// It would be nice if we could scale ate the vector level of abstraction. | |
const x = f * a.x; | |
const y = f * a.y; | |
const z = f * a.z; | |
return vec(x, y, z); | |
} | |
export function reflect(a: EIGHT.VectorE3, n: EIGHT.VectorE3): EIGHT.VectorE3 { | |
const p = proj(a, n); | |
// It would be nice if we could subtract at the vector level of abstraction. | |
const x = a.x - 2 * p.x; | |
const y = a.y - 2 * p.y; | |
const z = a.z - 2 * p.z; | |
return vec(x, y, z); | |
} | |
export function normalize(v: EIGHT.VectorE3): EIGHT.VectorE3 { | |
// Exercise: Complete this function. | |
const x = 0; | |
const y = 0; | |
const z = 0; | |
return vec(x, y, z); | |
} | |
export function random(): EIGHT.VectorE3 { | |
// Exercise: Complete this function. | |
// Hint: Use Math.random | |
const x = 0; | |
const y = 0; | |
const z = 0; | |
return vec(x, y, z); | |
} | |
export function wedge(...vs: EIGHT.VectorE3[]): any { | |
} | |
wedge(void 0, void 0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function makeColorChangeHandler(color: EIGHT.Color) { | |
return function(value: number[]) { | |
color.r = value[0] / 255; | |
color.g = value[1] / 255; | |
color.b = value[2] / 255; | |
} | |
} | |
export default class GUI extends dat.GUI { | |
showA = true; | |
showB = true; | |
showC = false; | |
showAxes = false; | |
showBox = false; | |
showComponents = false; | |
showDirections = false; | |
showProjection = false; | |
showReflection = false; | |
showUnitSphere = false; | |
constructor() { | |
super(); | |
this.add(this, 'showA'); | |
this.add(this, 'showB'); | |
this.add(this, 'showC'); | |
this.add(this, 'showAxes'); | |
this.add(this, 'showBox'); | |
// this.add(this, 'showComponents'); | |
this.add(this, 'showDirections'); | |
this.add(this, 'showProjection'); | |
this.add(this, 'showReflection'); | |
this.add(this, 'showUnitSphere'); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<style> | |
/* STYLE-MARKER */ | |
</style> | |
<script src="https://jspm.io/system.js"></script> | |
<!-- SHADERS-MARKER --> | |
<!-- SCRIPTS-MARKER --> | |
</head> | |
<body> | |
<canvas id='canvas'></canvas> | |
<pre id='errors'></pre> | |
<script> | |
// CODE-MARKER | |
</script> | |
<script> | |
try { | |
System.import('./index.js'); | |
} | |
catch(e) { | |
alert(`${e}`) | |
} | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Camera from './Camera'; | |
import {e1, e2, e3} from './math'; | |
import GUI from './GUI'; | |
import {proj, reflect, direction} from './Geometric3'; | |
import requestFrame from './requestFrame'; | |
import WireCube from './WireCube'; | |
const a = e1.clone().scale(1); | |
const aColor = EIGHT.Color.red.clone(); | |
const b = (1.5 * e1 + e2).scale(1); | |
const bColor = EIGHT.Color.magenta.clone(); | |
const c = EIGHT.Geometric3.random().grade(1).normalize(); | |
const cColor = EIGHT.Color.yellow.clone(); | |
/** | |
* Wrapper around the WebGLRenderingContext providing the ContextManager interface. | |
*/ | |
const engine = new EIGHT.Engine('canvas') | |
.size(500, 500) | |
.clearColor(0.1, 0.1, 0.1, 1.0) | |
.enable(EIGHT.Capability.DEPTH_TEST) | |
/** | |
* A collection of objects that can be rendered with a single draw method call. | |
*/ | |
const scene = new EIGHT.Scene(engine) | |
/** | |
* Rendering information that applies to all objects. | |
*/ | |
const ambients: EIGHT.Facet[] = [] | |
/** | |
* Provides the viewing point and perspective transformation. | |
*/ | |
const camera = new EIGHT.PerspectiveCamera() | |
camera.eye.copyVector(e1).addVector(e2, 0.8).addVector(e3, 2).normalize().scale(5) | |
ambients.push(camera) | |
/** | |
* Provides a light color and direction for Lambert shading. | |
*/ | |
const dirLight = new EIGHT.DirectionalLight() | |
ambients.push(dirLight) | |
/** | |
* Controls the camera by accumulating mouse movements then moving and rotating the camera. | |
*/ | |
const trackball = new EIGHT.TrackballControls(camera, window) | |
trackball.subscribe(engine.canvas) | |
trackball.noPan = true; | |
const geometry = new WireCube(engine) | |
const material = new EIGHT.HTMLScriptsMaterial(['line-vs', 'line-fs'], document, [], engine) | |
const box = new EIGHT.Mesh(geometry, material, engine) | |
const basisPos = new EIGHT.Basis({engine}); | |
basisPos.a.scale(10) | |
basisPos.b.scale(10) | |
basisPos.c.scale(10) | |
const basisNeg = new EIGHT.Basis({engine}); | |
basisNeg.a.copy(basisPos.a).neg(); | |
basisNeg.colorA.scale(0.3) | |
basisNeg.b.copy(basisPos.b).neg(); | |
basisNeg.colorB.scale(0.3) | |
basisNeg.c.copy(basisPos.c).neg(); | |
basisNeg.colorC.scale(0.3) | |
const gridXY = new EIGHT.GridXY({engine}); | |
// scene.add(gridXY) | |
const gridYZ = new EIGHT.GridYZ({engine, yMin:-5, yMax: +5, zMin:-5, zMax: +5}); | |
// scene.add(gridYZ) | |
const arrow = new EIGHT.Arrow({engine}); | |
arrow.color = EIGHT.Color.yellow | |
const sphere = new EIGHT.Sphere({engine, k: 1, azimuthSegments: 36, elevationSegments:18}) | |
const gui = new GUI(); | |
/** | |
* Animates the scene. | |
*/ | |
const animate = function(timestamp: number) { | |
engine.clear() | |
trackball.update() | |
dirLight.direction.copy(camera.look).sub(camera.eye) | |
if (gui.showA) { | |
arrow.h.copyVector(a); | |
arrow.color.copy(aColor); | |
arrow.render(ambients) | |
if (gui.showDirections) { | |
arrow.h.copyVector(direction(a)); | |
arrow.color.copy(aColor); | |
arrow.render(ambients); | |
} | |
} | |
if (gui.showB) { | |
arrow.h.copyVector(b); | |
arrow.color.copy(bColor); | |
arrow.render(ambients) | |
if (gui.showDirections) { | |
arrow.h.copyVector(direction(b)); | |
arrow.color.copy(bColor); | |
arrow.render(ambients); | |
} | |
} | |
if (gui.showC) { | |
// Reflection onto e3 | |
arrow.h.copyVector(c) | |
arrow.color.copy(cColor); | |
arrow.render(ambients) | |
} | |
if (gui.showAxes) { | |
basisPos.render(ambients) | |
basisNeg.render(ambients) | |
} | |
if (gui.showBox) { | |
box.render(ambients) | |
} | |
if (gui.showComponents) { | |
// Projection onto e1 | |
arrow.h.copyVector(proj(a, e1)) | |
arrow.color = EIGHT.Color.red | |
arrow.render(ambients) | |
// Projection onto e2 | |
arrow.h.copyVector(proj(a, e2)) | |
arrow.color = EIGHT.Color.green | |
arrow.render(ambients) | |
// Projection onto e3 | |
arrow.h.copyVector(proj(a, e3)) | |
arrow.color = EIGHT.Color.blue | |
arrow.render(ambients) | |
} | |
if (gui.showProjection) { | |
arrow.h.copyVector(proj(b, a)) | |
arrow.color.copy(bColor) | |
arrow.render(ambients) | |
if (gui.showDirections) { | |
arrow.h.copyVector(proj(direction(b), a)) | |
arrow.color.copy(bColor) | |
arrow.render(ambients) | |
} | |
if (gui.showA) { | |
arrow.h.copyVector(proj(a, b)) | |
arrow.color.copy(aColor) | |
arrow.render(ambients) | |
} | |
gridYZ.X.copyVector(proj(b,a)) | |
gridYZ.color.copy(bColor) | |
gridYZ.render(ambients); | |
} | |
if (gui.showReflection) { | |
// Reflection onto e3 | |
arrow.h.copyVector(reflect(a, c)) | |
arrow.color.copy(bColor) | |
arrow.render(ambients) | |
} | |
if (gui.showUnitSphere) { | |
sphere.render(ambients) | |
} | |
scene.draw(ambients) | |
requestFrame(animate) | |
} | |
requestFrame(animate) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
varying highp vec4 vColor; | |
void main(void) { | |
gl_FragColor = vColor; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
attribute vec3 aPosition; | |
uniform vec3 uColor; | |
uniform float uOpacity; | |
uniform mat4 uModel; | |
uniform mat4 uProjection; | |
uniform mat4 uView; | |
varying highp vec4 vColor; | |
void main(void) { | |
gl_Position = uProjection * uView * uModel * vec4(aPosition, 1.0); | |
vColor = vec4(uColor, uOpacity); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const e1 = EIGHT.Geometric3.e1(); | |
export const e2 = EIGHT.Geometric3.e2(); | |
export const e3 = EIGHT.Geometric3.e3(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
varying highp vec4 vColor; | |
varying highp vec3 vLight; | |
void main(void) { | |
gl_FragColor = vec4(vColor.xyz * vLight, vColor.a); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
attribute vec3 aPosition; | |
attribute vec3 aNormal; | |
uniform vec3 uColor; | |
uniform float uOpacity; | |
uniform mat4 uModel; | |
uniform mat3 uNormal; | |
uniform mat4 uProjection; | |
uniform mat4 uView; | |
uniform vec3 uAmbientLight; | |
uniform vec3 uDirectionalLightColor; | |
uniform vec3 uDirectionalLightDirection; | |
varying highp vec4 vColor; | |
varying highp vec3 vLight; | |
void main(void) { | |
gl_Position = uProjection * uView * uModel * vec4(aPosition, 1.0); | |
vColor = vec4(uColor, uOpacity); | |
vec3 L = normalize(uDirectionalLightDirection); | |
vec3 N = normalize(uNormal * aNormal); | |
// The minus sign arises because L is the light direction, so we need dot(N, -L) = -dot(N, L) | |
float directionalLightCosineFactor = max(-dot(N, L), 0.0); | |
vLight = uAmbientLight + directionalLightCosineFactor * uDirectionalLightColor; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"description": "WireCube Scaffold", | |
"dependencies": { | |
"davinci-eight": "2.307.0", | |
"dat-gui": "0.5.0" | |
}, | |
"operatorOverloading": true, | |
"name": "copy-of-eight-starter-template", | |
"version": "0.1.0", | |
"keywords": [ | |
"EIGHT", | |
"EightJS", | |
"WebGL", | |
"Getting Started", | |
"Engine", | |
"Scene", | |
"PerspectiveCamera", | |
"DirectionalLight", | |
"TrackballControls", | |
"DomReady", | |
"HTMLCanvasElement", | |
"requestAnimationFrame", | |
"Geometric3" | |
], | |
"author": "David Geo Holmes" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import displayError from './displayError' | |
/** | |
* Catches exceptions thrown in the animation callback and displays them. | |
*/ | |
export default function requestFrame(callback: FrameRequestCallback): number { | |
const wrapper: FrameRequestCallback = function(time: number) { | |
try { | |
callback(time) | |
} | |
catch(e) { | |
displayError(e) | |
} | |
} | |
return window.requestAnimationFrame(wrapper) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { margin: 0; } | |
canvas { width: 500px; height: 500px } | |
#stats { position: absolute; top: 0; left: 0; } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A Geometry for rendering a cube made from lines. | |
*/ | |
export default class WireCube implements EIGHT.Geometry { | |
private buffer: WebGLBuffer; | |
public data: Float32Array; | |
/** | |
* | |
*/ | |
public invalid = true; | |
constructor(private engine: EIGHT.Engine) { | |
const gl = engine.gl; | |
const size = 1; | |
const L = size / 2; | |
this.data = new Float32Array([ | |
-L, -L, -L, +L, -L, -L, | |
-L, +L, -L, +L, +L, -L, | |
-L, -L, +L, +L, -L, +L, | |
-L, +L, +L, +L, +L, +L, | |
-L, +L, +L, -L, +L, -L, | |
+L, +L, +L, +L, +L, -L, | |
-L, -L, +L, -L, -L, -L, | |
+L, -L, +L, +L, -L, -L, | |
-L, -L, -L, -L, +L, -L, | |
+L, -L, -L, +L, +L, -L, | |
-L, -L, +L, -L, +L, +L, | |
+L, -L, +L, +L, +L, +L | |
]); | |
this.buffer = gl.createBuffer(); | |
} | |
bind(material: EIGHT.Material): void { | |
const gl = this.engine.gl; | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer); | |
} | |
unbind(material: EIGHT.Material): void { | |
const gl = this.engine.gl; | |
gl.bindBuffer(gl.ARRAY_BUFFER, null); | |
} | |
draw(material: EIGHT.Material): void { | |
const gl = this.engine.gl; | |
const aPosition = material.getAttribLocation('aPosition'); | |
if (this.invalid) { | |
gl.bufferData(gl.ARRAY_BUFFER, this.data, EIGHT.Usage.STATIC_DRAW); | |
this.invalid = false; | |
} | |
gl.vertexAttribPointer(aPosition, 3, EIGHT.DataType.FLOAT, true, 0, 0); | |
gl.enableVertexAttribArray(aPosition); | |
gl.drawArrays(EIGHT.BeginMode.LINES, 0, 24); | |
gl.disableVertexAttribArray(aPosition); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment