

export var vs_hdr =
`#version 300 es
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;

out vec2 TexCoords;
void main()
{
TexCoords = aTexCoords;
gl_Position = vec4(aPos, 1.0);
}`
export var fs_hdr =
`#version 300 es
precision mediump float;
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D hdrBuffer;
uniform bool hdr;
uniform float exposure;
void main()
{
const float gamma = 2.2;
vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
if(hdr)
{
// reinhard
// vec3 result = hdrColor / (hdrColor + vec3(1.0));
// exposure
vec3 result = vec3(1.0) - exp(-hdrColor * exposure);
// also gamma correct while we're at it
result = pow(result, vec3(1.0 / gamma));
FragColor = vec4(result, 1.0);
}
else
{
vec3 result = pow(hdrColor, vec3(1.0 / gamma));
FragColor = vec4(result, 1.0);
}
}`
export var vs_lighting =
`#version 300 es
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform bool inverse_normals;
void main()
{
FragPos = vec3(model * vec4(aPos, 1.0));
TexCoords = aTexCoords;
vec3 n = inverse_normals ? -aNormal : aNormal;
mat3 normalMatrix = transpose(inverse(mat3(model)));
Normal = normalize(normalMatrix * n);
gl_Position = projection * view * model * vec4(aPos, 1.0);
}`
export var fs_lighting =
`#version 300 es
precision mediump float;
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
// struct Light {
// vec3 Position;
// vec3 Color;
// };
uniform vec3 lightPositions[4];
uniform vec3 lightColors[4];
//uniform Light lights[16];
uniform sampler2D diffuseTexture;
uniform vec3 viewPos;
void main()
{
vec3 color = texture(diffuseTexture, TexCoords).rgb;
vec3 normal = normalize(Normal);
// ambient
vec3 ambient = 0.0 * color;
// lighting
vec3 lighting = vec3(0.0);
for(int i = 0; i < 4; i++)
{
// diffuse
vec3 lightDir = normalize(lightPositions[i] - FragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = lightColors[i] * diff * color;
vec3 result = diffuse;
// attenuation (use quadratic as we have gamma correction)
float distance = length(FragPos - lightPositions[i]);
result *= 1.0 / (distance * distance);
lighting += result;
}
FragColor = vec4(ambient + lighting, 1.0);
}`
const sizeFloat = 4
let hdr = true
let deltaTime = 0.0
let lastFrame = 0.0
let cubeVAO = null
function renderCube() {
if (!cubeVAO) {
let vertices = new Float32Array([
-1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,
1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0,
1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 0.0,
1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0,
-1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,
-1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0,
-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0,
-1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0,
-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
-1.0, 1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 0.0,
-1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 1.0,
-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0,
-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0,
-1.0, -1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0,
1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 1.0,
1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0,
1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
-1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 1.0,
1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 1.0, 1.0,
1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0,
1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0,
-1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0,
-1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 1.0,
-1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0,
1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0,
1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0,
1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0,
-1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0,
-1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0
])
cubeVAO = gl.createVertexArray()
let cubeVBO = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVBO)
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
gl.bindVertexArray(cubeVAO)
gl.enableVertexAttribArray(0)
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 8 * sizeFloat, 0)
gl.enableVertexAttribArray(1)
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 8 * sizeFloat, (3 * sizeFloat))
gl.enableVertexAttribArray(2)
gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 8 * sizeFloat, (6 * sizeFloat))
gl.bindBuffer(gl.ARRAY_BUFFER, null)
gl.bindVertexArray(null)
}
gl.bindVertexArray(cubeVAO)
gl.drawArrays(gl.TRIANGLES, 0, 36)
gl.bindVertexArray(null)
}
let quadVBO = null
function renderQuad() {
let quadVBO = null
if (!quadVAO) {
let quadVertices = new Float32Array([
-1.0, 1.0, 0.0, 0.0, 1.0,
-1.0, -1.0, 0.0, 0.0, 0.0,
1.0, 1.0, 0.0, 1.0, 1.0,
1.0, -1.0, 0.0, 1.0, 0.0,
])
quadVAO = gl.createVertexArray()
quadVBO = gl.createBuffer()
gl.bindVertexArray(quadVAO)
gl.bindBuffer(gl.ARRAY_BUFFER, quadVBO)
gl.bufferData(gl.ARRAY_BUFFER, quadVertices, gl.STATIC_DRAW)
gl.enableVertexAttribArray(0)
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 5 * sizeFloat, 0)
gl.enableVertexAttribArray(1)
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 5 * sizeFloat, (3 * sizeFloat))
}
gl.bindVertexArray(quadVAO)
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
gl.bindVertexArray(null)
}
- createFramebuffer createTexture bindTexture texImage2D
- createRenderbuffer bindRenderbuffer renderbufferStorage bindFramebuffer renderbufferStorage framebufferTexture2D framebufferRenderbuffer

