Add some basic Phong shading to the monument

This commit is contained in:
Patrick Walton 2017-11-03 18:49:25 -07:00
parent 1e446f816f
commit 8a1e3bc8b2
3 changed files with 110 additions and 42 deletions

View File

@ -28,7 +28,8 @@ import {BUILTIN_FONT_URI, ExpandedMeshData} from "./text";
import {calculatePixelRectForGlyph, GlyphStore, Hint, PathfinderFont} from "./text"; import {calculatePixelRectForGlyph, GlyphStore, Hint, PathfinderFont} from "./text";
import {SimpleTextLayout, TextFrame, TextRun, UnitMetrics} from "./text"; import {SimpleTextLayout, TextFrame, TextRun, UnitMetrics} from "./text";
import {TextRenderContext, TextRenderer} from './text-renderer'; import {TextRenderContext, TextRenderer} from './text-renderer';
import {assert, FLOAT32_SIZE, panic, PathfinderError, Range, unwrapNull} from "./utils"; import {assert, FLOAT32_SIZE, panic, PathfinderError, Range, UINT16_SIZE} from "./utils";
import {unwrapNull} from "./utils";
import {DemoView, Timings} from "./view"; import {DemoView, Timings} from "./view";
const TEXT_AVAILABLE_WIDTH: number = 150000; const TEXT_AVAILABLE_WIDTH: number = 150000;
@ -63,7 +64,12 @@ const MONUMENT_SCALE: glmatrix.vec3 =
(TEXT_AVAILABLE_WIDTH * 0.5 + TEXT_PADDING) * TEXT_SCALE[2]); (TEXT_AVAILABLE_WIDTH * 0.5 + TEXT_PADDING) * TEXT_SCALE[2]);
const TEXT_COLOR: Uint8Array = new Uint8Array([0xf2, 0xf8, 0xf8, 0xff]); const TEXT_COLOR: Uint8Array = new Uint8Array([0xf2, 0xf8, 0xf8, 0xff]);
const MONUMENT_COLOR: number[] = [0x70 / 0xff, 0x80 / 0xff, 0x80 / 0xff];
const AMBIENT_COLOR: glmatrix.vec3 = glmatrix.vec3.clone([0.063, 0.063, 0.063]);
const DIFFUSE_COLOR: glmatrix.vec3 = glmatrix.vec3.clone([0.356, 0.264, 0.136]);
const SPECULAR_COLOR: glmatrix.vec3 = glmatrix.vec3.clone([0.490, 0.420, 0.324]);
const MONUMENT_SHININESS: number = 32.0;
const CUBE_VERTEX_POSITIONS: Float32Array = new Float32Array([ const CUBE_VERTEX_POSITIONS: Float32Array = new Float32Array([
-1.0, -1.0, -1.0, // 0 -1.0, -1.0, -1.0, // 0
@ -85,6 +91,15 @@ const CUBE_INDICES: Uint16Array = new Uint16Array([
4, 5, 6, 6, 5, 7, // top 4, 5, 6, 6, 5, 7, // top
]); ]);
const MONUMENT_NORMALS: glmatrix.vec4[] = [
glmatrix.vec4.clone([ 0.0, -1.0, 0.0, 1.0]),
glmatrix.vec4.clone([ 0.0, 0.0, -1.0, 1.0]),
glmatrix.vec4.clone([-1.0, 0.0, 0.0, 1.0]),
glmatrix.vec4.clone([ 1.0, 0.0, 0.0, 1.0]),
glmatrix.vec4.clone([ 0.0, 0.0, 1.0, 1.0]),
glmatrix.vec4.clone([ 0.0, 1.0, 0.0, 1.0]),
];
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = { const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
none: NoAAStrategy, none: NoAAStrategy,
ssaa: SSAAStrategy, ssaa: SSAAStrategy,
@ -393,22 +408,20 @@ class ThreeDRenderer extends Renderer {
constructor(renderContext: ThreeDView) { constructor(renderContext: ThreeDView) {
super(renderContext); super(renderContext);
const gl = renderContext.gl;
this.camera = new PerspectiveCamera(renderContext.canvas, { this.camera = new PerspectiveCamera(renderContext.canvas, {
innerCollisionExtent: MONUMENT_SCALE[0], innerCollisionExtent: MONUMENT_SCALE[0],
}); });
this.camera.onChange = () => renderContext.setDirty(); this.camera.onChange = () => renderContext.setDirty();
this.cubeVertexPositionBuffer = unwrapNull(renderContext.gl.createBuffer()); this.cubeVertexPositionBuffer = unwrapNull(gl.createBuffer());
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, this.cubeVertexPositionBuffer); gl.bindBuffer(gl.ARRAY_BUFFER, this.cubeVertexPositionBuffer);
renderContext.gl.bufferData(renderContext.gl.ARRAY_BUFFER, gl.bufferData(gl.ARRAY_BUFFER, CUBE_VERTEX_POSITIONS, gl.STATIC_DRAW);
CUBE_VERTEX_POSITIONS,
renderContext.gl.STATIC_DRAW);
this.cubeIndexBuffer = unwrapNull(renderContext.gl.createBuffer()); this.cubeIndexBuffer = unwrapNull(gl.createBuffer());
renderContext.gl.bindBuffer(renderContext.gl.ELEMENT_ARRAY_BUFFER, this.cubeIndexBuffer); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.cubeIndexBuffer);
renderContext.gl.bufferData(renderContext.gl.ELEMENT_ARRAY_BUFFER, gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, CUBE_INDICES, gl.STATIC_DRAW);
CUBE_INDICES,
renderContext.gl.STATIC_DRAW);
} }
attachMeshes(expandedMeshes: PathfinderMeshData[]) { attachMeshes(expandedMeshes: PathfinderMeshData[]) {
@ -597,31 +610,33 @@ class ThreeDRenderer extends Renderer {
} }
private drawMonument(): void { private drawMonument(): void {
const gl = this.renderContext.gl; const renderContext = this.renderContext;
const gl = renderContext.gl;
// Set up the cube VBO. // Set up the cube VBO.
const monumentProgram = this.renderContext.shaderPrograms.demo3DMonument; const monumentProgram = this.renderContext.shaderPrograms.demo3DMonument;
this.renderContext.gl.useProgram(monumentProgram.program); gl.useProgram(monumentProgram.program);
this.renderContext.gl.bindBuffer(this.renderContext.gl.ARRAY_BUFFER, gl.bindBuffer(gl.ARRAY_BUFFER, this.cubeVertexPositionBuffer);
this.cubeVertexPositionBuffer); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.cubeIndexBuffer);
this.renderContext.gl.bindBuffer(this.renderContext.gl.ELEMENT_ARRAY_BUFFER, gl.vertexAttribPointer(monumentProgram.attributes.aPosition, 3, gl.FLOAT, false, 0, 0);
this.cubeIndexBuffer); gl.enableVertexAttribArray(monumentProgram.attributes.aPosition);
this.renderContext.gl.vertexAttribPointer(monumentProgram.attributes.aPosition,
3,
this.renderContext.gl.FLOAT,
false,
0,
0);
this.renderContext.gl.enableVertexAttribArray(monumentProgram.attributes.aPosition);
// Set uniforms for the monument. // Set uniforms for the monument.
const transform = this.calculateWorldTransform(MONUMENT_TRANSLATION, MONUMENT_SCALE); const projection = this.calculateProjectionTransform();
gl.uniformMatrix4fv(monumentProgram.uniforms.uTransform, false, transform); const modelview = this.calculateModelviewTransform(MONUMENT_TRANSLATION, MONUMENT_SCALE);
gl.uniform4f(monumentProgram.uniforms.uColor, gl.uniformMatrix4fv(monumentProgram.uniforms.uProjection, false, projection);
MONUMENT_COLOR[0], gl.uniformMatrix4fv(monumentProgram.uniforms.uModelview, false, modelview);
MONUMENT_COLOR[1], const cameraModelview = this.calculateCameraModelviewTransform();
MONUMENT_COLOR[2], const lightPosition = glmatrix.vec4.clone([-1750.0, -700.0, 1750.0, 1.0]);
1.0); glmatrix.vec4.transformMat4(lightPosition, lightPosition, cameraModelview);
gl.uniform3f(monumentProgram.uniforms.uLightPosition,
lightPosition[0] / lightPosition[3],
lightPosition[1] / lightPosition[3],
lightPosition[2] / lightPosition[3]);
gl.uniform3fv(monumentProgram.uniforms.uAmbientColor, AMBIENT_COLOR);
gl.uniform3fv(monumentProgram.uniforms.uDiffuseColor, DIFFUSE_COLOR);
gl.uniform3fv(monumentProgram.uniforms.uSpecularColor, SPECULAR_COLOR);
gl.uniform1f(monumentProgram.uniforms.uShininess, MONUMENT_SHININESS);
// Set state for the monument. // Set state for the monument.
gl.enable(gl.DEPTH_TEST); gl.enable(gl.DEPTH_TEST);
@ -630,8 +645,19 @@ class ThreeDRenderer extends Renderer {
gl.disable(gl.SCISSOR_TEST); gl.disable(gl.SCISSOR_TEST);
gl.disable(gl.BLEND); gl.disable(gl.BLEND);
// Draw the monument! // Loop over each face.
gl.drawElements(gl.TRIANGLES, CUBE_INDICES.length, gl.UNSIGNED_SHORT, 0); for (let face = 0; face < 6; face++) {
// Set the uniforms for this face.
const normal = glmatrix.vec4.clone(MONUMENT_NORMALS[face]);
glmatrix.vec4.transformMat4(normal, normal, this.camera.rotationMatrix);
gl.uniform3f(monumentProgram.uniforms.uNormal,
normal[0] / normal[3],
normal[1] / normal[3],
normal[2] / normal[3]);
// Draw the face!
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, face * 6 * UINT16_SIZE);
}
} }
private drawDistantGlyphs(): void { private drawDistantGlyphs(): void {
@ -760,9 +786,7 @@ class ThreeDRenderer extends Renderer {
this.renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); this.renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
} }
private calculateWorldTransform(modelviewTranslation: glmatrix.vec3, private calculateProjectionTransform(): glmatrix.mat4 {
modelviewScale: glmatrix.vec3):
glmatrix.mat4 {
const canvas = this.renderContext.canvas; const canvas = this.renderContext.canvas;
const projection = glmatrix.mat4.create(); const projection = glmatrix.mat4.create();
glmatrix.mat4.perspective(projection, glmatrix.mat4.perspective(projection,
@ -770,12 +794,30 @@ class ThreeDRenderer extends Renderer {
canvas.width / canvas.height, canvas.width / canvas.height,
NEAR_CLIP_PLANE, NEAR_CLIP_PLANE,
FAR_CLIP_PLANE); FAR_CLIP_PLANE);
return projection;
}
private calculateCameraModelviewTransform(): glmatrix.mat4 {
const modelview = glmatrix.mat4.create(); const modelview = glmatrix.mat4.create();
glmatrix.mat4.mul(modelview, modelview, this.camera.rotationMatrix); glmatrix.mat4.mul(modelview, modelview, this.camera.rotationMatrix);
glmatrix.mat4.translate(modelview, modelview, this.camera.translation); glmatrix.mat4.translate(modelview, modelview, this.camera.translation);
return modelview;
}
private calculateModelviewTransform(modelviewTranslation: glmatrix.vec3,
modelviewScale: glmatrix.vec3):
glmatrix.mat4 {
const modelview = this.calculateCameraModelviewTransform();
glmatrix.mat4.translate(modelview, modelview, modelviewTranslation); glmatrix.mat4.translate(modelview, modelview, modelviewTranslation);
glmatrix.mat4.scale(modelview, modelview, modelviewScale); glmatrix.mat4.scale(modelview, modelview, modelviewScale);
return modelview;
}
private calculateWorldTransform(modelviewTranslation: glmatrix.vec3,
modelviewScale: glmatrix.vec3):
glmatrix.mat4 {
const projection = this.calculateProjectionTransform();
const modelview = this.calculateModelviewTransform(modelviewTranslation, modelviewScale);
const transform = glmatrix.mat4.create(); const transform = glmatrix.mat4.create();
glmatrix.mat4.mul(transform, projection, modelview); glmatrix.mat4.mul(transform, projection, modelview);

View File

@ -10,9 +10,30 @@
precision mediump float; precision mediump float;
uniform vec4 uColor; uniform vec3 uLightPosition;
uniform vec3 uAmbientColor;
uniform vec3 uDiffuseColor;
uniform vec3 uSpecularColor;
uniform float uShininess;
uniform vec3 uNormal;
varying vec3 vPosition;
void main() { void main() {
// TODO(pcwalton): Lighting. vec3 normal = normalize(uNormal);
gl_FragColor = uColor; vec3 lightDirection = normalize(uLightPosition - vPosition);
float lambertian = max(dot(lightDirection, normal), 0.0);
float specular = 0.0;
if (lambertian > 0.0) {
vec3 viewDirection = normalize(-vPosition);
vec3 halfDirection = normalize(lightDirection + viewDirection);
float specularAngle = max(dot(halfDirection, normal), 0.0);
specular = pow(specularAngle, uShininess);
}
vec3 color = uAmbientColor + lambertian * uDiffuseColor + specular * uSpecularColor;
gl_FragColor = vec4(color, 1.0);
} }

View File

@ -10,10 +10,15 @@
precision mediump float; precision mediump float;
uniform mat4 uTransform; uniform mat4 uProjection;
uniform mat4 uModelview;
attribute vec3 aPosition; attribute vec3 aPosition;
varying vec3 vPosition;
void main() { void main() {
gl_Position = uTransform * vec4(aPosition, 1.0); vec4 position = uModelview * vec4(aPosition, 1.0);
vPosition = position.xyz / position.w;
gl_Position = uProjection * position;
} }