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 {SimpleTextLayout, TextFrame, TextRun, UnitMetrics} from "./text";
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";
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]);
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([
-1.0, -1.0, -1.0, // 0
@ -85,6 +91,15 @@ const CUBE_INDICES: Uint16Array = new Uint16Array([
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 = {
none: NoAAStrategy,
ssaa: SSAAStrategy,
@ -393,22 +408,20 @@ class ThreeDRenderer extends Renderer {
constructor(renderContext: ThreeDView) {
super(renderContext);
const gl = renderContext.gl;
this.camera = new PerspectiveCamera(renderContext.canvas, {
innerCollisionExtent: MONUMENT_SCALE[0],
});
this.camera.onChange = () => renderContext.setDirty();
this.cubeVertexPositionBuffer = unwrapNull(renderContext.gl.createBuffer());
renderContext.gl.bindBuffer(renderContext.gl.ARRAY_BUFFER, this.cubeVertexPositionBuffer);
renderContext.gl.bufferData(renderContext.gl.ARRAY_BUFFER,
CUBE_VERTEX_POSITIONS,
renderContext.gl.STATIC_DRAW);
this.cubeVertexPositionBuffer = unwrapNull(gl.createBuffer());
gl.bindBuffer(gl.ARRAY_BUFFER, this.cubeVertexPositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, CUBE_VERTEX_POSITIONS, gl.STATIC_DRAW);
this.cubeIndexBuffer = unwrapNull(renderContext.gl.createBuffer());
renderContext.gl.bindBuffer(renderContext.gl.ELEMENT_ARRAY_BUFFER, this.cubeIndexBuffer);
renderContext.gl.bufferData(renderContext.gl.ELEMENT_ARRAY_BUFFER,
CUBE_INDICES,
renderContext.gl.STATIC_DRAW);
this.cubeIndexBuffer = unwrapNull(gl.createBuffer());
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.cubeIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, CUBE_INDICES, gl.STATIC_DRAW);
}
attachMeshes(expandedMeshes: PathfinderMeshData[]) {
@ -597,31 +610,33 @@ class ThreeDRenderer extends Renderer {
}
private drawMonument(): void {
const gl = this.renderContext.gl;
const renderContext = this.renderContext;
const gl = renderContext.gl;
// Set up the cube VBO.
const monumentProgram = this.renderContext.shaderPrograms.demo3DMonument;
this.renderContext.gl.useProgram(monumentProgram.program);
this.renderContext.gl.bindBuffer(this.renderContext.gl.ARRAY_BUFFER,
this.cubeVertexPositionBuffer);
this.renderContext.gl.bindBuffer(this.renderContext.gl.ELEMENT_ARRAY_BUFFER,
this.cubeIndexBuffer);
this.renderContext.gl.vertexAttribPointer(monumentProgram.attributes.aPosition,
3,
this.renderContext.gl.FLOAT,
false,
0,
0);
this.renderContext.gl.enableVertexAttribArray(monumentProgram.attributes.aPosition);
gl.useProgram(monumentProgram.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.cubeVertexPositionBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.cubeIndexBuffer);
gl.vertexAttribPointer(monumentProgram.attributes.aPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(monumentProgram.attributes.aPosition);
// Set uniforms for the monument.
const transform = this.calculateWorldTransform(MONUMENT_TRANSLATION, MONUMENT_SCALE);
gl.uniformMatrix4fv(monumentProgram.uniforms.uTransform, false, transform);
gl.uniform4f(monumentProgram.uniforms.uColor,
MONUMENT_COLOR[0],
MONUMENT_COLOR[1],
MONUMENT_COLOR[2],
1.0);
const projection = this.calculateProjectionTransform();
const modelview = this.calculateModelviewTransform(MONUMENT_TRANSLATION, MONUMENT_SCALE);
gl.uniformMatrix4fv(monumentProgram.uniforms.uProjection, false, projection);
gl.uniformMatrix4fv(monumentProgram.uniforms.uModelview, false, modelview);
const cameraModelview = this.calculateCameraModelviewTransform();
const lightPosition = glmatrix.vec4.clone([-1750.0, -700.0, 1750.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.
gl.enable(gl.DEPTH_TEST);
@ -630,8 +645,19 @@ class ThreeDRenderer extends Renderer {
gl.disable(gl.SCISSOR_TEST);
gl.disable(gl.BLEND);
// Draw the monument!
gl.drawElements(gl.TRIANGLES, CUBE_INDICES.length, gl.UNSIGNED_SHORT, 0);
// Loop over each face.
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 {
@ -760,9 +786,7 @@ class ThreeDRenderer extends Renderer {
this.renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
}
private calculateWorldTransform(modelviewTranslation: glmatrix.vec3,
modelviewScale: glmatrix.vec3):
glmatrix.mat4 {
private calculateProjectionTransform(): glmatrix.mat4 {
const canvas = this.renderContext.canvas;
const projection = glmatrix.mat4.create();
glmatrix.mat4.perspective(projection,
@ -770,12 +794,30 @@ class ThreeDRenderer extends Renderer {
canvas.width / canvas.height,
NEAR_CLIP_PLANE,
FAR_CLIP_PLANE);
return projection;
}
private calculateCameraModelviewTransform(): glmatrix.mat4 {
const modelview = glmatrix.mat4.create();
glmatrix.mat4.mul(modelview, modelview, this.camera.rotationMatrix);
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.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();
glmatrix.mat4.mul(transform, projection, modelview);

View File

@ -10,9 +10,30 @@
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() {
// TODO(pcwalton): Lighting.
gl_FragColor = uColor;
vec3 normal = normalize(uNormal);
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;
uniform mat4 uTransform;
uniform mat4 uProjection;
uniform mat4 uModelview;
attribute vec3 aPosition;
varying vec3 vPosition;
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;
}