Add a simple model of the Mozilla Monument to the 3D scene

This commit is contained in:
Patrick Walton 2017-09-09 00:04:35 -07:00
parent 473c28e16d
commit 43513da957
7 changed files with 121 additions and 25 deletions

View File

@ -26,6 +26,7 @@ import * as _ from "lodash";
import PathfinderBufferTexture from "./buffer-texture";
const WIDTH: number = 150000;
const PADDING: number = 2000;
const TEXT_DATA_URI: string = "/data/mozmonument.json";
@ -34,12 +35,41 @@ const FONT: string = 'open-sans';
const PIXELS_PER_UNIT: number = 1.0;
const FOV: number = 45.0;
const NEAR_CLIP_PLANE: number = 0.01;
const FAR_CLIP_PLANE: number = 200000.0;
const NEAR_CLIP_PLANE: number = 0.1;
const FAR_CLIP_PLANE: number = 3000.0;
const SCALE: glmatrix.vec3 = glmatrix.vec3.fromValues(1.0 / 200.0, 1.0 / 200.0, 1.0 / 200.0);
const TEXT_TRANSLATION: number[] = [-WIDTH * 0.5, 0.0, WIDTH * 0.5];
const TEXT_TRANSLATION: number[] = [-(WIDTH + PADDING) * 0.5, 0.0, (WIDTH + PADDING) * 0.5];
const MONUMENT_TRANSLATION: glmatrix.vec3 = glmatrix.vec3.fromValues(0.0, -690.0, 0.0);
const MONUMENT_SCALE: glmatrix.vec3 =
glmatrix.vec3.fromValues((WIDTH + PADDING) / 400.0 - 0.5,
700.0,
(WIDTH + PADDING) / 400.0 - 0.5);
const TEXT_COLOR: Uint8Array = new Uint8Array([0xf2, 0xf8, 0xf8, 0xff]);
const MONUMENT_COLOR: number[] = [0x70 / 0xff, 0x80 / 0xff, 0x80 / 0xff];
const CUBE_VERTEX_POSITIONS: Float32Array = new Float32Array([
-1.0, -1.0, -1.0, // 0
1.0, -1.0, -1.0, // 1
-1.0, -1.0, 1.0, // 2
1.0, -1.0, 1.0, // 3
-1.0, 1.0, -1.0, // 4
1.0, 1.0, -1.0, // 5
-1.0, 1.0, 1.0, // 6
1.0, 1.0, 1.0, // 7
]);
const CUBE_INDICES: Uint16Array = new Uint16Array([
0, 1, 2, 2, 1, 3, // bottom
0, 5, 1, 0, 4, 5, // front
2, 4, 0, 2, 6, 4, // left
3, 5, 1, 3, 7, 5, // right
2, 7, 3, 2, 6, 7, // back
4, 5, 6, 6, 5, 7, // top
]);
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
none: NoAAStrategy,
@ -174,6 +204,14 @@ class ThreeDView extends PathfinderDemoView {
this.camera = new PerspectiveCamera(this.canvas);
this.camera.onChange = () => this.setDirty();
this.cubeVertexPositionBuffer = unwrapNull(this.gl.createBuffer());
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cubeVertexPositionBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, CUBE_VERTEX_POSITIONS, this.gl.STATIC_DRAW);
this.cubeIndexBuffer = unwrapNull(this.gl.createBuffer());
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.cubeIndexBuffer);
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, CUBE_INDICES, this.gl.STATIC_DRAW);
}
uploadPathMetadata() {
@ -194,9 +232,7 @@ class ThreeDView extends PathfinderDemoView {
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) {
const startOffset = (pathIndex + 1) * 4;
for (let channel = 0; channel < 3; channel++)
pathColors[startOffset + channel] = 0x00; // RGB
pathColors[startOffset + 3] = 0xff; // alpha
pathColors.set(TEXT_COLOR, startOffset);
const textGlyph = textGlyphs[pathIndex];
const glyphRect = textGlyph.pixelRect(PIXELS_PER_UNIT);
@ -222,6 +258,38 @@ class ThreeDView extends PathfinderDemoView {
throw new PathfinderError("Unsupported antialiasing type!");
}
protected drawSceneryIfNecessary(): void {
// Set up the cube VBO.
const shaderProgram = this.shaderPrograms.demo3DMonument;
this.gl.useProgram(shaderProgram.program);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cubeVertexPositionBuffer);
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.cubeIndexBuffer);
this.gl.vertexAttribPointer(shaderProgram.attributes.aPosition,
3,
this.gl.FLOAT,
false,
0,
0);
this.gl.enableVertexAttribArray(shaderProgram.attributes.aPosition);
// Set uniforms for the monument.
const transform = this.calculateWorldTransform(MONUMENT_TRANSLATION, MONUMENT_SCALE);
this.gl.uniformMatrix4fv(shaderProgram.uniforms.uTransform, false, transform);
this.gl.uniform4f(shaderProgram.uniforms.uColor,
MONUMENT_COLOR[0],
MONUMENT_COLOR[1],
MONUMENT_COLOR[2],
1.0);
// Set state for the monument.
this.gl.enable(this.gl.DEPTH_TEST);
this.gl.depthMask(true);
this.gl.disable(this.gl.SCISSOR_TEST);
// Draw the monument!
this.gl.drawElements(this.gl.TRIANGLES, CUBE_INDICES.length, this.gl.UNSIGNED_SHORT, 0);
}
protected compositeIfNecessary(): void {}
protected updateTimings(timings: Timings) {
@ -244,7 +312,9 @@ class ThreeDView extends PathfinderDemoView {
return glmatrix.vec2.fromValues(1.0, 1.0);
}
protected get worldTransform() {
private calculateWorldTransform(modelviewTranslation: glmatrix.vec3,
modelviewScale: glmatrix.vec3):
glmatrix.mat4 {
const projection = glmatrix.mat4.create();
glmatrix.mat4.perspective(projection,
FOV / 180.0 * Math.PI,
@ -255,13 +325,25 @@ class ThreeDView extends PathfinderDemoView {
const modelview = glmatrix.mat4.create();
glmatrix.mat4.mul(modelview, modelview, this.camera.rotationMatrix);
glmatrix.mat4.translate(modelview, modelview, this.camera.translation);
glmatrix.mat4.scale(modelview, modelview, SCALE);
glmatrix.mat4.translate(modelview, modelview, modelviewTranslation);
glmatrix.mat4.scale(modelview, modelview, modelviewScale);
const transform = glmatrix.mat4.create();
glmatrix.mat4.mul(transform, projection, modelview);
return transform;
}
protected clearForResolve(): void {
this.gl.clearColor(1.0, 1.0, 1.0, 1.0);
this.gl.clearDepth(1.0);
this.gl.depthMask(true);
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
}
protected get worldTransform() {
return this.calculateWorldTransform(glmatrix.vec3.create(), SCALE);
}
protected getModelviewTransform(objectIndex: number): glmatrix.mat4 {
const transform = glmatrix.mat4.create();
glmatrix.mat4.rotateY(transform, transform, Math.PI / 2.0 * objectIndex);
@ -277,10 +359,15 @@ class ThreeDView extends PathfinderDemoView {
return 'direct3DInterior';
}
protected depthFunction: number = this.gl.LESS;
private _scale: number;
private appController: ThreeDController;
private cubeVertexPositionBuffer: WebGLBuffer;
private cubeIndexBuffer: WebGLBuffer;
camera: PerspectiveCamera;
}

View File

@ -63,12 +63,6 @@ export class NoAAStrategy extends AntialiasingStrategy {
view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, view.destFramebuffer);
view.gl.viewport(0, 0, this.framebufferSize[0], this.framebufferSize[1]);
view.gl.disable(view.gl.SCISSOR_TEST);
// Clear.
view.gl.clearColor(1.0, 1.0, 1.0, 1.0);
view.gl.clearDepth(0.0);
view.gl.depthMask(true);
view.gl.clear(view.gl.COLOR_BUFFER_BIT | view.gl.DEPTH_BUFFER_BIT);
}
resolve(view: PathfinderDemoView) {}

View File

@ -135,8 +135,8 @@ export class PerspectiveCamera extends Camera {
if (document.pointerLockElement !== this.canvas)
return;
this.rotation[1] += event.movementX * PERSPECTIVE_ROTATION_SPEED;
this.rotation[0] += event.movementY * PERSPECTIVE_ROTATION_SPEED;
this.rotation[0] += event.movementX * PERSPECTIVE_ROTATION_SPEED;
this.rotation[1] += event.movementY * PERSPECTIVE_ROTATION_SPEED;
if (this.onChange != null)
this.onChange();
@ -144,8 +144,8 @@ export class PerspectiveCamera extends Camera {
get rotationMatrix(): glmatrix.mat4 {
const matrix = glmatrix.mat4.create();
glmatrix.mat4.fromYRotation(matrix, this.rotation[1]);
glmatrix.mat4.rotateX(matrix, matrix, this.rotation[0]);
glmatrix.mat4.fromXRotation(matrix, this.rotation[1]);
glmatrix.mat4.rotateY(matrix, matrix, this.rotation[0]);
return matrix;
}

View File

@ -75,12 +75,6 @@ export default class SSAAStrategy extends AntialiasingStrategy {
view.gl.viewport(0, 0, framebufferSize[0], framebufferSize[1]);
view.gl.scissor(0, 0, usedSize[0], usedSize[1]);
view.gl.enable(view.gl.SCISSOR_TEST);
// Clear.
view.gl.clearColor(1.0, 1.0, 1.0, 1.0);
view.gl.clearDepth(0.0);
view.gl.depthMask(true);
view.gl.clear(view.gl.COLOR_BUFFER_BIT | view.gl.DEPTH_BUFFER_BIT);
}
resolve(view: PathfinderDemoView) {

View File

@ -274,6 +274,8 @@ class SVGDemoView extends PathfinderDemoView {
return 'directInterior';
}
protected depthFunction: number = this.gl.GREATER;
private appController: SVGDemoController;
camera: OrthographicCamera;

View File

@ -505,6 +505,8 @@ class TextDemoView extends MonochromePathfinderView {
return 'directInterior';
}
protected depthFunction: number = this.gl.GREATER;
atlasFramebuffer: WebGLFramebuffer;
atlasDepthTexture: WebGLTexture;

View File

@ -247,6 +247,12 @@ export abstract class PathfinderDemoView extends PathfinderView {
const antialiasingStrategy = unwrapNull(this.antialiasingStrategy);
antialiasingStrategy.prepare(this);
// Clear.
this.clearForResolve();
// Draw "scenery" (used in the 3D view).
this.drawSceneryIfNecessary();
// Perform direct rendering (Loop-Blinn).
if (antialiasingStrategy.shouldRenderDirect)
this.renderDirect();
@ -287,7 +293,7 @@ export abstract class PathfinderDemoView extends PathfinderView {
const meshes = this.meshes[objectIndex];
// Set up implicit cover state.
this.gl.depthFunc(this.gl.GREATER);
this.gl.depthFunc(this.depthFunction);
this.gl.depthMask(true);
this.gl.enable(this.gl.DEPTH_TEST);
this.gl.disable(this.gl.BLEND);
@ -458,6 +464,17 @@ export abstract class PathfinderDemoView extends PathfinderView {
return glmatrix.mat4.create();
}
protected drawSceneryIfNecessary(): void {}
protected clearForResolve(): void {
this.gl.clearColor(1.0, 1.0, 1.0, 1.0);
this.gl.clearDepth(0.0);
this.gl.depthMask(true);
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
}
protected abstract get depthFunction(): number;
protected abstract createAAStrategy(aaType: AntialiasingStrategyName,
aaLevel: number,
subpixelAA: boolean):