2017-10-02 11:27:54 -07:00

184 lines
4.1 KiB
JavaScript

import {
GL, AnimationLoop, Framebuffer, Cube, setParameters, clear, Matrix4, radians
} from 'luma.gl';
const SCENE_FRAGMENT = `\
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D uShadowMap;
uniform float uShadow;
varying vec4 shadowCoord;
varying vec3 normal;
void main(void) {
float d = clamp(dot(normalize(normal), vec3(0,1,0)), 0.25, 1.0);
float s = 1.0;
if (texture2D(uShadowMap, shadowCoord.xy).z < shadowCoord.z - 0.005) {
s -= 0.5 * uShadow;
}
float c = d * s;
gl_FragColor = vec4(c,c,c,1);
}
`;
const SCENE_VERTEX = `\
#define SHADER_NAME scene.vs
attribute vec3 positions;
attribute vec3 normals;
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
uniform mat4 uShadowView;
uniform mat4 uShadowProj;
varying vec4 shadowCoord;
varying vec3 normal;
void main(void) {
gl_Position = uProjection * uView * uModel * vec4(positions, 1.0);
normal = vec3(uModel * vec4(normals, 0.0));
mat4 bias = mat4(
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0
);
shadowCoord = bias * uShadowProj * uShadowView * uModel * vec4(positions, 1.0);
}
`;
const SHADOWMAP_VERTEX = `\
#define SHADER_NAME shadowmap.vs
attribute vec3 positions;
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
void main(void) {
gl_Position = uProjection * uView * uModel * vec4(positions, 1.0);
}
`;
const SHADOWMAP_FRAGMENT = `\
#ifdef GL_ES
precision highp float;
#endif
void main(void) {
gl_FragColor = vec4(0,0,gl_FragCoord.z,1);
}
`;
// const q = 1;
// const y = -3;
// const plane = [
// -q, y, q, q, y, q, q, y, -q,
// -q, y, q, q, y, -q, -q, y, -q
// ];
// const planeBuffers = {
// positions: new Buffer(gl).setData({
// data: new Float32Array(plane),
// size: 3
// })
// };
const animationLoop = new AnimationLoop({
// gl: createGLContext()})
onInitialize: ({gl}) => {
setParameters(gl, {
depthTest: true,
depthFunc: GL.LEQUAL
});
return {
fbShadow: new Framebuffer(gl, {id: 'shadowmap', width: 1024, height: 1024}),
cube: new Cube(gl, {vs: SCENE_VERTEX, fs: SCENE_FRAGMENT}),
shadow: new Cube(gl, {vs: SHADOWMAP_VERTEX, fs: SHADOWMAP_FRAGMENT})
};
},
onRender: ({gl, tick, width, height, aspect, cube, shadow, fbShadow}) => {
const model = new Matrix4()
.translate([0, 6, 0])
.rotateXYZ([tick * 0.01, 0, 0])
.rotateXYZ([0, tick * 0.013, 0]);
const model2 = new Matrix4()
.scale([2, -2, 2])
.translate([0, 0, 0])
.rotateXYZ([0, 0, tick * 0.007]);
// Render the shadow buffer
gl.viewport(0, 0, 1024, 1024);
clear(gl, {framebuffer: fbShadow, color: [1, 1, 1, 1], depth: true});
const lightPos = [0, 8, 0];
const shadowView = new Matrix4().lookAt({eye: lightPos, center: [0, 0, 0], up: [0, 0, -1]});
const shadowProj =
new Matrix4().ortho({left: -4, right: 4, bottom: -4, top: 4, near: 0, far: 64});
shadow.setUniforms({
uModel: model,
uView: shadowView,
uProjection: shadowProj,
uLightPosition: lightPos
})
.draw({
framebuffer: fbShadow
});
// Render the screen
gl.viewport(0, 0, width, height);
clear(gl, {color: [0, 0.2, 0, 1], depth: true});
const camView = new Matrix4().lookAt({eye: [0, 8, 8], center: [0, 3, 0], up: [0, 1, 0]});
const camProj = new Matrix4().perspective({fov: radians(75), aspect, near: 0.1, far: 100});
cube.setUniforms({
uModel: model,
uView: camView,
uProjection: camProj,
uShadowView: shadowView,
uShadowProj: shadowProj,
uShadowMap: fbShadow
});
cube.render({
uShadow: 0.0
});
cube.render({
uModel: model2,
uShadow: 1.0
});
}
});
animationLoop.getInfo = () => {
return `
<p>
Simple <b>shadow mapping</b>.
<p>
A luma.gl <code>Cube</code>, rendering into a shadowmap framebuffer
and then rendering onto the screen.
`;
};
export default animationLoop;
/* expose on Window for standalone example */
/* global window */
if (typeof window !== 'undefined') {
window.animationLoop = animationLoop;
}