here2share

# WebGL_1Day_3DEngine.js

May 11th, 2022
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const { mat4, mat3, vec2, vec3, vec4, quat } = glMatrix;
  2.  
  3. let GL = null;
  4.  
  5. const _OPAQUE_VS = `#version 300 es
  6. precision highp float;
  7.  
  8.  
  9. uniform mat3 normalMatrix;
  10. uniform mat4 modelMatrix;
  11. uniform mat4 modelViewMatrix;
  12. uniform mat4 projectionMatrix;
  13.  
  14. in vec3 position;
  15. in vec3 normal;
  16. in vec3 tangent;
  17. in vec4 colour;
  18. in vec2 uv0;
  19.  
  20. out vec2 vUV0;
  21. out vec4 vColour;
  22.  
  23. void main(void) {
  24.   gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  25.   vColour = colour;
  26.   vUV0 = uv0;
  27. }
  28. `;
  29.  
  30.  
  31. const _OPAQUE_FS = `#version 300 es
  32. precision highp float;
  33.  
  34.  
  35. uniform sampler2D diffuseTexture;
  36. uniform sampler2D normalTexture;
  37. uniform sampler2D gBuffer_Light;
  38. uniform vec4 resolution;
  39.  
  40. in vec4 vColour;
  41. in vec2 vUV0;
  42.  
  43.  
  44. layout(location = 0) out vec4 out_FragColour;
  45.  
  46.  
  47. void main(void) {
  48.   vec2 uv = gl_FragCoord.xy / resolution.xy;
  49.   vec4 lightSample = texture(gBuffer_Light, uv);
  50.   vec4 albedo = texture(diffuseTexture, vUV0);
  51.  
  52.   out_FragColour = (albedo * vec4(lightSample.xyz, 1.0) +
  53.       lightSample.w * vec4(0.3, 0.6, 0.1, 0.0));
  54. }
  55. `;
  56.  
  57.  
  58. const _QUAD_VS = `#version 300 es
  59. precision highp float;
  60.  
  61.  
  62. uniform mat4 modelViewMatrix;
  63. uniform mat4 projectionMatrix;
  64.  
  65. in vec3 position;
  66. in vec2 uv0;
  67.  
  68.  
  69. void main(void) {
  70.   gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  71. }
  72. `;
  73.  
  74.  
  75. const _QUAD_FS = `#version 300 es
  76. precision highp float;
  77.  
  78.  
  79. uniform sampler2D gBuffer_Normal;
  80. uniform sampler2D gBuffer_Position;
  81.  
  82. uniform vec3 lightColour;
  83.  
  84. #define _LIGHT_TYPE_POINT
  85.  
  86. #ifdef _LIGHT_TYPE_DIRECTIONAL
  87. uniform vec3 lightDirection;
  88. #endif
  89.  
  90. uniform vec3 lightPosition;
  91. uniform vec3 lightAttenuation;
  92.  
  93. uniform vec3 cameraPosition;
  94. uniform vec4 resolution;
  95.  
  96.  
  97. out vec4 out_FragColour;
  98.  
  99. #define saturate(a) clamp(a, 0.0, 1.0)
  100.  
  101. float _SmootherStep(float x, float a, float b) {
  102.   x = x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
  103.   return x * (b - a) + a;
  104. }
  105.  
  106.  
  107. vec2 _CalculatePhong(vec3 lightDirection, vec3 cameraPosition, vec3 position, vec3 normal) {
  108.   vec3 viewDirection = normalize(cameraPosition - position);
  109.   vec3 H = normalize(lightDirection.xyz + viewDirection);
  110.   float NdotH = dot(normal.xyz, H);
  111.   float specular = saturate(pow(NdotH, 32.0));
  112.   float diffuse = saturate(dot(lightDirection.xyz, normal.xyz));
  113.  
  114.   return vec2(diffuse, diffuse * specular);
  115. }
  116.  
  117. vec4 _CalculateLight_Directional(
  118.     vec3 lightDirection, vec3 lightColour, vec3 position, vec3 normal) {
  119.  
  120.   vec2 lightSample = _CalculatePhong(-lightDirection, cameraPosition, position, normal);
  121.  
  122.   return vec4(lightSample.x * lightColour, lightSample.y);
  123. }
  124.  
  125. vec4 _CalculateLight_Point(
  126.     vec3 lightPosition, vec3 lightAttenuation, vec3 lightColour, vec3 position, vec3 normal) {
  127.  
  128.   vec3 dirToLight = lightPosition - position;
  129.   float lightDistance = length(dirToLight);
  130.   dirToLight = normalize(dirToLight);
  131.  
  132.   vec2 lightSample = _CalculatePhong(dirToLight, cameraPosition, position, normal);
  133.   float falloff = saturate((lightDistance - lightAttenuation.x) / lightAttenuation.y);
  134.  
  135.   lightSample *= _SmootherStep(falloff, 1.0, 0.0);
  136.  
  137.   return vec4(lightSample.x * lightColour, lightSample.y);
  138. }
  139.  
  140.  
  141. void main(void) {
  142.   vec2 uv = gl_FragCoord.xy / resolution.xy;
  143.  
  144.   vec4 normal = texture(gBuffer_Normal, uv);
  145.   vec4 position = texture(gBuffer_Position, uv);
  146.  
  147. #ifdef _LIGHT_TYPE_DIRECTIONAL
  148.   vec4 lightSample = _CalculateLight_Directional(
  149.       lightDirection, lightColour, position.xyz, normal.xyz);
  150. #elif defined(_LIGHT_TYPE_POINT)
  151.   vec4 lightSample = _CalculateLight_Point(
  152.       lightPosition, lightAttenuation, lightColour, position.xyz, normal.xyz);
  153. #endif
  154.  
  155.   out_FragColour = lightSample;
  156. }
  157. `;
  158.  
  159. const _QUAD_COLOUR_VS = `#version 300 es
  160. precision highp float;
  161.  
  162.  
  163. uniform mat4 modelViewMatrix;
  164. uniform mat4 projectionMatrix;
  165.  
  166. in vec3 position;
  167. in vec2 uv0;
  168.  
  169.  
  170. void main(void) {
  171.   gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  172. }
  173. `;
  174.  
  175.  
  176. const _QUAD_COLOUR_FS = `#version 300 es
  177. precision highp float;
  178.  
  179.  
  180. uniform sampler2D gQuadTexture;
  181. uniform vec4 resolution;
  182.  
  183. out vec4 out_FragColour;
  184.  
  185.  
  186. void main(void) {
  187.   vec2 uv = gl_FragCoord.xy / resolution.xy;
  188.  
  189.   out_FragColour = texture(gQuadTexture, uv);
  190. }
  191. `;
  192.  
  193. const _SIMPLE_VS = `#version 300 es
  194. precision highp float;
  195.  
  196.  
  197. uniform mat3 normalMatrix;
  198. uniform mat4 modelMatrix;
  199. uniform mat4 modelViewMatrix;
  200. uniform mat4 projectionMatrix;
  201.  
  202. in vec3 position;
  203. in vec3 normal;
  204. in vec3 tangent;
  205. in vec2 uv0;
  206.  
  207. out vec4 vWSPosition;
  208. out vec3 vNormal;
  209. out vec3 vTangent;
  210. out vec2 vUV0;
  211.  
  212. void main(void) {
  213.   gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  214.   vNormal = normalize(normalMatrix * normal);
  215.   vTangent = normalize(normalMatrix * tangent);
  216.   vWSPosition = modelMatrix * vec4(position, 1.0);
  217.   vUV0 = uv0;
  218. }
  219. `;
  220.  
  221.  
  222. const _SIMPLE_FS = `#version 300 es
  223. precision highp float;
  224.  
  225.  
  226. uniform sampler2D normalTexture;
  227.  
  228. in vec4 vWSPosition;
  229. in vec3 vNormal;
  230. in vec3 vTangent;
  231. in vec2 vUV0;
  232.  
  233. layout(location = 0) out vec4 out_Normals;
  234. layout(location = 1) out vec4 out_Position;
  235.  
  236.  
  237. void main(void) {
  238.   vec3 bitangent = normalize(cross(vTangent, vNormal));
  239.   mat3 tbn = mat3(vTangent, bitangent, vNormal);
  240.   vec3 normalSample = normalize(texture(normalTexture, vUV0).xyz * 2.0 - 1.0);
  241.   vec3 vsNormal = normalize(tbn * normalSample);
  242.  
  243.   out_Normals = vec4(vsNormal, 1.0);
  244.   out_Position = vWSPosition;
  245. }
  246. `;
  247.  
  248. class Shader {
  249.   constructor(vsrc, fsrc, defines) {
  250.     defines = defines || [];
  251.  
  252.     this._Init(vsrc, fsrc, defines);
  253.   }
  254.  
  255.   _Init(vsrc, fsrc, defines) {
  256.     this._defines = defines;
  257.  
  258.     vsrc = this._ModifySourceWithDefines(vsrc, defines);
  259.     fsrc = this._ModifySourceWithDefines(fsrc, defines);
  260.  
  261.     this._vsSource = vsrc;
  262.     this._fsSource = fsrc;
  263.  
  264.     this._vsProgram = this._Load(GL.VERTEX_SHADER, vsrc);
  265.     this._fsProgram = this._Load(GL.FRAGMENT_SHADER, fsrc);
  266.  
  267.     this._shader = GL.createProgram();
  268.     GL.attachShader(this._shader, this._vsProgram);
  269.     GL.attachShader(this._shader, this._fsProgram);
  270.     GL.linkProgram(this._shader);
  271.  
  272.     if (!GL.getProgramParameter(this._shader, GL.LINK_STATUS)) {
  273.       return null;
  274.     }
  275.  
  276.     this.attribs = {
  277.       positions: GL.getAttribLocation(this._shader, 'position'),
  278.       normals: GL.getAttribLocation(this._shader, 'normal'),
  279.       tangents: GL.getAttribLocation(this._shader, 'tangent'),
  280.       uvs: GL.getAttribLocation(this._shader, 'uv0'),
  281.       colours: GL.getAttribLocation(this._shader, 'colour'),
  282.     };
  283.     this.uniforms = {
  284.       projectionMatrix: {
  285.         type: 'mat4',
  286.         location: GL.getUniformLocation(this._shader, 'projectionMatrix')
  287.       },
  288.       modelViewMatrix: {
  289.         type: 'mat4',
  290.         location: GL.getUniformLocation(this._shader, 'modelViewMatrix'),
  291.       },
  292.       modelMatrix: {
  293.         type: 'mat4',
  294.         location: GL.getUniformLocation(this._shader, 'modelMatrix'),
  295.       },
  296.       normalMatrix: {
  297.         type: 'mat3',
  298.         location: GL.getUniformLocation(this._shader, 'normalMatrix'),
  299.       },
  300.       resolution: {
  301.         type: 'vec4',
  302.         location: GL.getUniformLocation(this._shader, 'resolution'),
  303.       },
  304.       lightColour: {
  305.         type: 'vec3',
  306.         location: GL.getUniformLocation(this._shader, 'lightColour'),
  307.       },
  308.       lightDirection: {
  309.         type: 'vec3',
  310.         location: GL.getUniformLocation(this._shader, 'lightDirection'),
  311.       },
  312.       lightPosition: {
  313.         type: 'vec3',
  314.         location: GL.getUniformLocation(this._shader, 'lightPosition'),
  315.       },
  316.       lightAttenuation: {
  317.         type: 'vec3',
  318.         location: GL.getUniformLocation(this._shader, 'lightAttenuation'),
  319.       },
  320.       cameraPosition: {
  321.         type: 'vec3',
  322.         location: GL.getUniformLocation(this._shader, 'cameraPosition'),
  323.       },
  324.       diffuseTexture: {
  325.         type: 'texture',
  326.         location: GL.getUniformLocation(this._shader, 'diffuseTexture'),
  327.       },
  328.       normalTexture: {
  329.         type: 'texture',
  330.         location: GL.getUniformLocation(this._shader, 'normalTexture'),
  331.       },
  332.       gBuffer_Light: {
  333.         type: 'texture',
  334.         location: GL.getUniformLocation(this._shader, 'gBuffer_Light'),
  335.       },
  336.       gBuffer_Colour: {
  337.         type: 'texture',
  338.         location: GL.getUniformLocation(this._shader, 'gBuffer_Colour'),
  339.       },
  340.       gBuffer_Normal: {
  341.         type: 'texture',
  342.         location: GL.getUniformLocation(this._shader, 'gBuffer_Normal'),
  343.       },
  344.       gBuffer_Position: {
  345.         type: 'texture',
  346.         location: GL.getUniformLocation(this._shader, 'gBuffer_Position'),
  347.       },
  348.       gQuadTexture: {
  349.         type: 'texture',
  350.         location: GL.getUniformLocation(this._shader, 'gQuadTexture'),
  351.       }
  352.     };
  353.   }
  354.  
  355.   _ModifySourceWithDefines(src, defines) {
  356.     const lines = src.split('\n');
  357.  
  358.     const defineStrings = defines.map(d => '#define ' + d);
  359.  
  360.     lines.splice(3, 0, defineStrings);
  361.  
  362.     return lines.join('\n');
  363.   }
  364.  
  365.   _Load(type, source) {
  366.     const shader = GL.createShader(type);
  367.  
  368.     GL.shaderSource(shader, source);
  369.     GL.compileShader(shader);
  370.  
  371.     if (!GL.getShaderParameter(shader, GL.COMPILE_STATUS)) {
  372.       console.log(GL.getShaderInfoLog(shader));
  373.       console.log(source);
  374.       GL.deleteShader(shader);
  375.       return null;
  376.     }
  377.  
  378.     return shader;
  379.   }
  380.  
  381.   Bind() {
  382.     GL.useProgram(this._shader);
  383.   }
  384. }
  385.  
  386.  
  387. class ShaderInstance {
  388.   constructor(shader) {
  389.     this._shaderData = shader;
  390.     this._uniforms = {};
  391.     for (let k in shader.uniforms) {
  392.       this._uniforms[k] = {
  393.         location: shader.uniforms[k].location,
  394.         type: shader.uniforms[k].type,
  395.         value: null
  396.       };
  397.     }
  398.     this._attribs = {...shader.attribs};
  399.   }
  400.  
  401.   SetMat4(name, m) {
  402.     this._uniforms[name].value = m;
  403.   }
  404.  
  405.   SetMat3(name, m) {
  406.     this._uniforms[name].value = m;
  407.   }
  408.  
  409.   SetVec4(name, v) {
  410.     this._uniforms[name].value = v;
  411.   }
  412.  
  413.   SetVec3(name, v) {
  414.     this._uniforms[name].value = v;
  415.   }
  416.  
  417.   SetTexture(name, t) {
  418.     this._uniforms[name].value = t;
  419.   }
  420.  
  421.   Bind(constants) {
  422.     this._shaderData.Bind();
  423.  
  424.     let textureIndex = 0;
  425.  
  426.     for (let k in this._uniforms) {
  427.       const v = this._uniforms[k];
  428.  
  429.       let value = constants[k];
  430.       if (v.value) {
  431.         value = v.value;
  432.       }
  433.  
  434.       if (value && v.location) {
  435.         const t = v.type;
  436.  
  437.         if (t == 'mat4') {
  438.           GL.uniformMatrix4fv(v.location, false, value);
  439.         } else if (t == 'mat3') {
  440.           GL.uniformMatrix3fv(v.location, false, value);
  441.         } else if (t == 'vec4') {
  442.           GL.uniform4fv(v.location, value);
  443.         } else if (t == 'vec3') {
  444.           GL.uniform3fv(v.location, value);
  445.         } else if (t == 'texture') {
  446.           value.Bind(textureIndex);
  447.           GL.uniform1i(v.location, textureIndex);
  448.           textureIndex++;
  449.         }
  450.       }
  451.     }
  452.   }
  453. }
  454.  
  455.  
  456. class Texture {
  457.   constructor() {
  458.   }
  459.  
  460.   Load(src) {
  461.     this._name = src;
  462.     this._Load(src);
  463.     return this;
  464.   }
  465.  
  466.   _Load(src) {
  467.     this._texture = GL.createTexture();
  468.     GL.bindTexture(GL.TEXTURE_2D, this._texture);
  469.     GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA,
  470.                   1, 1, 0, GL.RGBA, GL.UNSIGNED_BYTE,
  471.                   new Uint8Array([0, 0, 255, 255]));
  472.  
  473.     const img = new Image();
  474.     img.src = src;
  475.     img.onload = () => {
  476.       GL.bindTexture(GL.TEXTURE_2D, this._texture);
  477.       GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, img);  
  478.       GL.generateMipmap(GL.TEXTURE_2D);
  479.       GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR_MIPMAP_LINEAR);
  480.       GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR);
  481.       GL.bindTexture(GL.TEXTURE_2D, null);
  482.     };
  483.   }
  484.  
  485.   Bind(index) {
  486.     if (!this._texture) {
  487.       return;
  488.     }
  489.     GL.activeTexture(GL.TEXTURE0 + index);
  490.     GL.bindTexture(GL.TEXTURE_2D, this._texture);
  491.   }
  492.  
  493.   Unbind() {
  494.     GL.bindTexture(GL.TEXTURE_2D, null);
  495.   }
  496. }
  497.  
  498.  
  499. class Mesh {
  500.   constructor() {
  501.     this._buffers = {};
  502.  
  503.     this._OnInit();
  504.   }
  505.  
  506.   _BufferData(info, name) {
  507.     if (name == 'index') {
  508.       info.buffer = GL.createBuffer();
  509.       GL.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, info.buffer);
  510.       GL.bufferData(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(info.data), GL.STATIC_DRAW);
  511.     } else {
  512.       info.buffer = GL.createBuffer();
  513.       GL.bindBuffer(GL.ARRAY_BUFFER, info.buffer);
  514.       GL.bufferData(GL.ARRAY_BUFFER, new Float32Array(info.data), GL.STATIC_DRAW);
  515.     }
  516.  
  517.     this._buffers[name] = info;
  518.   }
  519.  
  520.   Bind(shader) {
  521.     for (let k in this._buffers) {
  522.       if (shader._attribs[k] == -1) {
  523.         continue;
  524.       }
  525.  
  526.       const b = this._buffers[k];
  527.  
  528.       if (k == 'index') {
  529.         GL.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, b.buffer);
  530.       } else {
  531.         GL.bindBuffer(GL.ARRAY_BUFFER, b.buffer);
  532.         GL.vertexAttribPointer(shader._attribs[k], b.size, GL.FLOAT, false, 0, 0);
  533.         GL.enableVertexAttribArray(shader._attribs[k]);
  534.       }
  535.     }
  536.   }
  537.  
  538.   Draw() {
  539.     const vertexCount = this._buffers.index.data.length;
  540.     GL.drawElements(GL.TRIANGLES, vertexCount, GL.UNSIGNED_SHORT, 0);
  541.   }
  542. }
  543.  
  544.  
  545. class MeshInstance {
  546.   constructor(mesh, shaders, shaderParams) {
  547.     this._mesh = mesh;
  548.     this._shaders = shaders;
  549.  
  550.     shaderParams = shaderParams || {};
  551.     for (let sk in shaders) {
  552.       const s = shaders[sk];
  553.       for (let k in shaderParams) {
  554.         s.SetTexture(k, shaderParams[k]);
  555.       }  
  556.     }
  557.  
  558.     this._position = vec3.create();
  559.     this._scale = vec3.fromValues(1, 1, 1);
  560.     this._rotation = quat.create();
  561.   }
  562.  
  563.   SetPosition(x, y, z) {
  564.     vec3.set(this._position, x, y, z);
  565.   }
  566.  
  567.   RotateX(rad) {
  568.     quat.rotateX(this._rotation, this._rotation, rad);
  569.   }
  570.  
  571.   RotateY(rad) {
  572.     quat.rotateY(this._rotation, this._rotation, rad);
  573.   }
  574.  
  575.   Scale(x, y, z) {
  576.     vec3.set(this._scale, x, y, z);
  577.   }
  578.  
  579.   Bind(constants, pass) {
  580.     const modelMatrix = mat4.create();
  581.     mat4.fromRotationTranslationScale(
  582.         modelMatrix, this._rotation, this._position, this._scale);
  583.  
  584.     // TODO View matrix
  585.     const viewMatrix = constants['viewMatrix'];
  586.     const modelViewMatrix = mat4.create();
  587.     mat4.multiply(modelViewMatrix, viewMatrix, modelMatrix);
  588.  
  589.     const normalMatrix = mat3.create();
  590.     mat3.fromMat4(normalMatrix, modelMatrix);
  591.     mat3.invert(normalMatrix, normalMatrix);
  592.     mat3.transpose(normalMatrix, normalMatrix);
  593.  
  594.     const s = this._shaders[pass];
  595.  
  596.     s.SetMat4('modelViewMatrix', modelViewMatrix);
  597.     s.SetMat4('modelMatrix', modelMatrix);
  598.     s.SetMat3('normalMatrix', normalMatrix);
  599.     s.Bind(constants);
  600.  
  601.     this._mesh.Bind(s);
  602.   }
  603.  
  604.   Draw() {
  605.     this._mesh.Draw();
  606.   }
  607. }
  608.  
  609.  
  610. class Box extends Mesh {
  611.   constructor() {
  612.     super();
  613.   }
  614.  
  615.   _OnInit() {
  616.     const positions = [
  617.       // Front face
  618.       -1.0, -1.0,  1.0,
  619.       1.0, -1.0,  1.0,
  620.       1.0,  1.0,  1.0,
  621.       -1.0,  1.0,  1.0,
  622.  
  623.       // Back face
  624.       -1.0, -1.0, -1.0,
  625.       -1.0,  1.0, -1.0,
  626.       1.0,  1.0, -1.0,
  627.       1.0, -1.0, -1.0,
  628.  
  629.       // Top face
  630.       -1.0,  1.0, -1.0,
  631.       -1.0,  1.0,  1.0,
  632.       1.0,  1.0,  1.0,
  633.       1.0,  1.0, -1.0,
  634.  
  635.       // Bottom face
  636.       -1.0, -1.0, -1.0,
  637.       1.0, -1.0, -1.0,
  638.       1.0, -1.0,  1.0,
  639.       -1.0, -1.0,  1.0,
  640.  
  641.       // Right face
  642.       1.0, -1.0, -1.0,
  643.       1.0,  1.0, -1.0,
  644.       1.0,  1.0,  1.0,
  645.       1.0, -1.0,  1.0,
  646.  
  647.       // Left face
  648.       -1.0, -1.0, -1.0,
  649.       -1.0, -1.0,  1.0,
  650.       -1.0,  1.0,  1.0,
  651.       -1.0,  1.0, -1.0,
  652.     ];
  653.  
  654.     const uvs = [
  655.       // Front face
  656.       0.0, 0.0,
  657.       1.0, 0.0,
  658.       1.0, 1.0,
  659.       0.0, 1.0,
  660.  
  661.       // Back face
  662.       0.0, 0.0,
  663.       1.0, 0.0,
  664.       1.0, 1.0,
  665.       0.0, 1.0,
  666.  
  667.       // Top face
  668.       0.0, 0.0,
  669.       1.0, 0.0,
  670.       1.0, 1.0,
  671.       0.0, 1.0,
  672.  
  673.       // Bottom face
  674.       0.0, 0.0,
  675.       1.0, 0.0,
  676.       1.0, 1.0,
  677.       0.0, 1.0,
  678.  
  679.       // Right face
  680.       0.0, 0.0,
  681.       1.0, 0.0,
  682.       1.0, 1.0,
  683.       0.0, 1.0,
  684.  
  685.       // Left face
  686.       0.0, 0.0,
  687.       1.0, 0.0,
  688.       1.0, 1.0,
  689.       0.0, 1.0,
  690.     ];
  691.  
  692.     const normals = [
  693.       // Front face
  694.       0.0, 0.0, 1.0,
  695.       0.0, 0.0, 1.0,
  696.       0.0, 0.0, 1.0,
  697.       0.0, 0.0, 1.0,
  698.  
  699.       // Back face
  700.       0.0, 0.0, -1.0,
  701.       0.0, 0.0, -1.0,
  702.       0.0, 0.0, -1.0,
  703.       0.0, 0.0, -1.0,
  704.  
  705.       // Top face
  706.       0.0, 1.0, 0.0,
  707.       0.0, 1.0, 0.0,
  708.       0.0, 1.0, 0.0,
  709.       0.0, 1.0, 0.0,
  710.  
  711.       // Bottom face
  712.       0.0, -1.0, 0.0,
  713.       0.0, -1.0, 0.0,
  714.       0.0, -1.0, 0.0,
  715.       0.0, -1.0, 0.0,
  716.  
  717.       // Right face
  718.       1.0, 0.0, 0.0,
  719.       1.0, 0.0, 0.0,
  720.       1.0, 0.0, 0.0,
  721.       1.0, 0.0, 0.0,
  722.  
  723.       // Left face
  724.       -1.0, 0.0, 0.0,
  725.       -1.0, 0.0, 0.0,
  726.       -1.0, 0.0, 0.0,
  727.       -1.0, 0.0, 0.0,
  728.     ];
  729.  
  730.     const tangents = [
  731.       // Front face
  732.       -1.0, 0.0, 0.0,
  733.       -1.0, 0.0, 0.0,
  734.       -1.0, 0.0, 0.0,
  735.       -1.0, 0.0, 0.0,
  736.  
  737.       // Back face
  738.       0.0, 1.0, 0.0,
  739.       0.0, 1.0, 0.0,
  740.       0.0, 1.0, 0.0,
  741.       0.0, 1.0, 0.0,
  742.  
  743.       // Top face
  744.       0.0, 0.0, 1.0,
  745.       0.0, 0.0, 1.0,
  746.       0.0, 0.0, 1.0,
  747.       0.0, 0.0, 1.0,
  748.  
  749.       // Bottom face
  750.       -1.0, 0.0, 0.0,
  751.       -1.0, 0.0, 0.0,
  752.       -1.0, 0.0, 0.0,
  753.       -1.0, 0.0, 0.0,
  754.  
  755.       // Right face
  756.       0.0, 1.0, 0.0,
  757.       0.0, 1.0, 0.0,
  758.       0.0, 1.0, 0.0,
  759.       0.0, 1.0, 0.0,
  760.  
  761.       // Left face
  762.       0.0, 0.0, -1.0,
  763.       0.0, 0.0, -1.0,
  764.       0.0, 0.0, -1.0,
  765.       0.0, 0.0, -1.0,
  766.     ];
  767.  
  768.     const faceColors = [
  769.       [1.0,  1.0,  1.0,  1.0],    // Front face: white
  770.       [1.0,  0.0,  0.0,  1.0],    // Back face: red
  771.       [0.0,  1.0,  0.0,  1.0],    // Top face: green
  772.       [0.0,  0.0,  1.0,  1.0],    // Bottom face: blue
  773.       [1.0,  1.0,  0.0,  1.0],    // Right face: yellow
  774.       [1.0,  0.0,  1.0,  1.0],    // Left face: purple
  775.     ];
  776.  
  777.     // Convert the array of colors into a table for all the vertices.
  778.  
  779.     let colours = [];
  780.  
  781.     for (var j = 0; j < faceColors.length; ++j) {
  782.       const c = faceColors[j];
  783.  
  784.       // Repeat each color four times for the four vertices of the face
  785.       colours = colours.concat(c, c, c, c);
  786.     }
  787.  
  788.     const indices = [
  789.       0,  1,  2,      0,  2,  3,    // front
  790.       4,  5,  6,      4,  6,  7,    // back
  791.       8,  9,  10,     8,  10, 11,   // top
  792.       12, 13, 14,     12, 14, 15,   // bottom
  793.       16, 17, 18,     16, 18, 19,   // right
  794.       20, 21, 22,     20, 22, 23,   // left
  795.     ];
  796.  
  797.     this._BufferData({size: 3, data: positions}, 'positions');
  798.     this._BufferData({size: 3, data: normals}, 'normals');
  799.     this._BufferData({size: 3, data: tangents}, 'tangents');
  800.     this._BufferData({size: 4, data: colours}, 'colours');
  801.     this._BufferData({size: 2, data: uvs}, 'uvs');
  802.     this._BufferData({data: indices}, 'index');
  803.   }
  804. }
  805.  
  806. class Quad extends Mesh {
  807.   constructor() {
  808.     super();
  809.   }
  810.  
  811.   _OnInit() {
  812.     const positions = [
  813.       -0.5, -0.5, 1.0,
  814.       0.5, -0.5, 1.0,
  815.       0.5, 0.5, 1.0,
  816.       -0.5, 0.5, 1.0,
  817.     ];
  818.  
  819.     const normals = [
  820.       0.0, 0.0, 1.0,
  821.       0.0, 0.0, 1.0,
  822.       0.0, 0.0, 1.0,
  823.       0.0, 0.0, 1.0,
  824.     ];
  825.  
  826.     const tangents = [
  827.       -1.0, 0.0, 0.0,
  828.       -1.0, 0.0, 0.0,
  829.       -1.0, 0.0, 0.0,
  830.       -1.0, 0.0, 0.0,
  831.     ];
  832.  
  833.     const uvs = [
  834.       0.0, 0.0,
  835.       1.0, 0.0,
  836.       1.0, 1.0,
  837.       0.0, 1.0,
  838.     ];
  839.  
  840.     const indices = [
  841.       0, 1, 2,
  842.       0, 2, 3,
  843.     ];
  844.  
  845.     this._BufferData({size: 3, data: positions}, 'positions');
  846.     this._BufferData({size: 3, data: normals}, 'normals');
  847.     this._BufferData({size: 3, data: tangents}, 'tangents');
  848.     this._BufferData({size: 2, data: uvs}, 'uvs');
  849.     this._BufferData({data: indices}, 'index');
  850.   }
  851. }
  852.  
  853.  
  854. class Camera {
  855.   constructor() {
  856.     this._position = vec3.create();
  857.     this._target = vec3.create();
  858.     this._viewMatrix = mat4.create();
  859.     this._cameraMatrix = mat4.create();
  860.   }
  861.  
  862.   SetPosition(x, y, z) {
  863.     vec3.set(this._position, x, y, z);
  864.   }
  865.  
  866.   SetTarget(x, y, z) {
  867.     vec3.set(this._target, x, y, z);
  868.   }
  869.  
  870.   UpdateConstants(constants) {
  871.     mat4.lookAt(this._viewMatrix, this._position, this._target, vec3.fromValues(0, 1, 0));
  872.     mat4.invert(this._cameraMatrix, this._viewMatrix);
  873.  
  874.     constants['projectionMatrix'] = this._projectionMatrix;
  875.     constants['viewMatrix'] = this._viewMatrix;
  876.     constants['cameraMatrix'] = this._cameraMatrix;
  877.     constants['cameraPosition'] = this._position;
  878.   }
  879. }
  880.  
  881.  
  882. class PerspectiveCamera extends Camera {
  883.   constructor(fov, aspect, zNear, zFar) {
  884.     super();
  885.  
  886.     this._projectionMatrix = mat4.create();
  887.     this._fov = fov;
  888.     this._aspect = aspect;
  889.     this._zNear = zNear;
  890.     this._zFar = zFar;
  891.  
  892.     mat4.perspective(this._projectionMatrix, fov * Math.PI / 180.0, aspect, zNear, zFar);
  893.   }
  894.  
  895.   GetUp() {
  896.     const v = vec4.fromValues(0, 0, 1, 0);
  897.  
  898.     vec4.transformMat4(v, v, this._cameraMatrix);
  899.  
  900.     return v;
  901.   }
  902.  
  903.   GetRight() {
  904.     const v = vec4.fromValues(1, 0, 0, 0);
  905.  
  906.     vec4.transformMat4(v, v, this._cameraMatrix);
  907.  
  908.     return v;
  909.   }
  910. }
  911.  
  912.  
  913. class OrthoCamera extends Camera {
  914.   constructor(l, r, b, t, n, f) {
  915.     super();
  916.  
  917.     this._projectionMatrix = mat4.create();
  918.  
  919.     mat4.ortho(this._projectionMatrix, l, r, b, t, n, f);
  920.   }
  921. }
  922.  
  923.  
  924. class Light {
  925.   constructor() {
  926.   }
  927.  
  928.   UpdateConstants() {
  929.   }
  930. }
  931.  
  932.  
  933. class DirectionalLight extends Light {
  934.   constructor() {
  935.     super();
  936.  
  937.     this._colour = vec3.fromValues(1, 1, 1);
  938.     this._direction = vec3.fromValues(1, 0, 0);
  939.   }
  940.  
  941.   get Type() {
  942.     return 'Directional';
  943.   }
  944.  
  945.   SetColour(r, g, b) {
  946.     vec3.set(this._colour, r, g, b);
  947.   }
  948.  
  949.   SetDirection(x, y, z) {
  950.     vec3.set(this._direction, x, y, z);
  951.     vec3.normalize(this._direction, this._direction);
  952.   }
  953.  
  954.   UpdateConstants(constants) {
  955.     constants['lightDirection'] = this._direction;
  956.     constants['lightColour'] = this._colour;
  957.   }
  958. }
  959.  
  960. class PointLight extends Light {
  961.   constructor() {
  962.     super();
  963.  
  964.     this._colour = vec3.fromValues(1, 1, 1);
  965.     this._position = vec3.create();
  966.     this._attenuation = vec3.create();
  967.   }
  968.  
  969.   get Type() {
  970.     return 'Point';
  971.   }
  972.  
  973.   SetColour(r, g, b) {
  974.     vec3.set(this._colour, r, g, b);
  975.   }
  976.  
  977.   SetPosition(x, y, z) {
  978.     vec3.set(this._position, x, y, z);
  979.   }
  980.  
  981.   SetRadius(r1, r2) {
  982.     vec3.set(this._attenuation, r1, r2, 0);
  983.   }
  984.  
  985.   UpdateConstants(constants) {
  986.     constants['lightPosition'] = this._position;
  987.     constants['lightColour'] = this._colour;
  988.     constants['lightAttenuation'] = this._attenuation;
  989.   }
  990. }
  991.  
  992.  
  993. class Renderer {
  994.   constructor() {
  995.     this._Init();
  996.   }
  997.  
  998.   _Init() {
  999.     this._canvas = document.createElement('canvas');
  1000.  
  1001.     document.body.appendChild(this._canvas);
  1002.  
  1003.     GL = this._canvas.getContext('webgl2');
  1004.  
  1005.     if (GL === null) {
  1006.       alert("Unable to initialize WebGL. Your browser or machine may not support it.");
  1007.       return;
  1008.     }
  1009.  
  1010.     this._constants = {};
  1011.  
  1012.     this._textures = {};
  1013.     this._textures['test-diffuse'] = new Texture().Load('./resources/rough-wet-cobble-albedo-1024.png');
  1014.     this._textures['test-normal'] = new Texture().Load('./resources/rough-wet-cobble-normal-1024.jpg');
  1015.     this._textures['worn-bumpy-rock-albedo'] = new Texture().Load(
  1016.         './resources/worn-bumpy-rock-albedo-1024.png');
  1017.     this._textures['worn-bumpy-rock-normal'] = new Texture().Load(
  1018.         './resources/worn-bumpy-rock-normal-1024.jpg');
  1019.  
  1020.     this._shaders = {};
  1021.     this._shaders['z'] = new Shader(_SIMPLE_VS, _SIMPLE_FS);
  1022.     this._shaders['default'] = new Shader(_OPAQUE_VS, _OPAQUE_FS);
  1023.  
  1024.     this._shaders['post-quad-colour'] = new Shader(
  1025.         _QUAD_COLOUR_VS, _QUAD_COLOUR_FS);
  1026.     this._shaders['post-quad-directional'] = new Shader(
  1027.         _QUAD_VS, _QUAD_FS, ['_LIGHT_TYPE_DIRECTIONAL']);
  1028.     this._shaders['post-quad-point'] = new Shader(
  1029.         _QUAD_VS, _QUAD_FS, ['_LIGHT_TYPE_POINT']);
  1030.  
  1031.     this._camera = new PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1.0, 1000.0);
  1032.     this._camera.SetPosition(0, 20, 10);
  1033.     this._camera.SetTarget(0, 0, -20);
  1034.  
  1035.     this._postCamera = new OrthoCamera(0.0, 1.0, 0.0, 1.0, 1.0, 1000.0);
  1036.  
  1037.     this._meshes = [];
  1038.     this._lights = [];
  1039.  
  1040.     this._quadDirectional = new MeshInstance(
  1041.         new Quad(),
  1042.         {light: new ShaderInstance(this._shaders['post-quad-directional'])});
  1043.     this._quadDirectional.SetPosition(0.5, 0.5, -10.0);
  1044.  
  1045.     this._quadPoint = new MeshInstance(
  1046.         new Quad(),
  1047.         {light: new ShaderInstance(this._shaders['post-quad-point'])});
  1048.     this._quadPoint.SetPosition(0.5, 0.5, -10.0);
  1049.  
  1050.     this._quadColour = new MeshInstance(
  1051.         new Quad(),
  1052.         {colour: new ShaderInstance(this._shaders['post-quad-colour'])});
  1053.     this._quadColour.SetPosition(0.5, 0.5, -10.0);
  1054.  
  1055.     this._InitGBuffer();
  1056.     this.Resize(window.innerWidth, window.innerHeight);
  1057.   }
  1058.  
  1059.   _InitGBuffer() {
  1060.     // Float textures have only been around for like 15 years.
  1061.     // So of course make them an extension.
  1062.     GL.getExtension('EXT_color_buffer_float');
  1063.  
  1064.     this._depthBuffer = GL.createRenderbuffer();
  1065.     GL.bindRenderbuffer(GL.RENDERBUFFER, this._depthBuffer);
  1066.     GL.renderbufferStorage(
  1067.         GL.RENDERBUFFER,
  1068.         GL.DEPTH_COMPONENT24,
  1069.         window.innerWidth, window.innerHeight);
  1070.     GL.bindRenderbuffer(GL.RENDERBUFFER, null);
  1071.  
  1072.     this._normalBuffer = GL.createTexture();
  1073.     GL.bindTexture(GL.TEXTURE_2D, this._normalBuffer);
  1074.     GL.texImage2D(
  1075.         GL.TEXTURE_2D, 0, GL.RGBA32F, window.innerWidth, window.innerHeight,
  1076.         0, GL.RGBA, GL.FLOAT, null);  
  1077.     GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
  1078.     GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
  1079.       GL.bindTexture(GL.TEXTURE_2D, null);
  1080.  
  1081.     this._positionBuffer = GL.createTexture();
  1082.     GL.bindTexture(GL.TEXTURE_2D, this._positionBuffer);
  1083.     GL.texImage2D(
  1084.         GL.TEXTURE_2D, 0, GL.RGBA32F, window.innerWidth, window.innerHeight,
  1085.         0, GL.RGBA, GL.FLOAT, null);  
  1086.     GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
  1087.     GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
  1088.     GL.bindTexture(GL.TEXTURE_2D, null);
  1089.  
  1090.     this._lightBuffer = GL.createTexture();
  1091.     GL.bindTexture(GL.TEXTURE_2D, this._lightBuffer);
  1092.     GL.texImage2D(
  1093.         GL.TEXTURE_2D, 0, GL.RGBA32F, window.innerWidth, window.innerHeight,
  1094.         0, GL.RGBA, GL.FLOAT, null);  
  1095.     GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
  1096.     GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
  1097.     GL.bindTexture(GL.TEXTURE_2D, null);
  1098.  
  1099.     this._colourBuffer = GL.createTexture();
  1100.     GL.bindTexture(GL.TEXTURE_2D, this._colourBuffer);
  1101.     GL.texImage2D(
  1102.         GL.TEXTURE_2D, 0, GL.RGBA32F, window.innerWidth, window.innerHeight,
  1103.         0, GL.RGBA, GL.FLOAT, null);  
  1104.     GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
  1105.     GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
  1106.     GL.bindTexture(GL.TEXTURE_2D, null);
  1107.  
  1108.     // Create the FBO's for each pass
  1109.     this._zFBO = GL.createFramebuffer();
  1110.     GL.bindFramebuffer(GL.FRAMEBUFFER, this._zFBO);
  1111.     GL.framebufferRenderbuffer(
  1112.         GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, this._depthBuffer);
  1113.     GL.framebufferTexture2D(
  1114.         GL.DRAW_FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, this._normalBuffer, 0);
  1115.     GL.framebufferTexture2D(
  1116.         GL.DRAW_FRAMEBUFFER, GL.COLOR_ATTACHMENT1, GL.TEXTURE_2D, this._positionBuffer, 0);
  1117.     GL.bindFramebuffer(GL.FRAMEBUFFER, null);
  1118.  
  1119.     this._lightFBO = GL.createFramebuffer();
  1120.     GL.bindFramebuffer(GL.FRAMEBUFFER, this._lightFBO);
  1121.     GL.framebufferRenderbuffer(
  1122.         GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, this._depthBuffer);
  1123.     GL.framebufferTexture2D(
  1124.         GL.DRAW_FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, this._lightBuffer, 0);
  1125.     GL.bindFramebuffer(GL.FRAMEBUFFER, null);
  1126.  
  1127.     this._colourFBO = GL.createFramebuffer();
  1128.     GL.bindFramebuffer(GL.FRAMEBUFFER, this._colourFBO);
  1129.     GL.framebufferRenderbuffer(
  1130.         GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.RENDERBUFFER, this._depthBuffer);
  1131.     GL.framebufferTexture2D(
  1132.         GL.DRAW_FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, this._colourBuffer, 0);
  1133.     GL.bindFramebuffer(GL.FRAMEBUFFER, null);
  1134.  
  1135.     // GROSS
  1136.     this._normalTexture = new Texture();
  1137.     this._normalTexture._texture = this._normalBuffer;
  1138.  
  1139.     this._positionTexture = new Texture();
  1140.     this._positionTexture._texture = this._positionBuffer;
  1141.  
  1142.     this._lightTexture = new Texture();
  1143.     this._lightTexture._texture = this._lightBuffer;
  1144.  
  1145.     this._colourTexture = new Texture();
  1146.     this._colourTexture._texture = this._colourBuffer;
  1147.   }
  1148.  
  1149.   CreateMeshInstance(mesh, shaderParams) {
  1150.     const params = {};
  1151.     for (let k in shaderParams.params) {
  1152.       params[k] = this._textures[shaderParams.params[k]];
  1153.     }
  1154.  
  1155.     const m = new MeshInstance(
  1156.         mesh,
  1157.         {
  1158.           z: new ShaderInstance(this._shaders['z']),
  1159.           colour: new ShaderInstance(this._shaders[shaderParams.shader])
  1160.         }, params);
  1161.  
  1162.     this._meshes.push(m);
  1163.  
  1164.     return m;
  1165.   }
  1166.  
  1167.   CreateLight(type) {
  1168.     let l = null;
  1169.  
  1170.     if (type == 'directional') {
  1171.       l = new DirectionalLight();
  1172.     } else if (type == 'point') {
  1173.       l = new PointLight();
  1174.     }
  1175.  
  1176.     if (!l) {
  1177.       return null;
  1178.     }
  1179.  
  1180.     this._lights.push(l);
  1181.  
  1182.     return l;
  1183.   }
  1184.  
  1185.   Resize(w, h) {
  1186.     this._canvas.width = w;
  1187.     this._canvas.height = h;
  1188.     GL.viewport(0, 0, w, h);
  1189.   }
  1190.  
  1191.   _SetQuadSizeForLight(quad, light) {
  1192.     const wvp = mat4.create();
  1193.     const w = mat4.create();
  1194.     mat4.fromTranslation(w, light._position);
  1195.  
  1196.     const viewMatrix = this._camera._viewMatrix;
  1197.     const projectionMatrix = this._camera._projectionMatrix;
  1198.  
  1199.     const _TransformToScreenSpace = (p) => {
  1200.       const screenPos = vec4.fromValues(
  1201.           p[0], p[1], p[2], 1.0);
  1202.  
  1203.       vec4.transformMat4(screenPos, screenPos, projectionMatrix);
  1204.  
  1205.       screenPos[0] = (screenPos[0] / screenPos[3]) * 0.5 + 0.5;
  1206.       screenPos[1] = (screenPos[1] / screenPos[3]) * 0.5 + 0.5;
  1207.  
  1208.       return screenPos;
  1209.     };
  1210.  
  1211.     const lightRadius = (light._attenuation[0] + light._attenuation[1]);
  1212.     const lightDistance = vec3.distance(this._camera._position, light._position);
  1213.  
  1214.     if (lightDistance < lightRadius) {
  1215.       quad.SetPosition(0.5, 0.5, -10);
  1216.       quad.Scale(1, 1, 1);
  1217.     } else {
  1218.       const viewSpaceCenter = vec3.clone(light._position);
  1219.       vec3.transformMat4(viewSpaceCenter, viewSpaceCenter, viewMatrix);
  1220.  
  1221.       const rightPos = vec3.clone(viewSpaceCenter);
  1222.       const upPos = vec3.clone(viewSpaceCenter);
  1223.       vec3.add(rightPos, rightPos, vec3.fromValues(lightRadius, 0, 0));
  1224.       vec3.add(upPos, upPos, vec3.fromValues(0, -lightRadius, 0));
  1225.  
  1226.       const center = _TransformToScreenSpace(light._position);    
  1227.       const up = _TransformToScreenSpace(upPos);
  1228.       const right = _TransformToScreenSpace(rightPos);
  1229.  
  1230.       const radius = 2 * Math.max(
  1231.           vec2.distance(center, up), vec2.distance(center, right));
  1232.  
  1233.       quad.SetPosition(center[0], center[1], -10);
  1234.       quad.Scale(radius, radius, 1);
  1235.     }
  1236.   }
  1237.  
  1238.   Render(timeElapsed) {
  1239.     this._constants['resolution'] = vec4.fromValues(
  1240.         window.innerWidth, window.innerHeight, 0, 0);
  1241.     this._camera.UpdateConstants(this._constants);
  1242.  
  1243.     this._constants['gBuffer_Normal'] = null;
  1244.     this._constants['gBuffer_Position'] = null;
  1245.     this._constants['gBuffer_Colour'] = null;
  1246.     this._constants['gBuffer_Light'] = null;
  1247.  
  1248.     // Z-Prepass + normals
  1249.     GL.bindFramebuffer(GL.FRAMEBUFFER, this._zFBO);
  1250.     GL.drawBuffers([GL.COLOR_ATTACHMENT0, GL.COLOR_ATTACHMENT1]);
  1251.  
  1252.     GL.clearColor(0.0, 0.0, 0.0, 0.0);
  1253.     GL.clearDepth(1.0);
  1254.     GL.enable(GL.DEPTH_TEST);
  1255.     GL.depthMask(true);
  1256.     GL.depthFunc(GL.LEQUAL);
  1257.     GL.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT);
  1258.  
  1259.     this._camera.UpdateConstants(this._constants);
  1260.  
  1261.     for (let m of this._meshes) {
  1262.       m.Bind(this._constants, 'z');
  1263.       m.Draw();
  1264.     }
  1265.  
  1266.     GL.useProgram(null);
  1267.     GL.bindTexture(GL.TEXTURE_2D, null);
  1268.  
  1269.     // Light buffer generation
  1270.     GL.bindFramebuffer(GL.FRAMEBUFFER, this._lightFBO);
  1271.     GL.drawBuffers([GL.COLOR_ATTACHMENT0]);
  1272.  
  1273.     GL.clear(GL.COLOR_BUFFER_BIT);
  1274.     GL.disable(GL.DEPTH_TEST);
  1275.     GL.enable(GL.BLEND);
  1276.     GL.blendFunc(GL.ONE, GL.ONE);
  1277.  
  1278.     this._postCamera.UpdateConstants(this._constants);
  1279.  
  1280.     this._constants['gBuffer_Normal'] = this._normalTexture;
  1281.     this._constants['gBuffer_Position'] = this._positionTexture;
  1282.  
  1283.     for (let l of this._lights) {
  1284.       l.UpdateConstants(this._constants);
  1285.  
  1286.       let quad = null;
  1287.       if (l.Type == 'Directional') {
  1288.         quad = this._quadDirectional;
  1289.       } else if (l.Type == 'Point') {
  1290.         quad = this._quadPoint;
  1291.  
  1292.         // Calculate screenspace size
  1293.         this._SetQuadSizeForLight(quad, l);
  1294.       }
  1295.       quad.Bind(this._constants, 'light');
  1296.       quad.Draw();
  1297.     }
  1298.  
  1299.     GL.useProgram(null);
  1300.     GL.bindTexture(GL.TEXTURE_2D, null);
  1301.  
  1302.     // Colour pass
  1303.     GL.bindFramebuffer(GL.FRAMEBUFFER, this._colourFBO);
  1304.     GL.drawBuffers([GL.COLOR_ATTACHMENT0]);
  1305.     GL.disable(GL.BLEND);
  1306.     GL.depthMask(false);
  1307.     GL.enable(GL.DEPTH_TEST);
  1308.  
  1309.     this._camera.UpdateConstants(this._constants);
  1310.  
  1311.     this._constants['gBuffer_Colour'] = null;
  1312.     this._constants['gBuffer_Light'] = this._lightTexture;
  1313.     this._constants['gBuffer_Normal'] = null;
  1314.     this._constants['gBuffer_Position'] = null;
  1315.  
  1316.     for (let m of this._meshes) {
  1317.       m.Bind(this._constants, 'colour');
  1318.       m.Draw();
  1319.     }
  1320.  
  1321.     GL.useProgram(null);
  1322.     GL.bindTexture(GL.TEXTURE_2D, null);
  1323.     GL.disable(GL.BLEND);
  1324.  
  1325.     // Now just draw directly to screen
  1326.     GL.bindFramebuffer(GL.FRAMEBUFFER, null);
  1327.     GL.disable(GL.DEPTH_TEST);
  1328.     GL.disable(GL.BLEND);
  1329.  
  1330.     this._postCamera.UpdateConstants(this._constants);
  1331.  
  1332.     // Really fucking hate JavaScript sometimes.
  1333.     this._constants['gQuadTexture'] = this._colourTexture;
  1334.  
  1335.     this._quadColour.Bind(this._constants, 'colour');
  1336.     this._quadColour.Draw();
  1337.   }
  1338. }
  1339.  
  1340. class LightPrepassDemo {
  1341.   constructor() {
  1342.     this._Initialize();
  1343.   }
  1344.  
  1345.   _Initialize() {
  1346.     this._renderer = new Renderer();
  1347.  
  1348.     window.addEventListener('resize', () => {
  1349.       this._OnWindowResize();
  1350.     }, false);
  1351.  
  1352.     this._Init();
  1353.  
  1354.     this._previousRAF = null;
  1355.     this._RAF();
  1356.   }
  1357.  
  1358.   _OnWindowResize() {
  1359.     this._renderer.Resize(window.innerWidth, window.innerHeight);
  1360.   }
  1361.  
  1362.   _Init() {
  1363.     this._CreateLights();
  1364.     this._CreateMeshes();
  1365.   }
  1366.  
  1367.   _CreateLights() {
  1368.     this._lights = [];
  1369.  
  1370.     for (let i = -9; i <= 9; i++) {
  1371.       let l = this._renderer.CreateLight('point');
  1372.  
  1373.       const v = vec3.fromValues(Math.random(), Math.random(), Math.random());
  1374.       vec3.normalize(v, v);
  1375.  
  1376.       const p = vec3.fromValues(
  1377.         (Math.random() * 2 - 1) * 10,
  1378.         3,
  1379.         -Math.random() * 10 - 10);
  1380.  
  1381.       l.SetColour(v[0], v[1], v[2]);
  1382.       l.SetPosition(p[0], p[1], p[2]);
  1383.       l.SetRadius(4, 1);
  1384.  
  1385.       this._lights.push({
  1386.           light: l,
  1387.           position: p,
  1388.           acc: Math.random() * 10.0,
  1389.           accSpeed: Math.random() * 0.5 + 0.5,
  1390.       });
  1391.     }
  1392.   }
  1393.  
  1394.   _CreateMeshes() {
  1395.     this._meshes = [];
  1396.  
  1397.     let m = this._renderer.CreateMeshInstance(
  1398.         new Quad(),
  1399.         {
  1400.           shader: 'default',
  1401.           params: {
  1402.             diffuseTexture: 'worn-bumpy-rock-albedo',
  1403.             normalTexture: 'worn-bumpy-rock-normal',
  1404.           }
  1405.         });
  1406.     m.SetPosition(0, -2, -10);
  1407.     m.RotateX(-Math.PI * 0.5);
  1408.     m.Scale(50, 50, 1);
  1409.  
  1410.     for (let x = -5; x < 5; x++) {
  1411.       for (let y = 0; y < 20; y++) {
  1412.         let m = this._renderer.CreateMeshInstance(
  1413.             new Box(),
  1414.             {
  1415.               shader: 'default',
  1416.               params: {
  1417.                 diffuseTexture: 'test-diffuse',
  1418.                 normalTexture: 'test-normal',
  1419.               }
  1420.             });
  1421.         m.SetPosition(x * 4, 0, -y * 4);
  1422.    
  1423.         this._meshes.push(m);
  1424.       }
  1425.     }
  1426.   }
  1427.  
  1428.   _RAF() {
  1429.     requestAnimationFrame((t) => {
  1430.       if (this._previousRAF === null) {
  1431.         this._previousRAF = t;
  1432.       }
  1433.  
  1434.       this._RAF();
  1435.       this._Step(t - this._previousRAF);
  1436.       this._previousRAF = t;
  1437.     });
  1438.   }
  1439.  
  1440.   _Step(timeElapsed) {
  1441.     const timeElapsedS = timeElapsed * 0.001;
  1442.  
  1443.     for (let m of this._meshes) {
  1444.       m.RotateY(timeElapsedS);
  1445.     }
  1446.  
  1447.     for (let l of this._lights) {
  1448.       l.acc += timeElapsed * 0.001 * l.accSpeed;
  1449.  
  1450.       l.light.SetPosition(
  1451.           l.position[0] + 10 * Math.cos(l.acc),
  1452.           l.position[1],
  1453.           l.position[2] + 10 * Math.sin(l.acc));
  1454.     }
  1455.  
  1456.     this._renderer.Render(timeElapsedS);
  1457.   }
  1458. }
  1459.  
  1460.  
  1461. let _APP = null;
  1462.  
  1463. window.addEventListener('DOMContentLoaded', () => {
  1464.   _APP = new LightPrepassDemo();
  1465. });
Add Comment
Please, Sign In to add comment