diff --git a/InstanceBuffer.mjs b/InstanceBuffer.mjs index 232e0b9..220fe49 100644 --- a/InstanceBuffer.mjs +++ b/InstanceBuffer.mjs @@ -51,20 +51,11 @@ InstanceBuffer.prototype.init = function(instances, materials, images) { let {geometryBuffer} = this; // create copy and insert placeholder material - let placeHolderMaterial = { - color: [0, 0, 0], - metalness: 0.0, - roughness: 0.0, - specular: 0.0, - albedo: null, - normal: null, - emission: null, - metalRoughness: null - }; + let placeHolderMaterial = {}; materials = [placeHolderMaterial, ...materials]; // create material buffer - let materialBufferStride = 12; + let materialBufferStride = 20; let materialBufferTotalLength = materials.length * materialBufferStride; let materialBuffer = device.createBuffer({ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE, @@ -78,23 +69,32 @@ InstanceBuffer.prototype.init = function(instances, materials, images) { let materialBufferDataU32 = new Uint32Array(materialBufferDataBase); for (let ii = 0; ii < materials.length; ++ii) { let material = materials[ii]; - let {color} = material; + let {color, emission} = material; let {metalness, roughness, specular} = material; - let {albedo, normal, emission, metalRoughness} = material; - let {textureScaling, emissionIntensity} = material; + let {textureScaling} = material; + let {albedoMap, normalMap, emissionMap, metalRoughnessMap} = material; + let {emissionIntensity, metalnessIntensity, roughnessIntensity} = material; let offset = ii * materialBufferStride; - materialBufferDataF32[offset++] = Math.pow(color[0] / 255.0, 1.0 / 2.2); - materialBufferDataF32[offset++] = Math.pow(color[1] / 255.0, 1.0 / 2.2); - materialBufferDataF32[offset++] = Math.pow(color[2] / 255.0, 1.0 / 2.2); - materialBufferDataF32[offset++] = clamp(parseFloat(metalness), -0.999, 0.999); - materialBufferDataF32[offset++] = clamp(parseFloat(roughness), -0.999, 0.999); - materialBufferDataF32[offset++] = clamp(parseFloat(specular), -0.999, 0.999); - materialBufferDataF32[offset++] = textureScaling !== void 0 ? textureScaling : 1.0; - materialBufferDataF32[offset++] = emissionIntensity !== void 0 ? emissionIntensity : 1.0; - materialBufferDataU32[offset++] = albedo ? images.indexOf(albedo) + 1 : 0; - materialBufferDataU32[offset++] = normal ? images.indexOf(normal) + 1 : 0; - materialBufferDataU32[offset++] = emission ? images.indexOf(emission) + 1 : 0; - materialBufferDataU32[offset++] = metalRoughness ? images.indexOf(metalRoughness) + 1 : 0; + materialBufferDataF32[offset++] = color !== void 0 ? Math.pow(color[0] / 255.0, 1.0 / 2.2) : 0.0; + materialBufferDataF32[offset++] = color !== void 0 ? Math.pow(color[1] / 255.0, 1.0 / 2.2) : 0.0; + materialBufferDataF32[offset++] = color !== void 0 ? Math.pow(color[2] / 255.0, 1.0 / 2.2) : 0.0; + materialBufferDataF32[offset++] = 0.0; // alpha + materialBufferDataF32[offset++] = emission !== void 0 ? Math.pow(emission[0] / 255.0, 1.0 / 2.2) : 0.0; + materialBufferDataF32[offset++] = emission !== void 0 ? Math.pow(emission[1] / 255.0, 1.0 / 2.2) : 0.0; + materialBufferDataF32[offset++] = emission !== void 0 ? Math.pow(emission[2] / 255.0, 1.0 / 2.2) : 0.0; + materialBufferDataF32[offset++] = 0.0; // alpha + materialBufferDataF32[offset++] = clamp(parseFloat(metalness), 0.001, 0.999); + materialBufferDataF32[offset++] = clamp(parseFloat(roughness), 0.001, 0.999); + materialBufferDataF32[offset++] = clamp(parseFloat(specular), 0.001, 0.999); + materialBufferDataF32[offset++] = textureScaling !== void 0 ? parseFloat(textureScaling) : 1.0; + materialBufferDataU32[offset++] = albedoMap ? images.indexOf(albedoMap) + 1 : 0; + materialBufferDataU32[offset++] = normalMap ? images.indexOf(normalMap) + 1 : 0; + materialBufferDataU32[offset++] = emissionMap ? images.indexOf(emissionMap) + 1 : 0; + materialBufferDataU32[offset++] = metalRoughnessMap ? images.indexOf(metalRoughnessMap) + 1 : 0; + materialBufferDataF32[offset++] = emissionIntensity !== void 0 ? parseFloat(emissionIntensity) : 1.0; + materialBufferDataF32[offset++] = metalnessIntensity !== void 0 ? parseFloat(metalnessIntensity) : 1.0; + materialBufferDataF32[offset++] = roughnessIntensity !== void 0 ? parseFloat(roughnessIntensity) : 1.0; + materialBufferDataF32[offset++] = 0.0; // padding }; materialBuffer.setSubData(0, materialBufferDataU32); @@ -153,7 +153,7 @@ InstanceBuffer.prototype.init = function(instances, materials, images) { let container = device.createRayTracingAccelerationContainer({ level: "top", - flags: GPURayTracingAccelerationContainerFlag.PREFER_FAST_TRACE, + flags: GPURayTracingAccelerationContainerFlag.ALLOW_UPDATE | GPURayTracingAccelerationContainerFlag.PREFER_FAST_TRACE, instances: containerInstances }); containers.push({ diff --git a/RayPickingPass.mjs b/RayPickingPass.mjs index 7fa24e0..b79818a 100644 --- a/RayPickingPass.mjs +++ b/RayPickingPass.mjs @@ -66,12 +66,12 @@ RayPickingPass.prototype.getPickingResult = async function() { queue.submit([ commandEncoder.finish() ]); let result = await pickingReadBackBuffer.mapReadAsync(); - let data = new Float32Array(new Float32Array(result)); + let resultF32 = new Float32Array(result); - let x = data[4]; - let y = data[5]; - let z = data[6]; - let instanceId = data[7]; + let x = resultF32[4]; + let y = resultF32[5]; + let z = resultF32[6]; + let instanceId = resultF32[7]; pickingReadBackBuffer.unmap(); diff --git a/RayTracingPass.mjs b/RayTracingPass.mjs index ccd84ed..7b651a5 100644 --- a/RayTracingPass.mjs +++ b/RayTracingPass.mjs @@ -80,11 +80,11 @@ RayTracingPass.prototype.init = function(instances, materials, images, lights, g let accumulationBuffer = device.createBuffer({ usage: GPUBufferUsage.STORAGE, size: accumulationBufferByteLength }); accumulationBuffer.byteLength = accumulationBufferByteLength; - let rayGenShaderModule = device.createShaderModule({ code: loadShaderFile(`shaders/ray-generation.rgen`) }); - let rayCHitModule = device.createShaderModule({ code: loadShaderFile(`shaders/ray-closest-hit.rchit`) }); - let rayMissShaderModule = device.createShaderModule({ code: loadShaderFile(`shaders/ray-miss.rmiss`) }); - let rayShadowCHitShaderModule = device.createShaderModule({ code: loadShaderFile(`shaders/shadow-ray-closest-hit.rchit`) }); - let rayShadowMissShaderModule = device.createShaderModule({ code: loadShaderFile(`shaders/shadow-ray-miss.rmiss`) }); + let rayGenShaderModule = device.createShaderModule({ code: loadShaderFile(`shaders/shading/ray-generation.rgen`) }); + let rayCHitModule = device.createShaderModule({ code: loadShaderFile(`shaders/shading/ray-closest-hit.rchit`) }); + let rayMissShaderModule = device.createShaderModule({ code: loadShaderFile(`shaders/shading/ray-miss.rmiss`) }); + let rayShadowCHitShaderModule = device.createShaderModule({ code: loadShaderFile(`shaders/shading/shadow-ray-closest-hit.rchit`) }); + let rayShadowMissShaderModule = device.createShaderModule({ code: loadShaderFile(`shaders/shading/shadow-ray-miss.rmiss`) }); let shaderBindingTable = device.createRayTracingShaderBindingTable({ stages: [ @@ -110,11 +110,11 @@ RayTracingPass.prototype.init = function(instances, materials, images, lights, g { binding: 2, type: "storage-buffer", visibility: GPUShaderStage.RAY_GENERATION }, { binding: 3, type: "uniform-buffer", visibility: GPUShaderStage.RAY_GENERATION | GPUShaderStage.RAY_CLOSEST_HIT }, { binding: 4, type: "uniform-buffer", visibility: GPUShaderStage.RAY_GENERATION | GPUShaderStage.RAY_CLOSEST_HIT }, - { binding: 5, type: "storage-buffer", visibility: GPUShaderStage.RAY_GENERATION | GPUShaderStage.RAY_CLOSEST_HIT }, - { binding: 6, type: "storage-buffer", visibility: GPUShaderStage.RAY_GENERATION | GPUShaderStage.RAY_CLOSEST_HIT }, - { binding: 7, type: "storage-buffer", visibility: GPUShaderStage.RAY_GENERATION | GPUShaderStage.RAY_CLOSEST_HIT }, - { binding: 8, type: "storage-buffer", visibility: GPUShaderStage.RAY_GENERATION | GPUShaderStage.RAY_CLOSEST_HIT }, - { binding: 9, type: "storage-buffer", visibility: GPUShaderStage.RAY_GENERATION | GPUShaderStage.RAY_CLOSEST_HIT }, + { binding: 5, type: "storage-buffer", visibility: GPUShaderStage.RAY_CLOSEST_HIT }, + { binding: 6, type: "storage-buffer", visibility: GPUShaderStage.RAY_CLOSEST_HIT }, + { binding: 7, type: "storage-buffer", visibility: GPUShaderStage.RAY_CLOSEST_HIT }, + { binding: 8, type: "storage-buffer", visibility: GPUShaderStage.RAY_CLOSEST_HIT }, + { binding: 9, type: "storage-buffer", visibility: GPUShaderStage.RAY_CLOSEST_HIT }, { binding: 10, type: "sampler", visibility: GPUShaderStage.RAY_CLOSEST_HIT }, { binding: 11, type: "sampled-texture", visibility: GPUShaderStage.RAY_CLOSEST_HIT, textureDimension: "2d-array" }, ] @@ -144,7 +144,7 @@ RayTracingPass.prototype.init = function(instances, materials, images, lights, g }), rayTracingState: { shaderBindingTable, - maxRecursionDepth: 1 + maxRecursionDepth: 2 } }); diff --git a/index.mjs b/index.mjs index 96f2b05..278f4ee 100644 --- a/index.mjs +++ b/index.mjs @@ -88,28 +88,32 @@ Object.assign(global, glMatrix); metalness: 0.001, roughness: 0.068, specular: 0.0117, - albedo: images[6], - normal: images[7], - metalRoughness: images[8], + albedoMap: images[6], + normalMap: images[7], + metalRoughnessMap: images[8], textureScaling: 5.5, }, { color: [0, 0, 0], - metalness: 0.5, - roughness: -0.1634, + metalness: 0.0, + roughness: 0.0, specular: 0.95, - albedo: images[0], - normal: images[1], - metalRoughness: images[2], + albedoMap: images[0], + normalMap: images[1], + metalRoughnessMap: images[2], + metalnessIntensity: 1.0, + roughnessIntensity: 0.1125, }, { color: [0, 0, 0], - metalness: 0.5, - roughness: -0.1634, + metalness: 0.0, + roughness: 0.0, specular: 0.95, - albedo: images[3], - normal: images[4], - metalRoughness: images[5], + albedoMap: images[3], + normalMap: images[4], + metalRoughnessMap: images[5], + metalnessIntensity: 1.0, + roughnessIntensity: 0.1125, }, { color: [14600, 14600, 14600], @@ -126,7 +130,7 @@ Object.assign(global, glMatrix); geometry: bottomContainers[2], transform: { translation: { x: -32, y: 0, z: 128 }, - rotation: { x: 0, y: -80, z: 0 }, + rotation: { x: 0, y: 100, z: 0 }, scale: { x: 512, y: 512, z: 512 } } }, @@ -136,7 +140,7 @@ Object.assign(global, glMatrix); geometry: bottomContainers[3], transform: { translation: { x: -32, y: 0, z: 128 }, - rotation: { x: 0, y: -80, z: 0 }, + rotation: { x: 0, y: 100, z: 0 }, scale: { x: 512, y: 512, z: 512 } } }, @@ -243,6 +247,11 @@ Object.assign(global, glMatrix); let rpPass = new RayPickingPass({ device, topLevelContainer }); + images = null; + instances = null; + materials = null; + geometries = null; + let blitBindGroupLayout = device.createBindGroupLayout({ bindings: [ { binding: 0, type: "storage-buffer", visibility: GPUShaderStage.FRAGMENT }, @@ -264,11 +273,11 @@ Object.assign(global, glMatrix); }), sampleCount: 1, vertexStage: { - module: device.createShaderModule({ code: loadShaderFile(`shaders/screen.vert`) }), + module: device.createShaderModule({ code: loadShaderFile(`shaders/blit/screen.vert`) }), entryPoint: "main" }, fragmentStage: { - module: device.createShaderModule({ code: loadShaderFile(`shaders/screen.frag`) }), + module: device.createShaderModule({ code: loadShaderFile(`shaders/blit/screen.frag`) }), entryPoint: "main" }, primitiveTopology: "triangle-list", @@ -287,6 +296,8 @@ Object.assign(global, glMatrix); }] }); + let pickedInstanceId = 0; + let isLeftMousePressed = false; window.onmousedown = e => { isLeftMousePressed = e.button === 0; @@ -295,31 +306,37 @@ Object.assign(global, glMatrix); rpPass.setMousePickingPosition(e.x, e.y); queue.submit([ rpPass.getCommandBuffer() ]); rpPass.getPickingResult().then(({ x, y, z, instanceId } = _) => { - console.log("Picked:", instanceId); + pickedInstanceId = instanceId; + console.log("Picked Instance:", pickedInstanceId - 1); }); } }; window.onmouseup = e => { isLeftMousePressed = false; }; + let baseTransform = { + translation: { x: -32, y: 0, z: 128 }, + rotation: { x: 0, y: -80, z: 0 }, + scale: { x: 512, y: 512, z: 512 } + }; window.onmousemove = e => { if (!isLeftMousePressed) return; camera.deltaMovement.x = e.movementX * 0.25; camera.deltaMovement.y = e.movementY * 0.25; }; - let rofl = false; + let resetAccumulation = false; window.onmousewheel = e => { // aperture if (isKeyPressed("Ŕ")) { // shift key camera.settings.aperture += e.deltaY * 0.01; - rofl = true; + resetAccumulation = true; console.log(`Camera: Aperture: '${camera.settings.aperture}'`); } // focus distance else { camera.settings.focusDistance += e.deltaY * 0.125; camera.settings.focusDistance = Math.max(0.1, camera.settings.focusDistance); - rofl = true; + resetAccumulation = true; console.log(`Camera: Focus-Distance: '${camera.settings.focusDistance}'`); } }; @@ -367,9 +384,9 @@ Object.assign(global, glMatrix); if (camera.hasMoved) camera.resetAccumulation(); else camera.increaseAccumulation(); - if (rofl) { + if (resetAccumulation) { camera.resetAccumulation(); - rofl = false; + resetAccumulation = false; } let backBufferView = swapChain.getCurrentTextureView(); diff --git a/objects/Geometry.mjs b/objects/Geometry.mjs new file mode 100644 index 0000000..07bca29 --- /dev/null +++ b/objects/Geometry.mjs @@ -0,0 +1,5 @@ +export default class Geometry { + constructor({ } = _) { + + } +}; diff --git a/objects/GeometryInstance.mjs b/objects/GeometryInstance.mjs new file mode 100644 index 0000000..1130fec --- /dev/null +++ b/objects/GeometryInstance.mjs @@ -0,0 +1,5 @@ +export default class GeometryInstance { + constructor({ } = _) { + + } +}; diff --git a/objects/Material.mjs b/objects/Material.mjs new file mode 100644 index 0000000..28b0565 --- /dev/null +++ b/objects/Material.mjs @@ -0,0 +1,5 @@ +export default class Material { + constructor({ } = _) { + + } +}; diff --git a/objects/Texture.mjs b/objects/Texture.mjs new file mode 100644 index 0000000..193937e --- /dev/null +++ b/objects/Texture.mjs @@ -0,0 +1,5 @@ +export default class Texture { + constructor({ } = _) { + + } +}; diff --git a/package-lock.json b/package-lock.json index c2d5333..c1be4d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,49 +2,34 @@ "requires": true, "lockfileVersion": 1, "dependencies": { - "babel-plugin-rewire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-rewire/-/babel-plugin-rewire-1.1.0.tgz", - "integrity": "sha1-prlm2djAbAPZXc2i7sTiUhUZVJs=" + "@canvas/image-data": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@canvas/image-data/-/image-data-1.0.0.tgz", + "integrity": "sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==" + }, + "@cwasm/jpeg-turbo": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@cwasm/jpeg-turbo/-/jpeg-turbo-0.1.2.tgz", + "integrity": "sha512-LXLrmchl/eXfoFB14Gk1Jo139igd21sLniVUD7GC4KtdFCPL2SDPDfqyftXkwmSDQ8Te+JBIyURX7QuIxdYm/w==", + "requires": { + "@canvas/image-data": "^1.0.0" + } + }, + "@cwasm/lodepng": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@cwasm/lodepng/-/lodepng-0.1.1.tgz", + "integrity": "sha512-i2aa5ILUfPsPrWhJdJTjIWZTSVWwoDCwBBnjErDhxBdcZNQywkcAc+xtHuLibQ++chS5bLQNvBNaeP0sYS5n5A==" }, "gl-matrix": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.2.1.tgz", "integrity": "sha512-YYVO8jUSf6+SakL4AJmx9Jc7zAZhkJQ+WhdtX3VQe5PJdCOX6/ybY4x1vk+h94ePnjRn6uml68+QxTAJneUpvA==" }, - "sbt-image": { - "version": "file:../nvk-optix-denoiser", - "dependencies": { - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=" - }, - "node-addon-api": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.1.tgz", - "integrity": "sha512-2+DuKodWvwRTrCfKOeR24KIc5unKjOh8mz17NCzVnHWfjAdDqbfbjqh7gUT+BkXBRQM52+xCHciKWonJ3CbJMQ==" - } - } - }, - "simplex-noise": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/simplex-noise/-/simplex-noise-2.4.0.tgz", - "integrity": "sha512-OjyDWm/QZjVbMrPxDVi9b2as+SeNn9EBXlrWVRlFW+TSyWMSXouDryXkQN0vf5YP+QZKobrmkvx1eQYPLtuqfw==" - }, "tolw": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/tolw/-/tolw-0.1.8.tgz", "integrity": "sha512-olxkOErscYps+5LaBCEOpYbR9MuK3NiUNz2eojPVu6CCxOmZXvf07O405au/Cd2HdevnRCPS6mWo8tlIbTxbVQ==" }, - "vox-parser": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/vox-parser/-/vox-parser-0.2.2.tgz", - "integrity": "sha512-PNWoYe/shI2IBtNAPSHELH1it1oUA781KvXcCGYkuQo6bbaqfqzzjIIXR61ZVc+p4gkh0t6MfkMmZTFfGtuY0A==", - "requires": { - "babel-plugin-rewire": "1.1.0" - } - }, "webgpu": { "version": "file:../webgpu", "dependencies": { diff --git a/package.json b/package.json index e47ff6a..f8bf471 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,10 @@ "start": "node index.mjs" }, "dependencies": { - "sbt-image": "file:../nvk-optix-denoiser", + "@cwasm/jpeg-turbo": "0.1.2", + "@cwasm/lodepng": "0.1.1", "gl-matrix": "^3.1.0", - "simplex-noise": "^2.4.0", "tolw": "^0.1.8", - "vox-parser": "^0.2.2", "webgpu": "file:../webgpu" } } diff --git a/shaders/screen.frag b/shaders/blit/screen.frag similarity index 100% rename from shaders/screen.frag rename to shaders/blit/screen.frag diff --git a/shaders/screen.vert b/shaders/blit/screen.vert similarity index 100% rename from shaders/screen.vert rename to shaders/blit/screen.vert diff --git a/shaders/picking/ray-closest-hit.rchit b/shaders/picking/ray-closest-hit.rchit index d36b0df..4912ea4 100644 --- a/shaders/picking/ray-closest-hit.rchit +++ b/shaders/picking/ray-closest-hit.rchit @@ -14,5 +14,5 @@ hitAttributeNV vec4 Hit; void main() { Ray.position.xyz = gl_WorldRayOriginNV + gl_WorldRayDirectionNV * gl_RayTmaxNV; - Ray.instanceId = gl_InstanceCustomIndexNV; + Ray.instanceId = gl_InstanceCustomIndexNV + 1; } diff --git a/shaders/picking/ray-generation.rgen b/shaders/picking/ray-generation.rgen index a664a11..8cddd86 100644 --- a/shaders/picking/ray-generation.rgen +++ b/shaders/picking/ray-generation.rgen @@ -43,8 +43,9 @@ layout (binding = 3) uniform SettingsBuffer { } Settings; void main() { - const vec2 pixel = vec2(Picking.inputData.x, 768 - Picking.inputData.y); - const vec2 uv = (pixel / vec2(1280, 768)) * 2.0 - 1.0; + const vec2 res = vec2(Settings.screenWidth, Settings.screenHeight); + const vec2 pixel = vec2(Picking.inputData.x, res.y - Picking.inputData.y); + const vec2 uv = (pixel / res) * 2.0 - 1.0; vec4 origin = Camera.viewInverse * vec4(0, 0, 0, 1); vec4 target = Camera.projectionInverse * (vec4(uv.x, uv.y, 1, 1)); diff --git a/shaders/disney.glsl b/shaders/shading/disney.glsl similarity index 100% rename from shaders/disney.glsl rename to shaders/shading/disney.glsl diff --git a/shaders/ray-closest-hit.rchit b/shaders/shading/ray-closest-hit.rchit similarity index 97% rename from shaders/ray-closest-hit.rchit rename to shaders/shading/ray-closest-hit.rchit index 4ee3373..8f5efd8 100644 --- a/shaders/ray-closest-hit.rchit +++ b/shaders/shading/ray-closest-hit.rchit @@ -90,7 +90,7 @@ LightSource PickRandomLightSource(inout uint seed, in vec3 surfacePos, out vec3 const float triangleArea = 0.5 * length(cross(p1 - p0, p2 - p0)); const vec3 lightSurfacePos = pw; - const vec3 lightEmission = Materials[instance.materialIndex].color; + const vec3 lightEmission = Materials[instance.materialIndex].color.rgb; const vec3 lightNormal = normalize(lightSurfacePos - surfacePos); const vec3 lightPos = lightSurfacePos - surfacePos; @@ -186,7 +186,7 @@ void main() { const vec3 tex3 = texture(sampler2DArray(TextureArray, TextureSampler), vec3(uv, material.emissionIndex)).rgb; // material color - vec3 color = tex0 + material.color; + vec3 color = tex0 + material.color.rgb; // material normal const vec3 normal = normalize( material.normalIndex > 0 ? @@ -198,10 +198,6 @@ void main() { // material emission const vec3 emission = pow(tex3, vec3(GAMMA)) * material.emissionIntensity; - const vec3 W = vec3(0.2125, 0.7154, 0.0721); - vec3 intensity = vec3(dot(color, W)); - color = mix(intensity, color, 1.25); - uint seed = Ray.seed; float t = gl_HitTNV; @@ -211,9 +207,9 @@ void main() { radiance += emission * throughput; shading.base_color = color; - shading.metallic = clamp(metalRoughness.r + material.metalness, 0.001, 0.999); + shading.metallic = clamp(metalRoughness.r + material.metalness, 0.001, 0.999) * material.metalnessIntensity; shading.specular = material.specular; - shading.roughness = clamp(metalRoughness.g + material.roughness, 0.001, 0.999); + shading.roughness = clamp(metalRoughness.g + material.roughness, 0.001, 0.999) * material.roughnessIntensity; { const vec3 cd_lin = shading.base_color; const float cd_lum = dot(cd_lin, vec3(0.3, 0.6, 0.1)); diff --git a/shaders/ray-generation.rgen b/shaders/shading/ray-generation.rgen similarity index 87% rename from shaders/ray-generation.rgen rename to shaders/shading/ray-generation.rgen index c064c20..e43de6c 100644 --- a/shaders/ray-generation.rgen +++ b/shaders/shading/ray-generation.rgen @@ -43,26 +43,6 @@ layout (binding = 4) uniform SettingsBuffer { uint pad_2; } Settings; -layout (binding = 5, std430) readonly buffer AttributeBuffer { - Vertex Vertices[]; -}; - -layout (binding = 6, std430) readonly buffer FaceBuffer { - uint Faces[]; -}; - -layout (binding = 7, std140, row_major) readonly buffer InstanceBuffer { - Instance Instances[]; -}; - -layout (binding = 8, std430) readonly buffer MaterialBuffer { - Material Materials[]; -}; - -layout (binding = 9, std430) readonly buffer LightBuffer { - Light Lights[]; -}; - void main() { const ivec2 ipos = ivec2(gl_LaunchIDNV.xy); const ivec2 resolution = ivec2(gl_LaunchSizeNV.xy); diff --git a/shaders/ray-miss.rmiss b/shaders/shading/ray-miss.rmiss similarity index 100% rename from shaders/ray-miss.rmiss rename to shaders/shading/ray-miss.rmiss diff --git a/shaders/shadow-ray-closest-hit.rchit b/shaders/shading/shadow-ray-closest-hit.rchit similarity index 100% rename from shaders/shadow-ray-closest-hit.rchit rename to shaders/shading/shadow-ray-closest-hit.rchit diff --git a/shaders/shadow-ray-miss.rmiss b/shaders/shading/shadow-ray-miss.rmiss similarity index 100% rename from shaders/shadow-ray-miss.rmiss rename to shaders/shading/shadow-ray-miss.rmiss diff --git a/shaders/structs.glsl b/shaders/shading/structs.glsl similarity index 91% rename from shaders/structs.glsl rename to shaders/shading/structs.glsl index 91c6d13..933f549 100644 --- a/shaders/structs.glsl +++ b/shaders/shading/structs.glsl @@ -44,16 +44,20 @@ struct Offset { }; struct Material { - vec3 color; + vec4 color; + vec4 emission; float metalness; float roughness; float specular; float textureScaling; - float emissionIntensity; uint albedoIndex; uint normalIndex; uint emissionIndex; uint metalRoughnessIndex; + float emissionIntensity; + float metalnessIntensity; + float roughnessIntensity; + float pad_0; }; struct Light { diff --git a/shaders/utils.glsl b/shaders/shading/utils.glsl similarity index 100% rename from shaders/utils.glsl rename to shaders/shading/utils.glsl diff --git a/utils.mjs b/utils.mjs index 99553e8..29572e2 100644 --- a/utils.mjs +++ b/utils.mjs @@ -1,6 +1,7 @@ import fs from "fs"; import path from "path"; -import sbtImage from "sbt-image"; +import lodepng from "@cwasm/lodepng"; +import jpegturbo from "@cwasm/jpeg-turbo"; export function fixateToZero(value, range) { if (value > 0 && value <= range) return 0.0; @@ -24,12 +25,39 @@ export function readBinaryFile(path) { export function readImageFile(path) { let buf = fs.readFileSync(path); - let {width, height, data} = sbtImage.loadImage(buf); - return { - width, - height, - data: new Uint8ClampedArray(data) - }; + if (isPNGFile(buf)) return readPNGFile(buf); + if (isJPEGFile(buf)) return readJPEGFile(buf); + throw new Error(`Cannot process image file '${path}'`); +}; + +export function readPNGFile(buf) { + return lodepng.decode(buf); +}; + +export function readJPEGFile(buf) { + return jpegturbo.decode(buf); +}; + +export function isPNGFile(buffer) { + let viewU8 = new Uint8Array(buffer); + let offset = 0x0; + return ( + viewU8[offset++] === 0x89 && + viewU8[offset++] === 0x50 && + viewU8[offset++] === 0x4E && + viewU8[offset++] === 0x47 + ); +}; + +export function isJPEGFile(buffer) { + let viewU8 = new Uint8Array(buffer); + let offset = 0x0; + return ( + viewU8[offset++] === 0xFF && + viewU8[offset++] === 0xD8 && + viewU8[offset++] === 0xFF && + viewU8[offset++] === 0xE0 + ); }; function findIncludedFile(filePath, includes) {