Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const { mat4, mat3, vec2, vec3, vec4, quat } = glMatrix;
- let GL = null;
- const _OPAQUE_VS = `#version 300 es
- precision highp float;
- uniform mat3 normalMatrix;
- uniform mat4 modelMatrix;
- uniform mat4 modelViewMatrix;
- uniform mat4 projectionMatrix;
- in vec3 position;
- in vec3 normal;
- in vec3 tangent;
- in vec4 colour;
- in vec2 uv0;
- out vec2 vUV0;
- out vec4 vColour;
- void main(void) {
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- vColour = colour;
- vUV0 = uv0;
- }
- `;
- const _OPAQUE_FS = `#version 300 es
- precision highp float;
- uniform sampler2D diffuseTexture;
- uniform sampler2D normalTexture;
- uniform sampler2D gBuffer_Light;
- uniform vec4 resolution;
- in vec4 vColour;
- in vec2 vUV0;
- layout(location = 0) out vec4 out_FragColour;
- void main(void) {
- vec2 uv = gl_FragCoord.xy / resolution.xy;
- vec4 lightSample = texture(gBuffer_Light, uv);
- vec4 albedo = texture(diffuseTexture, vUV0);
- out_FragColour = (albedo * vec4(lightSample.xyz, 1.0) +
- lightSample.w * vec4(0.3, 0.6, 0.1, 0.0));
- }
- `;
- const _QUAD_VS = `#version 300 es
- precision highp float;
- uniform mat4 modelViewMatrix;
- uniform mat4 projectionMatrix;
- in vec3 position;
- in vec2 uv0;
- void main(void) {
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- }
- `;
- const _QUAD_FS = `#version 300 es
- precision highp float;
- uniform sampler2D gBuffer_Normal;
- uniform sampler2D gBuffer_Position;
- uniform vec3 lightColour;
- #define _LIGHT_TYPE_POINT
- #ifdef _LIGHT_TYPE_DIRECTIONAL
- uniform vec3 lightDirection;
- #endif
- uniform vec3 lightPosition;
- uniform vec3 lightAttenuation;
- uniform vec3 cameraPosition;
- uniform vec4 resolution;
- out vec4 out_FragColour;
- #define saturate(a) clamp(a, 0.0, 1.0)
- float _SmootherStep(float x, float a, float b) {
- x = x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
- return x * (b - a) + a;
- }
- vec2 _CalculatePhong(vec3 lightDirection, vec3 cameraPosition, vec3 position, vec3 normal) {
- vec3 viewDirection = normalize(cameraPosition - position);
- vec3 H = normalize(lightDirection.xyz + viewDirection);
- float NdotH = dot(normal.xyz, H);
- float specular = saturate(pow(NdotH, 32.0));
- float diffuse = saturate(dot(lightDirection.xyz, normal.xyz));
- return vec2(diffuse, diffuse * specular);
- }
- vec4 _CalculateLight_Directional(
- vec3 lightDirection, vec3 lightColour, vec3 position, vec3 normal) {
- vec2 lightSample = _CalculatePhong(-lightDirection, cameraPosition, position, normal);
- return vec4(lightSample.x * lightColour, lightSample.y);
- }
- vec4 _CalculateLight_Point(
- vec3 lightPosition, vec3 lightAttenuation, vec3 lightColour, vec3 position, vec3 normal) {
- vec3 dirToLight = lightPosition - position;
- float lightDistance = length(dirToLight);
- dirToLight = normalize(dirToLight);
- vec2 lightSample = _CalculatePhong(dirToLight, cameraPosition, position, normal);
- float falloff = saturate((lightDistance - lightAttenuation.x) / lightAttenuation.y);
- lightSample *= _SmootherStep(falloff, 1.0, 0.0);
- return vec4(lightSample.x * lightColour, lightSample.y);
- }
- void main(void) {
- vec2 uv = gl_FragCoord.xy / resolution.xy;
- vec4 normal = texture(gBuffer_Normal, uv);
- vec4 position = texture(gBuffer_Position, uv);
- #ifdef _LIGHT_TYPE_DIRECTIONAL
- vec4 lightSample = _CalculateLight_Directional(
- lightDirection, lightColour, position.xyz, normal.xyz);
- #elif defined(_LIGHT_TYPE_POINT)
- vec4 lightSample = _CalculateLight_Point(
- lightPosition, lightAttenuation, lightColour, position.xyz, normal.xyz);
- #endif
- out_FragColour = lightSample;
- }
- `;
- const _QUAD_COLOUR_VS = `#version 300 es
- precision highp float;
- uniform mat4 modelViewMatrix;
- uniform mat4 projectionMatrix;
- in vec3 position;
- in vec2 uv0;
- void main(void) {
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- }
- `;
- const _QUAD_COLOUR_FS = `#version 300 es
- precision highp float;
- uniform sampler2D gQuadTexture;
- uniform vec4 resolution;
- out vec4 out_FragColour;
- void main(void) {
- vec2 uv = gl_FragCoord.xy / resolution.xy;
- out_FragColour = texture(gQuadTexture, uv);
- }
- `;
- const _SIMPLE_VS = `#version 300 es
- precision highp float;
- uniform mat3 normalMatrix;
- uniform mat4 modelMatrix;
- uniform mat4 modelViewMatrix;
- uniform mat4 projectionMatrix;
- in vec3 position;
- in vec3 normal;
- in vec3 tangent;
- in vec2 uv0;
- out vec4 vWSPosition;
- out vec3 vNormal;
- out vec3 vTangent;
- out vec2 vUV0;
- void main(void) {
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
- vNormal = normalize(normalMatrix * normal);
- vTangent = normalize(normalMatrix * tangent);
- vWSPosition = modelMatrix * vec4(position, 1.0);
- vUV0 = uv0;
- }
- `;
- const _SIMPLE_FS = `#version 300 es
- precision highp float;
- uniform sampler2D normalTexture;
- in vec4 vWSPosition;
- in vec3 vNormal;
- in vec3 vTangent;
- in vec2 vUV0;
- layout(location = 0) out vec4 out_Normals;
- layout(location = 1) out vec4 out_Position;
- void main(void) {
- vec3 bitangent = normalize(cross(vTangent, vNormal));
- mat3 tbn = mat3(vTangent, bitangent, vNormal);
- vec3 normalSample = normalize(texture(normalTexture, vUV0).xyz * 2.0 - 1.0);
- vec3 vsNormal = normalize(tbn * normalSample);
- out_Normals = vec4(vsNormal, 1.0);
- out_Position = vWSPosition;
- }
- `;
- class Shader {
- constructor(vsrc, fsrc, defines) {
- defines = defines || [];
- this._Init(vsrc, fsrc, defines);
- }
- _Init(vsrc, fsrc, defines) {
- this._defines = defines;
- vsrc = this._ModifySourceWithDefines(vsrc, defines);
- fsrc = this._ModifySourceWithDefines(fsrc, defines);
- this._vsSource = vsrc;
- this._fsSource = fsrc;
- this._vsProgram = this._Load(GL.VERTEX_SHADER, vsrc);
- this._fsProgram = this._Load(GL.FRAGMENT_SHADER, fsrc);
- this._shader = GL.createProgram();
- GL.attachShader(this._shader, this._vsProgram);
- GL.attachShader(this._shader, this._fsProgram);
- GL.linkProgram(this._shader);
- if (!GL.getProgramParameter(this._shader, GL.LINK_STATUS)) {
- return null;
- }
- this.attribs = {
- positions: GL.getAttribLocation(this._shader, 'position'),
- normals: GL.getAttribLocation(this._shader, 'normal'),
- tangents: GL.getAttribLocation(this._shader, 'tangent'),
- uvs: GL.getAttribLocation(this._shader, 'uv0'),
- colours: GL.getAttribLocation(this._shader, 'colour'),
- };
- this.uniforms = {
- projectionMatrix: {
- type: 'mat4',
- location: GL.getUniformLocation(this._shader, 'projectionMatrix')
- },
- modelViewMatrix: {
- type: 'mat4',
- location: GL.getUniformLocation(this._shader, 'modelViewMatrix'),
- },
- modelMatrix: {
- type: 'mat4',
- location: GL.getUniformLocation(this._shader, 'modelMatrix'),
- },
- normalMatrix: {
- type: 'mat3',
- location: GL.getUniformLocation(this._shader, 'normalMatrix'),
- },
- resolution: {
- type: 'vec4',
- location: GL.getUniformLocation(this._shader, 'resolution'),
- },
- lightColour: {
- type: 'vec3',
- location: GL.getUniformLocation(this._shader, 'lightColour'),
- },
- lightDirection: {
- type: 'vec3',
- location: GL.getUniformLocation(this._shader, 'lightDirection'),
- },
- lightPosition: {
- type: 'vec3',
- location: GL.getUniformLocation(this._shader, 'lightPosition'),
- },
- lightAttenuation: {
- type: 'vec3',
- location: GL.getUniformLocation(this._shader, 'lightAttenuation'),
- },
- cameraPosition: {
- type: 'vec3',
- location: GL.getUniformLocation(this._shader, 'cameraPosition'),
- },
- diffuseTexture: {
- type: 'texture',
- location: GL.getUniformLocation(this._shader, 'diffuseTexture'),
- },
- normalTexture: {
- type: 'texture',
- location: GL.getUniformLocation(this._shader, 'normalTexture'),
- },
- gBuffer_Light: {
- type: 'texture',
- location: GL.getUniformLocation(this._shader, 'gBuffer_Light'),
- },
- gBuffer_Colour: {
- type: 'texture',
- location: GL.getUniformLocation(this._shader, 'gBuffer_Colour'),
- },
- gBuffer_Normal: {
- type: 'texture',
- location: GL.getUniformLocation(this._shader, 'gBuffer_Normal'),
- },
- gBuffer_Position: {
- type: 'texture',
- location: GL.getUniformLocation(this._shader, 'gBuffer_Position'),
- },
- gQuadTexture: {
- type: 'texture',
- location: GL.getUniformLocation(this._shader, 'gQuadTexture'),
- }
- };
- }
- _ModifySourceWithDefines(src, defines) {
- const lines = src.split('\n');
- const defineStrings = defines.map(d => '#define ' + d);
- lines.splice(3, 0, defineStrings);
- return lines.join('\n');
- }
- _Load(type, source) {
- const shader = GL.createShader(type);
- GL.shaderSource(shader, source);
- GL.compileShader(shader);
- if (!GL.getShaderParameter(shader, GL.COMPILE_STATUS)) {
- console.log(GL.getShaderInfoLog(shader));
- console.log(source);
- GL.deleteShader(shader);
- return null;
- }
- return shader;
- }
- Bind() {
- GL.useProgram(this._shader);
- }
- }
- class ShaderInstance {
- constructor(shader) {
- this._shaderData = shader;
- this._uniforms = {};
- for (let k in shader.uniforms) {
- this._uniforms[k] = {
- location: shader.uniforms[k].location,
- type: shader.uniforms[k].type,
- value: null
- };
- }
- this._attribs = {...shader.attribs};
- }
- SetMat4(name, m) {
- this._uniforms[name].value = m;
- }
- SetMat3(name, m) {
- this._uniforms[name].value = m;
- }
- SetVec4(name, v) {
- this._uniforms[name].value = v;
- }
- SetVec3(name, v) {
- this._uniforms[name].value = v;
- }
- SetTexture(name, t) {
- this._uniforms[name].value = t;
- }
- Bind(constants) {
- this._shaderData.Bind();
- let textureIndex = 0;
- for (let k in this._uniforms) {
- const v = this._uniforms[k];
- let value = constants[k];
- if (v.value) {
- value = v.value;
- }
- if (value && v.location) {
- const t = v.type;
- if (t == 'mat4') {
- GL.uniformMatrix4fv(v.location, false, value);
- } else if (t == 'mat3') {
- GL.uniformMatrix3fv(v.location, false, value);
- } else if (t == 'vec4') {
- GL.uniform4fv(v.location, value);
- } else if (t == 'vec3') {
- GL.uniform3fv(v.location, value);
- } else if (t == 'texture') {
- value.Bind(textureIndex);
- GL.uniform1i(v.location, textureIndex);
- textureIndex++;
- }
- }
- }
- }
- }
- class Texture {
- constructor() {
- }
- Load(src) {
- this._name = src;
- this._Load(src);
- return this;
- }
- _Load(src) {
- this._texture = GL.createTexture();
- GL.bindTexture(GL.TEXTURE_2D, this._texture);
- GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA,
- 1, 1, 0, GL.RGBA, GL.UNSIGNED_BYTE,
- new Uint8Array([0, 0, 255, 255]));
- const img = new Image();
- img.src = src;
- img.onload = () => {
- GL.bindTexture(GL.TEXTURE_2D, this._texture);
- GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, img);
- GL.generateMipmap(GL.TEXTURE_2D);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR_MIPMAP_LINEAR);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR);
- GL.bindTexture(GL.TEXTURE_2D, null);
- };
- }
- Bind(index) {
- if (!this._texture) {
- return;
- }
- GL.activeTexture(GL.TEXTURE0 + index);
- GL.bindTexture(GL.TEXTURE_2D, this._texture);
- }
- Unbind() {
- GL.bindTexture(GL.TEXTURE_2D, null);
- }
- }
- class Mesh {
- constructor() {
- this._buffers = {};
- this._OnInit();
- }
- _BufferData(info, name) {
- if (name == 'index') {
- info.buffer = GL.createBuffer();
- GL.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, info.buffer);
- GL.bufferData(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(info.data), GL.STATIC_DRAW);
- } else {
- info.buffer = GL.createBuffer();
- GL.bindBuffer(GL.ARRAY_BUFFER, info.buffer);
- GL.bufferData(GL.ARRAY_BUFFER, new Float32Array(info.data), GL.STATIC_DRAW);
- }
- this._buffers[name] = info;
- }
- Bind(shader) {
- for (let k in this._buffers) {
- if (shader._attribs[k] == -1) {
- continue;
- }
- const b = this._buffers[k];
- if (k == 'index') {
- GL.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, b.buffer);
- } else {
- GL.bindBuffer(GL.ARRAY_BUFFER, b.buffer);
- GL.vertexAttribPointer(shader._attribs[k], b.size, GL.FLOAT, false, 0, 0);
- GL.enableVertexAttribArray(shader._attribs[k]);
- }
- }
- }
- Draw() {
- const vertexCount = this._buffers.index.data.length;
- GL.drawElements(GL.TRIANGLES, vertexCount, GL.UNSIGNED_SHORT, 0);
- }
- }
- class MeshInstance {
- constructor(mesh, shaders, shaderParams) {
- this._mesh = mesh;
- this._shaders = shaders;
- shaderParams = shaderParams || {};
- for (let sk in shaders) {
- const s = shaders[sk];
- for (let k in shaderParams) {
- s.SetTexture(k, shaderParams[k]);
- }
- }
- this._position = vec3.create();
- this._scale = vec3.fromValues(1, 1, 1);
- this._rotation = quat.create();
- }
- SetPosition(x, y, z) {
- vec3.set(this._position, x, y, z);
- }
- RotateX(rad) {
- quat.rotateX(this._rotation, this._rotation, rad);
- }
- RotateY(rad) {
- quat.rotateY(this._rotation, this._rotation, rad);
- }
- Scale(x, y, z) {
- vec3.set(this._scale, x, y, z);
- }
- Bind(constants, pass) {
- const modelMatrix = mat4.create();
- mat4.fromRotationTranslationScale(
- modelMatrix, this._rotation, this._position, this._scale);
- // TODO View matrix
- const viewMatrix = constants['viewMatrix'];
- const modelViewMatrix = mat4.create();
- mat4.multiply(modelViewMatrix, viewMatrix, modelMatrix);
- const normalMatrix = mat3.create();
- mat3.fromMat4(normalMatrix, modelMatrix);
- mat3.invert(normalMatrix, normalMatrix);
- mat3.transpose(normalMatrix, normalMatrix);
- const s = this._shaders[pass];
- s.SetMat4('modelViewMatrix', modelViewMatrix);
- s.SetMat4('modelMatrix', modelMatrix);
- s.SetMat3('normalMatrix', normalMatrix);
- s.Bind(constants);
- this._mesh.Bind(s);
- }
- Draw() {
- this._mesh.Draw();
- }
- }
- class Box extends Mesh {
- constructor() {
- super();
- }
- _OnInit() {
- const positions = [
- // Front face
- -1.0, -1.0, 1.0,
- 1.0, -1.0, 1.0,
- 1.0, 1.0, 1.0,
- -1.0, 1.0, 1.0,
- // Back face
- -1.0, -1.0, -1.0,
- -1.0, 1.0, -1.0,
- 1.0, 1.0, -1.0,
- 1.0, -1.0, -1.0,
- // Top face
- -1.0, 1.0, -1.0,
- -1.0, 1.0, 1.0,
- 1.0, 1.0, 1.0,
- 1.0, 1.0, -1.0,
- // Bottom face
- -1.0, -1.0, -1.0,
- 1.0, -1.0, -1.0,
- 1.0, -1.0, 1.0,
- -1.0, -1.0, 1.0,
- // Right face
- 1.0, -1.0, -1.0,
- 1.0, 1.0, -1.0,
- 1.0, 1.0, 1.0,
- 1.0, -1.0, 1.0,
- // Left face
- -1.0, -1.0, -1.0,
- -1.0, -1.0, 1.0,
- -1.0, 1.0, 1.0,
- -1.0, 1.0, -1.0,
- ];
- const uvs = [
- // Front face
- 0.0, 0.0,
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- // Back face
- 0.0, 0.0,
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- // Top face
- 0.0, 0.0,
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- // Bottom face
- 0.0, 0.0,
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- // Right face
- 0.0, 0.0,
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- // Left face
- 0.0, 0.0,
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- ];
- const normals = [
- // Front face
- 0.0, 0.0, 1.0,
- 0.0, 0.0, 1.0,
- 0.0, 0.0, 1.0,
- 0.0, 0.0, 1.0,
- // Back face
- 0.0, 0.0, -1.0,
- 0.0, 0.0, -1.0,
- 0.0, 0.0, -1.0,
- 0.0, 0.0, -1.0,
- // Top face
- 0.0, 1.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 1.0, 0.0,
- // Bottom face
- 0.0, -1.0, 0.0,
- 0.0, -1.0, 0.0,
- 0.0, -1.0, 0.0,
- 0.0, -1.0, 0.0,
- // Right face
- 1.0, 0.0, 0.0,
- 1.0, 0.0, 0.0,
- 1.0, 0.0, 0.0,
- 1.0, 0.0, 0.0,
- // Left face
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- ];
- const tangents = [
- // Front face
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- // Back face
- 0.0, 1.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 1.0, 0.0,
- // Top face
- 0.0, 0.0, 1.0,
- 0.0, 0.0, 1.0,
- 0.0, 0.0, 1.0,
- 0.0, 0.0, 1.0,
- // Bottom face
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- // Right face
- 0.0, 1.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 1.0, 0.0,
- // Left face
- 0.0, 0.0, -1.0,
- 0.0, 0.0, -1.0,
- 0.0, 0.0, -1.0,
- 0.0, 0.0, -1.0,
- ];
- const faceColors = [
- [1.0, 1.0, 1.0, 1.0], // Front face: white
- [1.0, 0.0, 0.0, 1.0], // Back face: red
- [0.0, 1.0, 0.0, 1.0], // Top face: green
- [0.0, 0.0, 1.0, 1.0], // Bottom face: blue
- [1.0, 1.0, 0.0, 1.0], // Right face: yellow
- [1.0, 0.0, 1.0, 1.0], // Left face: purple
- ];
- // Convert the array of colors into a table for all the vertices.
- let colours = [];
- for (var j = 0; j < faceColors.length; ++j) {
- const c = faceColors[j];
- // Repeat each color four times for the four vertices of the face
- colours = colours.concat(c, c, c, c);
- }
- const indices = [
- 0, 1, 2, 0, 2, 3, // front
- 4, 5, 6, 4, 6, 7, // back
- 8, 9, 10, 8, 10, 11, // top
- 12, 13, 14, 12, 14, 15, // bottom
- 16, 17, 18, 16, 18, 19, // right
- 20, 21, 22, 20, 22, 23, // left
- ];
- this._BufferData({size: 3, data: positions}, 'positions');
- this._BufferData({size: 3, data: normals}, 'normals');
- this._BufferData({size: 3, data: tangents}, 'tangents');
- this._BufferData({size: 4, data: colours}, 'colours');
- this._BufferData({size: 2, data: uvs}, 'uvs');
- this._BufferData({data: indices}, 'index');
- }
- }
- class Quad extends Mesh {
- constructor() {
- super();
- }
- _OnInit() {
- const positions = [
- -0.5, -0.5, 1.0,
- 0.5, -0.5, 1.0,
- 0.5, 0.5, 1.0,
- -0.5, 0.5, 1.0,
- ];
- const normals = [
- 0.0, 0.0, 1.0,
- 0.0, 0.0, 1.0,
- 0.0, 0.0, 1.0,
- 0.0, 0.0, 1.0,
- ];
- const tangents = [
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- -1.0, 0.0, 0.0,
- ];
- const uvs = [
- 0.0, 0.0,
- 1.0, 0.0,
- 1.0, 1.0,
- 0.0, 1.0,
- ];
- const indices = [
- 0, 1, 2,
- 0, 2, 3,
- ];
- this._BufferData({size: 3, data: positions}, 'positions');
- this._BufferData({size: 3, data: normals}, 'normals');
- this._BufferData({size: 3, data: tangents}, 'tangents');
- this._BufferData({size: 2, data: uvs}, 'uvs');
- this._BufferData({data: indices}, 'index');
- }
- }
- class Camera {
- constructor() {
- this._position = vec3.create();
- this._target = vec3.create();
- this._viewMatrix = mat4.create();
- this._cameraMatrix = mat4.create();
- }
- SetPosition(x, y, z) {
- vec3.set(this._position, x, y, z);
- }
- SetTarget(x, y, z) {
- vec3.set(this._target, x, y, z);
- }
- UpdateConstants(constants) {
- mat4.lookAt(this._viewMatrix, this._position, this._target, vec3.fromValues(0, 1, 0));
- mat4.invert(this._cameraMatrix, this._viewMatrix);
- constants['projectionMatrix'] = this._projectionMatrix;
- constants['viewMatrix'] = this._viewMatrix;
- constants['cameraMatrix'] = this._cameraMatrix;
- constants['cameraPosition'] = this._position;
- }
- }
- class PerspectiveCamera extends Camera {
- constructor(fov, aspect, zNear, zFar) {
- super();
- this._projectionMatrix = mat4.create();
- this._fov = fov;
- this._aspect = aspect;
- this._zNear = zNear;
- this._zFar = zFar;
- mat4.perspective(this._projectionMatrix, fov * Math.PI / 180.0, aspect, zNear, zFar);
- }
- GetUp() {
- const v = vec4.fromValues(0, 0, 1, 0);
- vec4.transformMat4(v, v, this._cameraMatrix);
- return v;
- }
- GetRight() {
- const v = vec4.fromValues(1, 0, 0, 0);
- vec4.transformMat4(v, v, this._cameraMatrix);
- return v;
- }
- }
- class OrthoCamera extends Camera {
- constructor(l, r, b, t, n, f) {
- super();
- this._projectionMatrix = mat4.create();
- mat4.ortho(this._projectionMatrix, l, r, b, t, n, f);
- }
- }
- class Light {
- constructor() {
- }
- UpdateConstants() {
- }
- }
- class DirectionalLight extends Light {
- constructor() {
- super();
- this._colour = vec3.fromValues(1, 1, 1);
- this._direction = vec3.fromValues(1, 0, 0);
- }
- get Type() {
- return 'Directional';
- }
- SetColour(r, g, b) {
- vec3.set(this._colour, r, g, b);
- }
- SetDirection(x, y, z) {
- vec3.set(this._direction, x, y, z);
- vec3.normalize(this._direction, this._direction);
- }
- UpdateConstants(constants) {
- constants['lightDirection'] = this._direction;
- constants['lightColour'] = this._colour;
- }
- }
- class PointLight extends Light {
- constructor() {
- super();
- this._colour = vec3.fromValues(1, 1, 1);
- this._position = vec3.create();
- this._attenuation = vec3.create();
- }
- get Type() {
- return 'Point';
- }
- SetColour(r, g, b) {
- vec3.set(this._colour, r, g, b);
- }
- SetPosition(x, y, z) {
- vec3.set(this._position, x, y, z);
- }
- SetRadius(r1, r2) {
- vec3.set(this._attenuation, r1, r2, 0);
- }
- UpdateConstants(constants) {
- constants['lightPosition'] = this._position;
- constants['lightColour'] = this._colour;
- constants['lightAttenuation'] = this._attenuation;
- }
- }
- class Renderer {
- constructor() {
- this._Init();
- }
- _Init() {
- this._canvas = document.createElement('canvas');
- document.body.appendChild(this._canvas);
- GL = this._canvas.getContext('webgl2');
- if (GL === null) {
- alert("Unable to initialize WebGL. Your browser or machine may not support it.");
- return;
- }
- this._constants = {};
- this._textures = {};
- this._textures['test-diffuse'] = new Texture().Load('./resources/rough-wet-cobble-albedo-1024.png');
- this._textures['test-normal'] = new Texture().Load('./resources/rough-wet-cobble-normal-1024.jpg');
- this._textures['worn-bumpy-rock-albedo'] = new Texture().Load(
- './resources/worn-bumpy-rock-albedo-1024.png');
- this._textures['worn-bumpy-rock-normal'] = new Texture().Load(
- './resources/worn-bumpy-rock-normal-1024.jpg');
- this._shaders = {};
- this._shaders['z'] = new Shader(_SIMPLE_VS, _SIMPLE_FS);
- this._shaders['default'] = new Shader(_OPAQUE_VS, _OPAQUE_FS);
- this._shaders['post-quad-colour'] = new Shader(
- _QUAD_COLOUR_VS, _QUAD_COLOUR_FS);
- this._shaders['post-quad-directional'] = new Shader(
- _QUAD_VS, _QUAD_FS, ['_LIGHT_TYPE_DIRECTIONAL']);
- this._shaders['post-quad-point'] = new Shader(
- _QUAD_VS, _QUAD_FS, ['_LIGHT_TYPE_POINT']);
- this._camera = new PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1.0, 1000.0);
- this._camera.SetPosition(0, 20, 10);
- this._camera.SetTarget(0, 0, -20);
- this._postCamera = new OrthoCamera(0.0, 1.0, 0.0, 1.0, 1.0, 1000.0);
- this._meshes = [];
- this._lights = [];
- this._quadDirectional = new MeshInstance(
- new Quad(),
- {light: new ShaderInstance(this._shaders['post-quad-directional'])});
- this._quadDirectional.SetPosition(0.5, 0.5, -10.0);
- this._quadPoint = new MeshInstance(
- new Quad(),
- {light: new ShaderInstance(this._shaders['post-quad-point'])});
- this._quadPoint.SetPosition(0.5, 0.5, -10.0);
- this._quadColour = new MeshInstance(
- new Quad(),
- {colour: new ShaderInstance(this._shaders['post-quad-colour'])});
- this._quadColour.SetPosition(0.5, 0.5, -10.0);
- this._InitGBuffer();
- this.Resize(window.innerWidth, window.innerHeight);
- }
- _InitGBuffer() {
- // Float textures have only been around for like 15 years.
- // So of course make them an extension.
- GL.getExtension('EXT_color_buffer_float');
- this._depthBuffer = GL.createRenderbuffer();
- GL.bindRenderbuffer(GL.RENDERBUFFER, this._depthBuffer);
- GL.renderbufferStorage(
- GL.RENDERBUFFER,
- GL.DEPTH_COMPONENT24,
- window.innerWidth, window.innerHeight);
- GL.bindRenderbuffer(GL.RENDERBUFFER, null);
- this._normalBuffer = GL.createTexture();
- GL.bindTexture(GL.TEXTURE_2D, this._normalBuffer);
- GL.texImage2D(
- GL.TEXTURE_2D, 0, GL.RGBA32F, window.innerWidth, window.innerHeight,
- 0, GL.RGBA, GL.FLOAT, null);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
- GL.bindTexture(GL.TEXTURE_2D, null);
- this._positionBuffer = GL.createTexture();
- GL.bindTexture(GL.TEXTURE_2D, this._positionBuffer);
- GL.texImage2D(
- GL.TEXTURE_2D, 0, GL.RGBA32F, window.innerWidth, window.innerHeight,
- 0, GL.RGBA, GL.FLOAT, null);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
- GL.bindTexture(GL.TEXTURE_2D, null);
- this._lightBuffer = GL.createTexture();
- GL.bindTexture(GL.TEXTURE_2D, this._lightBuffer);
- GL.texImage2D(
- GL.TEXTURE_2D, 0, GL.RGBA32F, window.innerWidth, window.innerHeight,
- 0, GL.RGBA, GL.FLOAT, null);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
- GL.bindTexture(GL.TEXTURE_2D, null);
- this._colourBuffer = GL.createTexture();
- GL.bindTexture(GL.TEXTURE_2D, this._colourBuffer);
- GL.texImage2D(
- GL.TEXTURE_2D, 0, GL.RGBA32F, window.innerWidth, window.innerHeight,
- 0, GL.RGBA, GL.FLOAT, null);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
- GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
- GL.bindTexture(GL.TEXTURE_2D, null);
- // Create the FBO's for each pass
- this._zFBO = GL.createFramebuffer();
- GL.bindFramebuffer(GL.FRAMEBUFFER, this._zFBO);
- GL.framebufferRenderbuffer(
- GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, this._depthBuffer);
- GL.framebufferTexture2D(
- GL.DRAW_FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, this._normalBuffer, 0);
- GL.framebufferTexture2D(
- GL.DRAW_FRAMEBUFFER, GL.COLOR_ATTACHMENT1, GL.TEXTURE_2D, this._positionBuffer, 0);
- GL.bindFramebuffer(GL.FRAMEBUFFER, null);
- this._lightFBO = GL.createFramebuffer();
- GL.bindFramebuffer(GL.FRAMEBUFFER, this._lightFBO);
- GL.framebufferRenderbuffer(
- GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, this._depthBuffer);
- GL.framebufferTexture2D(
- GL.DRAW_FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, this._lightBuffer, 0);
- GL.bindFramebuffer(GL.FRAMEBUFFER, null);
- this._colourFBO = GL.createFramebuffer();
- GL.bindFramebuffer(GL.FRAMEBUFFER, this._colourFBO);
- GL.framebufferRenderbuffer(
- GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, this._depthBuffer);
- GL.framebufferTexture2D(
- GL.DRAW_FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, this._colourBuffer, 0);
- GL.bindFramebuffer(GL.FRAMEBUFFER, null);
- // GROSS
- this._normalTexture = new Texture();
- this._normalTexture._texture = this._normalBuffer;
- this._positionTexture = new Texture();
- this._positionTexture._texture = this._positionBuffer;
- this._lightTexture = new Texture();
- this._lightTexture._texture = this._lightBuffer;
- this._colourTexture = new Texture();
- this._colourTexture._texture = this._colourBuffer;
- }
- CreateMeshInstance(mesh, shaderParams) {
- const params = {};
- for (let k in shaderParams.params) {
- params[k] = this._textures[shaderParams.params[k]];
- }
- const m = new MeshInstance(
- mesh,
- {
- z: new ShaderInstance(this._shaders['z']),
- colour: new ShaderInstance(this._shaders[shaderParams.shader])
- }, params);
- this._meshes.push(m);
- return m;
- }
- CreateLight(type) {
- let l = null;
- if (type == 'directional') {
- l = new DirectionalLight();
- } else if (type == 'point') {
- l = new PointLight();
- }
- if (!l) {
- return null;
- }
- this._lights.push(l);
- return l;
- }
- Resize(w, h) {
- this._canvas.width = w;
- this._canvas.height = h;
- GL.viewport(0, 0, w, h);
- }
- _SetQuadSizeForLight(quad, light) {
- const wvp = mat4.create();
- const w = mat4.create();
- mat4.fromTranslation(w, light._position);
- const viewMatrix = this._camera._viewMatrix;
- const projectionMatrix = this._camera._projectionMatrix;
- const _TransformToScreenSpace = (p) => {
- const screenPos = vec4.fromValues(
- p[0], p[1], p[2], 1.0);
- vec4.transformMat4(screenPos, screenPos, projectionMatrix);
- screenPos[0] = (screenPos[0] / screenPos[3]) * 0.5 + 0.5;
- screenPos[1] = (screenPos[1] / screenPos[3]) * 0.5 + 0.5;
- return screenPos;
- };
- const lightRadius = (light._attenuation[0] + light._attenuation[1]);
- const lightDistance = vec3.distance(this._camera._position, light._position);
- if (lightDistance < lightRadius) {
- quad.SetPosition(0.5, 0.5, -10);
- quad.Scale(1, 1, 1);
- } else {
- const viewSpaceCenter = vec3.clone(light._position);
- vec3.transformMat4(viewSpaceCenter, viewSpaceCenter, viewMatrix);
- const rightPos = vec3.clone(viewSpaceCenter);
- const upPos = vec3.clone(viewSpaceCenter);
- vec3.add(rightPos, rightPos, vec3.fromValues(lightRadius, 0, 0));
- vec3.add(upPos, upPos, vec3.fromValues(0, -lightRadius, 0));
- const center = _TransformToScreenSpace(light._position);
- const up = _TransformToScreenSpace(upPos);
- const right = _TransformToScreenSpace(rightPos);
- const radius = 2 * Math.max(
- vec2.distance(center, up), vec2.distance(center, right));
- quad.SetPosition(center[0], center[1], -10);
- quad.Scale(radius, radius, 1);
- }
- }
- Render(timeElapsed) {
- this._constants['resolution'] = vec4.fromValues(
- window.innerWidth, window.innerHeight, 0, 0);
- this._camera.UpdateConstants(this._constants);
- this._constants['gBuffer_Normal'] = null;
- this._constants['gBuffer_Position'] = null;
- this._constants['gBuffer_Colour'] = null;
- this._constants['gBuffer_Light'] = null;
- // Z-Prepass + normals
- GL.bindFramebuffer(GL.FRAMEBUFFER, this._zFBO);
- GL.drawBuffers([GL.COLOR_ATTACHMENT0, GL.COLOR_ATTACHMENT1]);
- GL.clearColor(0.0, 0.0, 0.0, 0.0);
- GL.clearDepth(1.0);
- GL.enable(GL.DEPTH_TEST);
- GL.depthMask(true);
- GL.depthFunc(GL.LEQUAL);
- GL.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT);
- this._camera.UpdateConstants(this._constants);
- for (let m of this._meshes) {
- m.Bind(this._constants, 'z');
- m.Draw();
- }
- GL.useProgram(null);
- GL.bindTexture(GL.TEXTURE_2D, null);
- // Light buffer generation
- GL.bindFramebuffer(GL.FRAMEBUFFER, this._lightFBO);
- GL.drawBuffers([GL.COLOR_ATTACHMENT0]);
- GL.clear(GL.COLOR_BUFFER_BIT);
- GL.disable(GL.DEPTH_TEST);
- GL.enable(GL.BLEND);
- GL.blendFunc(GL.ONE, GL.ONE);
- this._postCamera.UpdateConstants(this._constants);
- this._constants['gBuffer_Normal'] = this._normalTexture;
- this._constants['gBuffer_Position'] = this._positionTexture;
- for (let l of this._lights) {
- l.UpdateConstants(this._constants);
- let quad = null;
- if (l.Type == 'Directional') {
- quad = this._quadDirectional;
- } else if (l.Type == 'Point') {
- quad = this._quadPoint;
- // Calculate screenspace size
- this._SetQuadSizeForLight(quad, l);
- }
- quad.Bind(this._constants, 'light');
- quad.Draw();
- }
- GL.useProgram(null);
- GL.bindTexture(GL.TEXTURE_2D, null);
- // Colour pass
- GL.bindFramebuffer(GL.FRAMEBUFFER, this._colourFBO);
- GL.drawBuffers([GL.COLOR_ATTACHMENT0]);
- GL.disable(GL.BLEND);
- GL.depthMask(false);
- GL.enable(GL.DEPTH_TEST);
- this._camera.UpdateConstants(this._constants);
- this._constants['gBuffer_Colour'] = null;
- this._constants['gBuffer_Light'] = this._lightTexture;
- this._constants['gBuffer_Normal'] = null;
- this._constants['gBuffer_Position'] = null;
- for (let m of this._meshes) {
- m.Bind(this._constants, 'colour');
- m.Draw();
- }
- GL.useProgram(null);
- GL.bindTexture(GL.TEXTURE_2D, null);
- GL.disable(GL.BLEND);
- // Now just draw directly to screen
- GL.bindFramebuffer(GL.FRAMEBUFFER, null);
- GL.disable(GL.DEPTH_TEST);
- GL.disable(GL.BLEND);
- this._postCamera.UpdateConstants(this._constants);
- // Really fucking hate JavaScript sometimes.
- this._constants['gQuadTexture'] = this._colourTexture;
- this._quadColour.Bind(this._constants, 'colour');
- this._quadColour.Draw();
- }
- }
- class LightPrepassDemo {
- constructor() {
- this._Initialize();
- }
- _Initialize() {
- this._renderer = new Renderer();
- window.addEventListener('resize', () => {
- this._OnWindowResize();
- }, false);
- this._Init();
- this._previousRAF = null;
- this._RAF();
- }
- _OnWindowResize() {
- this._renderer.Resize(window.innerWidth, window.innerHeight);
- }
- _Init() {
- this._CreateLights();
- this._CreateMeshes();
- }
- _CreateLights() {
- this._lights = [];
- for (let i = -9; i <= 9; i++) {
- let l = this._renderer.CreateLight('point');
- const v = vec3.fromValues(Math.random(), Math.random(), Math.random());
- vec3.normalize(v, v);
- const p = vec3.fromValues(
- (Math.random() * 2 - 1) * 10,
- 3,
- -Math.random() * 10 - 10);
- l.SetColour(v[0], v[1], v[2]);
- l.SetPosition(p[0], p[1], p[2]);
- l.SetRadius(4, 1);
- this._lights.push({
- light: l,
- position: p,
- acc: Math.random() * 10.0,
- accSpeed: Math.random() * 0.5 + 0.5,
- });
- }
- }
- _CreateMeshes() {
- this._meshes = [];
- let m = this._renderer.CreateMeshInstance(
- new Quad(),
- {
- shader: 'default',
- params: {
- diffuseTexture: 'worn-bumpy-rock-albedo',
- normalTexture: 'worn-bumpy-rock-normal',
- }
- });
- m.SetPosition(0, -2, -10);
- m.RotateX(-Math.PI * 0.5);
- m.Scale(50, 50, 1);
- for (let x = -5; x < 5; x++) {
- for (let y = 0; y < 20; y++) {
- let m = this._renderer.CreateMeshInstance(
- new Box(),
- {
- shader: 'default',
- params: {
- diffuseTexture: 'test-diffuse',
- normalTexture: 'test-normal',
- }
- });
- m.SetPosition(x * 4, 0, -y * 4);
- this._meshes.push(m);
- }
- }
- }
- _RAF() {
- requestAnimationFrame((t) => {
- if (this._previousRAF === null) {
- this._previousRAF = t;
- }
- this._RAF();
- this._Step(t - this._previousRAF);
- this._previousRAF = t;
- });
- }
- _Step(timeElapsed) {
- const timeElapsedS = timeElapsed * 0.001;
- for (let m of this._meshes) {
- m.RotateY(timeElapsedS);
- }
- for (let l of this._lights) {
- l.acc += timeElapsed * 0.001 * l.accSpeed;
- l.light.SetPosition(
- l.position[0] + 10 * Math.cos(l.acc),
- l.position[1],
- l.position[2] + 10 * Math.sin(l.acc));
- }
- this._renderer.Render(timeElapsedS);
- }
- }
- let _APP = null;
- window.addEventListener('DOMContentLoaded', () => {
- _APP = new LightPrepassDemo();
- });
Add Comment
Please, Sign In to add comment