This repository has been archived by the owner on Nov 22, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* move out scene processing * add gbuffer prototype * render gbuffer to framebuffer * use gbuffers for first ray trace bounce * extract material buffer creation to shared filed * rasterize material index * normalize normals * rasterize materials * antialiasing * fullscreen reprojection * reproject preview with light upscaling * use half-floats * restructure gbuffer outputs * use float32 for hdrBuffer; use linear filtering * upscale light near envmap * remove debug line * wrap uvs greater than 1 * upscale in tonemap step * disable jitter on camera move * only upscale if necessary * disable missing uniform log * cleanup * use integer attribute for mesh index
- Loading branch information
Lucas Crane
authored
Jan 30, 2020
1 parent
d42ea7d
commit c73d19b
Showing
30 changed files
with
1,121 additions
and
677 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { makeRenderPass } from './RenderPass'; | ||
import vertex from './glsl/gBuffer.vert'; | ||
import fragment from './glsl/gBuffer.frag'; | ||
import { Matrix4 } from 'three'; | ||
|
||
export function makeGBufferPass(gl, { materialBuffer, mergedMesh }) { | ||
const renderPass = makeRenderPass(gl, { | ||
defines: materialBuffer.defines, | ||
vertex, | ||
fragment | ||
}); | ||
|
||
renderPass.setTexture('diffuseMap', materialBuffer.textures.diffuseMap); | ||
renderPass.setTexture('normalMap', materialBuffer.textures.normalMap); | ||
renderPass.setTexture('pbrMap', materialBuffer.textures.pbrMap); | ||
|
||
const geometry = mergedMesh.geometry; | ||
|
||
const elementCount = geometry.getIndex().count; | ||
|
||
const vao = gl.createVertexArray(); | ||
|
||
gl.bindVertexArray(vao); | ||
uploadAttributes(gl, renderPass, geometry); | ||
gl.bindVertexArray(null); | ||
|
||
let jitterX = 0; | ||
let jitterY = 0; | ||
function setJitter(x, y) { | ||
jitterX = x; | ||
jitterY = y; | ||
} | ||
|
||
let currentCamera; | ||
function setCamera(camera) { | ||
currentCamera = camera; | ||
} | ||
|
||
function calcCamera() { | ||
projView.copy(currentCamera.projectionMatrix); | ||
|
||
projView.elements[8] += 2 * jitterX; | ||
projView.elements[9] += 2 * jitterY; | ||
|
||
projView.multiply(currentCamera.matrixWorldInverse); | ||
renderPass.setUniform('projView', projView.elements); | ||
} | ||
|
||
let projView = new Matrix4(); | ||
|
||
function draw() { | ||
calcCamera(); | ||
gl.bindVertexArray(vao); | ||
renderPass.useProgram(); | ||
gl.enable(gl.DEPTH_TEST); | ||
gl.drawElements(gl.TRIANGLES, elementCount, gl.UNSIGNED_INT, 0); | ||
gl.disable(gl.DEPTH_TEST); | ||
} | ||
|
||
return { | ||
draw, | ||
outputLocs: renderPass.outputLocs, | ||
setCamera, | ||
setJitter | ||
}; | ||
} | ||
|
||
function uploadAttributes(gl, renderPass, geometry) { | ||
setAttribute(gl, renderPass.attribLocs.aPosition, geometry.getAttribute('position')); | ||
setAttribute(gl, renderPass.attribLocs.aNormal, geometry.getAttribute('normal')); | ||
setAttribute(gl, renderPass.attribLocs.aUv, geometry.getAttribute('uv')); | ||
setAttribute(gl, renderPass.attribLocs.aMaterialMeshIndex, geometry.getAttribute('materialMeshIndex')); | ||
|
||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer()); | ||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, geometry.getIndex().array, gl.STATIC_DRAW); | ||
} | ||
|
||
function setAttribute(gl, location, bufferAttribute) { | ||
const { itemSize, array } = bufferAttribute; | ||
|
||
gl.enableVertexAttribArray(location); | ||
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); | ||
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW); | ||
|
||
if (array instanceof Float32Array) { | ||
gl.vertexAttribPointer(location, itemSize, gl.FLOAT, false, 0, 0); | ||
} else if (array instanceof Int32Array) { | ||
gl.vertexAttribIPointer(location, itemSize, gl.INT, 0, 0); | ||
} else { | ||
throw 'Unsupported buffer type'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
import { ThinMaterial, ThickMaterial, ShadowCatcherMaterial } from '../constants'; | ||
import materialBufferChunk from './glsl/chunks/materialBuffer.glsl'; | ||
import { makeUniformBuffer } from './UniformBuffer'; | ||
import { makeRenderPass } from "./RenderPass"; | ||
import { makeTexture } from './Texture'; | ||
import { getTexturesFromMaterials, mergeTexturesFromMaterials } from './texturesFromMaterials'; | ||
|
||
export function makeMaterialBuffer(gl, materials) { | ||
const maps = getTexturesFromMaterials(materials, ['map', 'normalMap']); | ||
const pbrMap = mergeTexturesFromMaterials(materials, ['roughnessMap', 'metalnessMap']); | ||
|
||
const textures = {}; | ||
|
||
const bufferData = {}; | ||
|
||
bufferData.color = materials.map(m => m.color); | ||
bufferData.roughness = materials.map(m => m.roughness); | ||
bufferData.metalness = materials.map(m => m.metalness); | ||
bufferData.normalScale = materials.map(m => m.normalScale); | ||
|
||
bufferData.type = materials.map(m => { | ||
if (m.shadowCatcher) { | ||
return ShadowCatcherMaterial; | ||
} | ||
if (m.transparent) { | ||
return m.solid ? ThickMaterial : ThinMaterial; | ||
} | ||
}); | ||
|
||
if (maps.map.textures.length > 0) { | ||
const { relativeSizes, texture } = makeTextureArray(gl, maps.map.textures, true); | ||
textures.diffuseMap = texture; | ||
bufferData.diffuseMapSize = relativeSizes; | ||
bufferData.diffuseMapIndex = maps.map.indices; | ||
} | ||
|
||
if (maps.normalMap.textures.length > 0) { | ||
const { relativeSizes, texture } = makeTextureArray(gl, maps.normalMap.textures, false); | ||
textures.normalMap = texture; | ||
bufferData.normalMapSize = relativeSizes; | ||
bufferData.normalMapIndex = maps.normalMap.indices; | ||
} | ||
|
||
if (pbrMap.textures.length > 0) { | ||
const { relativeSizes, texture } = makeTextureArray(gl, pbrMap.textures, false); | ||
textures.pbrMap = texture; | ||
bufferData.pbrMapSize = relativeSizes; | ||
bufferData.roughnessMapIndex = pbrMap.indices.roughnessMap; | ||
bufferData.metalnessMapIndex = pbrMap.indices.metalnessMap; | ||
} | ||
|
||
const defines = { | ||
NUM_MATERIALS: materials.length, | ||
NUM_DIFFUSE_MAPS: maps.map.textures.length, | ||
NUM_NORMAL_MAPS: maps.normalMap.textures.length, | ||
NUM_DIFFUSE_NORMAL_MAPS: Math.max(maps.map.textures.length, maps.normalMap.textures.length), | ||
NUM_PBR_MAPS: pbrMap.textures.length, | ||
}; | ||
|
||
// create temporary shader program including the Material uniform buffer | ||
// used to query the compiled structure of the uniform buffer | ||
const renderPass = makeRenderPass(gl, { | ||
vertex: { | ||
source: `void main() {}` | ||
}, | ||
fragment: { | ||
includes: [ materialBufferChunk ], | ||
source: `void main() {}` | ||
}, | ||
defines | ||
}); | ||
|
||
uploadToUniformBuffer(gl, renderPass.program, bufferData); | ||
|
||
return { defines, textures }; | ||
} | ||
|
||
function makeTextureArray(gl, textures, gammaCorrection = false) { | ||
const images = textures.map(t => t.image); | ||
const flipY = textures.map(t => t.flipY); | ||
const { maxSize, relativeSizes } = maxImageSize(images); | ||
|
||
// create GL Array Texture from individual textures | ||
const texture = makeTexture(gl, { | ||
width: maxSize.width, | ||
height: maxSize.height, | ||
gammaCorrection, | ||
data: images, | ||
flipY, | ||
channels: 3, | ||
minFilter: gl.LINEAR, | ||
magFilter: gl.LINEAR, | ||
}); | ||
|
||
return { | ||
texture, | ||
relativeSizes | ||
}; | ||
} | ||
|
||
function maxImageSize(images) { | ||
const maxSize = { | ||
width: 0, | ||
height: 0 | ||
}; | ||
|
||
for (const image of images) { | ||
maxSize.width = Math.max(maxSize.width, image.width); | ||
maxSize.height = Math.max(maxSize.height, image.height); | ||
} | ||
|
||
const relativeSizes = []; | ||
for (const image of images) { | ||
relativeSizes.push(image.width / maxSize.width); | ||
relativeSizes.push(image.height / maxSize.height); | ||
} | ||
|
||
return { maxSize, relativeSizes }; | ||
} | ||
|
||
|
||
// Upload arrays to uniform buffer objects | ||
// Packs different arrays into vec4's to take advantage of GLSL's std140 memory layout | ||
|
||
function uploadToUniformBuffer(gl, program, bufferData) { | ||
const materialBuffer = makeUniformBuffer(gl, program, 'Materials'); | ||
|
||
materialBuffer.set('Materials.colorAndMaterialType[0]', interleave( | ||
{ data: [].concat(...bufferData.color.map(d => d.toArray())), channels: 3 }, | ||
{ data: bufferData.type, channels: 1} | ||
)); | ||
|
||
materialBuffer.set('Materials.roughnessMetalnessNormalScale[0]', interleave( | ||
{ data: bufferData.roughness, channels: 1 }, | ||
{ data: bufferData.metalness, channels: 1 }, | ||
{ data: [].concat(...bufferData.normalScale.map(d => d.toArray())), channels: 2 } | ||
)); | ||
|
||
materialBuffer.set('Materials.diffuseNormalRoughnessMetalnessMapIndex[0]', interleave( | ||
{ data: bufferData.diffuseMapIndex, channels: 1 }, | ||
{ data: bufferData.normalMapIndex, channels: 1 }, | ||
{ data: bufferData.roughnessMapIndex, channels: 1 }, | ||
{ data: bufferData.metalnessMapIndex, channels: 1 } | ||
)); | ||
|
||
materialBuffer.set('Materials.diffuseNormalMapSize[0]', interleave( | ||
{ data: bufferData.diffuseMapSize, channels: 2 }, | ||
{ data: bufferData.normalMapSize, channels: 2 } | ||
)); | ||
|
||
materialBuffer.set('Materials.pbrMapSize[0]', bufferData.pbrMapSize); | ||
|
||
materialBuffer.bind(0); | ||
} | ||
|
||
function interleave(...arrays) { | ||
let maxLength = 0; | ||
for (let i = 0; i < arrays.length; i++) { | ||
const a = arrays[i]; | ||
const l = a.data ? a.data.length / a.channels : 0; | ||
maxLength = Math.max(maxLength, l); | ||
} | ||
|
||
const interleaved = []; | ||
for (let i = 0; i < maxLength; i++) { | ||
for (let j = 0; j < arrays.length; j++) { | ||
const { data = [], channels } = arrays[j]; | ||
for (let c = 0; c < channels; c++) { | ||
interleaved.push(data[i * channels + c]); | ||
} | ||
} | ||
} | ||
|
||
return interleaved; | ||
} |
Oops, something went wrong.