let exposure = 1.0
let main = function () {
gl.enable(gl.DEPTH_TEST)
shader = new Shader(gl, vs_lighting, fs_lighting)
hdrShader = new Shader(gl, vs_hdr, fs_hdr)
woodTexture = loadTexture("../../textures/wood.png", 4, false)
hdrFBO = gl.createFramebuffer()
colorBuffer = gl.createTexture()
gl.bindTexture(gl.TEXTURE_2D, colorBuffer)
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, canvas.width, canvas.height, 0, gl.RGBA, gl.FLOAT, null)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
let rboDepth
rboDepth = gl.createRenderbuffer()
gl.bindRenderbuffer(gl.RENDERBUFFER, rboDepth)
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, canvas.width, canvas.height)
gl.bindFramebuffer(gl.FRAMEBUFFER, hdrFBO)
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorBuffer, 0)
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rboDepth)
let check = gl.checkFramebufferStatus(gl.FRAMEBUFFER)
if (check != gl.FRAMEBUFFER_COMPLETE)
console.log("Framebuffer not complete")
gl.bindFramebuffer(gl.FRAMEBUFFER, null)
shader.use(gl)
shader.setInt(gl, "diffuseTexture", 0)
hdrShader.use(gl)
hdrShader.setInt(gl, "hdrBuffer", 0)
animate()
}()
function loadTexture(url, nrComponents, gammaCorrection) {
const textureID = gl.createTexture()
gl.bindTexture(gl.TEXTURE_2D, textureID)
const level = 0
const srcType = gl.UNSIGNED_BYTE
const pixel = new Uint8Array([0, 0, 255, 255])
gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, 1, 1, 0, gl.RGBA, srcType, pixel)
const image = new Image()
image.onload = function () {
let internalFormat
let dataFormat
if (nrComponents == 1) {
internalFormat = dataFormat = gl.RED
}
else if (nrComponents == 3) {
internalFormat = gammaCorrection ? gl.SRGB : gl.RGB
dataFormat = gl.RGB
}
else if (nrComponents == 4) {
internalFormat = gammaCorrection ? gl.SRGB8_ALPHA8 : gl.RGBA
dataFormat = gl.RGBA
}
gl.bindTexture(gl.TEXTURE_2D, textureID)
gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, image.naturalWidth, image.naturalHeight, 0, dataFormat, gl.UNSIGNED_BYTE, image)
gl.generateMipmap(gl.TEXTURE_2D)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
}
image.src = url
return textureID
}
lightPositions = new Float32Array([
0.0, 0.0, 49.5,
-1.4, -1.9, 9.0,
0.0, -1.8, 4.0,
0.8, -1.7, 6.0
])
lightColors = new Float32Array([
200.0, 200.0, 200.0,
0.1, 0.0, 0.0,
0.0, 0.0, 0.2,
0.0, 0.1, 0.0
])
function render() {
let currentFrame = performance.now()
deltaTime = currentFrame - lastFrame
lastFrame = currentFrame
processInput()
gl.clearColor(0.4, 0.1, 0.1, 1.0)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.bindFramebuffer(gl.FRAMEBUFFER, hdrFBO)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
mat4.perspective(projection, (camera.Zoom) * Math.PI / 180, canvas.width / canvas.height, 0.1, 100.0)
view = camera.GetViewMatrix()
shader.use(gl)
gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "projection"), false, projection)
gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "view"), false, view)
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, woodTexture)
gl.uniform3fv(gl.getUniformLocation(shader.programId, "lightPositions"), lightPositions)
gl.uniform3fv(gl.getUniformLocation(shader.programId, "lightColors"), lightColors)
gl.uniform3fv(gl.getUniformLocation(shader.programId, "viewPos"), camera.Position)
let model = mat4.create()
mat4.translate(model, model, vec3.fromValues(0.0, 0.0, 25.0))
mat4.scale(model, model, vec3.fromValues(2.5, 2.5, 27.5))
gl.uniformMatrix4fv(gl.getUniformLocation(shader.programId, "model"), false, model)
shader.setBoolean(gl, "inverse_normals", true)
renderCube()
gl.bindFramebuffer(gl.FRAMEBUFFER, null)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
hdrShader.use(gl)
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, colorBuffer)
hdrShader.setBoolean(gl, "hdr", hdr)
hdrShader.setFloat(gl, "exposure", exposure)
renderQuad()
}