├── src ├── pass │ ├── shaders │ │ ├── definition.glsl │ │ ├── common_data.glsl │ │ ├── jitter.glsl │ │ ├── sample_utils.glsl │ │ ├── utils.glsl │ │ ├── pbr_material.glsl │ │ └── camera.glsl │ ├── ray_tracing │ │ ├── shaders │ │ │ ├── define.glsl │ │ │ ├── reduce_noise_data.glsl │ │ │ ├── disney_utils.glsl │ │ │ ├── ray-miss-shadow.rmiss │ │ │ ├── raycommon.glsl │ │ │ ├── ray-miss.rmiss │ │ │ ├── light.glsl │ │ │ ├── shading_data.glsl │ │ │ ├── indirect_ray.glsl │ │ │ ├── shadow_ray.glsl │ │ │ ├── random.glsl │ │ │ ├── indirect_utils.glsl │ │ │ ├── pbr_compute.glsl │ │ │ ├── ray-closest-hit-indirect-gi.rchit │ │ │ ├── ggx_direct.glsl │ │ │ ├── disney.glsl │ │ │ ├── ggx_indirect.glsl │ │ │ ├── get_hit_shading_data.glsl │ │ │ └── ray-generation.rgen │ │ └── RayTracingPass.re │ ├── bmfr │ │ ├── regression │ │ │ ├── shaders │ │ │ │ ├── barrier.glsl │ │ │ │ └── regression.comp │ │ │ └── BMFRRegressionPass.re │ │ ├── postprocess │ │ │ ├── shaders │ │ │ │ ├── postprocess.vert │ │ │ │ └── postprocess.frag │ │ │ └── BMFRPostprocessPass.re │ │ ├── preprocess │ │ │ ├── shaders │ │ │ │ ├── preprocess.vert │ │ │ │ └── preprocess.frag │ │ │ └── BMFRPreprocessPass.re │ │ └── shaders │ │ │ └── utils.glsl │ ├── taa │ │ ├── shaders │ │ │ ├── taa_definition.glsl │ │ │ ├── taa.vert │ │ │ ├── taa_firstFrame.frag │ │ │ ├── taa_utils.glsl │ │ │ └── taa_otherFrame.frag │ │ ├── TAAJitter.re │ │ └── TAAPass.re │ ├── accumulation │ │ ├── shaders │ │ │ ├── accumulation.vert │ │ │ └── accumulation.frag │ │ └── AccumulationPass.re │ ├── utils │ │ └── GBufferUtils.re │ └── gbuffer │ │ ├── shaders │ │ ├── gbuffer.frag │ │ └── gbuffer.vert │ │ └── GBufferPass.re ├── RTXMain.re └── RTXScene.re ├── .gitignore ├── bsconfig.json ├── package.json └── yarn.lock /src/pass/shaders/definition.glsl: -------------------------------------------------------------------------------- 1 | #define NEAR_Z 0.1 2 | #define FAR_Z 4096.0 3 | -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/define.glsl: -------------------------------------------------------------------------------- 1 | 2 | #define M_PI 3.1415926535897932384626433832795 -------------------------------------------------------------------------------- /src/pass/bmfr/regression/shaders/barrier.glsl: -------------------------------------------------------------------------------- 1 | void groupMemoryBarrierWithGroupSync() { 2 | groupMemoryBarrier(); 3 | barrier(); 4 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/reduce_noise_data.glsl: -------------------------------------------------------------------------------- 1 | 2 | uint getIndirectLightSpecularSampleCount(vec4 compressedData) { 3 | return uint(compressedData.x); 4 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/disney_utils.glsl: -------------------------------------------------------------------------------- 1 | 2 | vec3 computeV(vec3 cameraPosition, vec3 worldPosition){ 3 | return normalize(cameraPosition - worldPosition); 4 | } -------------------------------------------------------------------------------- /src/pass/shaders/common_data.glsl: -------------------------------------------------------------------------------- 1 | uint getFrame(vec4 compressedData) { return uint(compressedData.x); } 2 | 3 | uint getLightCount(vec4 compressedData) { return uint(compressedData.y); } -------------------------------------------------------------------------------- /src/pass/shaders/jitter.glsl: -------------------------------------------------------------------------------- 1 | vec2 getJitterdUV(vec2 uv, vec2 jitter) { return uv; } 2 | 3 | vec2 getUnJitterdUV(vec2 uv, vec2 jitter) { 4 | return uv - vec2(jitter.x, jitter.y); 5 | } -------------------------------------------------------------------------------- /src/pass/taa/shaders/taa_definition.glsl: -------------------------------------------------------------------------------- 1 | #define USE_CLOSEST_VELOCITY 2 | 3 | #define USE_TONEMAP 4 | 5 | #define USE_MIXED_TONE_MAP 6 | #define MIXED_TONE_MAP_LINEAR_UPPER_BOUND 0.5f -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/ray-miss-shadow.rmiss: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : enable 3 | #pragma shader_stage(miss) 4 | 5 | layout(location = 1) rayPayloadInEXT bool isShadowed; 6 | 7 | void main() { isShadowed = false; } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | mine/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | .bsb.lock 7 | .idea/ 8 | .sass-cache/* 9 | .vscode 10 | 11 | .merlin 12 | 13 | .DS_Store 14 | 15 | lib/ 16 | 17 | 18 | 19 | src/**/.css 20 | src/**/.css.map 21 | 22 | 23 | node_modules/ -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/raycommon.glsl: -------------------------------------------------------------------------------- 1 | 2 | struct hitPayload { 3 | vec3 hitValue; 4 | uint seed; 5 | // 0:both, 1:diffuse, 2:specular 6 | uint evalDisneyType; 7 | vec3 V; 8 | 9 | ShadingData shading; 10 | 11 | vec3 worldNormal; 12 | vec3 worldPosition; 13 | }; -------------------------------------------------------------------------------- /src/pass/bmfr/postprocess/shaders/postprocess.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #pragma shader_stage(vertex) 3 | 4 | layout(location = 0) out vec2 uv; 5 | 6 | void main() { 7 | uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); 8 | gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0); 9 | } 10 | -------------------------------------------------------------------------------- /src/pass/bmfr/preprocess/shaders/preprocess.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #pragma shader_stage(vertex) 3 | 4 | layout(location = 0) out vec2 uv; 5 | 6 | void main() { 7 | uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); 8 | gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0); 9 | } 10 | -------------------------------------------------------------------------------- /src/pass/taa/shaders/taa.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #pragma shader_stage(vertex) 3 | 4 | layout(location = 0) out vec2 uv; 5 | 6 | void main() { 7 | uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); 8 | gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0); 9 | // uv = vec2(uv.x, 1.0 - uv.y); 10 | } 11 | -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/ray-miss.rmiss: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : enable 3 | #pragma shader_stage(miss) 4 | 5 | #include "shading_data.glsl" 6 | 7 | #include "raycommon.glsl" 8 | 9 | layout(location = 0) rayPayloadInEXT hitPayload prd; 10 | 11 | void main() { prd.hitValue = vec3(0.15); } 12 | -------------------------------------------------------------------------------- /src/pass/accumulation/shaders/accumulation.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #pragma shader_stage(vertex) 3 | 4 | layout(location = 0) out vec2 uv; 5 | 6 | void main() { 7 | uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); 8 | gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0); 9 | // uv = vec2(uv.x, 1.0 - uv.y); 10 | } 11 | -------------------------------------------------------------------------------- /src/pass/shaders/sample_utils.glsl: -------------------------------------------------------------------------------- 1 | 2 | vec3 buildJitteredV(uint seed, vec3 cameraPosition, vec3 worldPosition) { 3 | vec3 jitteredCameraPosition = 4 | vec3(cameraPosition.x + rnd(seed), cameraPosition.y + rnd(seed), 5 | cameraPosition.z + rnd(seed)); 6 | 7 | return computeV(jitteredCameraPosition, worldPosition); 8 | } -------------------------------------------------------------------------------- /src/pass/utils/GBufferUtils.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | let createLinearSampler = device => 6 | device 7 | |> Device.createSampler( 8 | Sampler.descriptor( 9 | ~magFilter="linear", 10 | ~minFilter="linear", 11 | ~addressModeU="repeat", 12 | ~addressModeV="repeat", 13 | ~addressModeW="repeat", 14 | ), 15 | ); 16 | -------------------------------------------------------------------------------- /src/pass/shaders/utils.glsl: -------------------------------------------------------------------------------- 1 | 2 | float saturateFloat(float v) { 3 | if (v < 0.0) { 4 | return 0.0; 5 | } 6 | 7 | if (v > 1.0) { 8 | return 1.0; 9 | } 10 | 11 | return v; 12 | } 13 | 14 | vec2 saturateVec2(vec2 v) { 15 | return vec2(saturateFloat(v.x), saturateFloat(v.y)); 16 | } 17 | 18 | uint getPixelIndex(vec2 uv, vec2 resolution) { 19 | const ivec2 bufferCoord = ivec2(floor(uv * resolution)); 20 | 21 | return bufferCoord.y * uint(resolution.x) + bufferCoord.x; 22 | } 23 | -------------------------------------------------------------------------------- /src/pass/shaders/pbr_material.glsl: -------------------------------------------------------------------------------- 1 | layout(std140, set = 1, binding = 0) uniform PBRMaterial { 2 | vec4 diffuse; 3 | // include metalness, roughness, specular 4 | vec4 compressedData; 5 | } 6 | uPBRMaterial; 7 | 8 | vec3 getMaterialDiffuse() { return vec3(uPBRMaterial.diffuse); } 9 | 10 | float getMaterialMetalness() { return uPBRMaterial.compressedData.x; } 11 | 12 | float getMaterialRoughness() { return uPBRMaterial.compressedData.y; } 13 | 14 | float getMaterialSpecular() { return uPBRMaterial.compressedData.z; } -------------------------------------------------------------------------------- /src/pass/shaders/camera.glsl: -------------------------------------------------------------------------------- 1 | layout(std140, set = 2, binding = 0) uniform Camera { 2 | vec4 cameraPosition; 3 | mat4 viewMatrix; 4 | mat4 projectionMatrix; 5 | mat4 lastViewProjectionMatrix; 6 | } 7 | uCamera; 8 | 9 | vec3 getViewDir(vec3 worldPosition) { 10 | return normalize(worldPosition - vec3(uCamera.cameraPosition)); 11 | } 12 | 13 | mat4 getViewMatrix() { return uCamera.viewMatrix; } 14 | 15 | mat4 getProjectionMatrix() { return uCamera.projectionMatrix; } 16 | 17 | mat4 getLastViewProjectionMatrix() { return uCamera.lastViewProjectionMatrix; } -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgpu-rtx", 3 | "sources": [ 4 | { 5 | "dir": "src", 6 | "subdirs": true 7 | } 8 | ], 9 | "bs-dev-dependencies": [], 10 | "refmt": 3, 11 | "bs-dependencies": [ 12 | "wonder-bs-most", 13 | "raytracing-framework" 14 | ], 15 | "package-specs": [ 16 | "commonjs" 17 | ], 18 | "warnings": { 19 | "number": "-0-1-2-3-4-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-62-101-104-K", 20 | "error": "+5+6" 21 | } 22 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/light.glsl: -------------------------------------------------------------------------------- 1 | 2 | struct DirectionLight { 3 | // include intentity 4 | vec4 compressedData; 5 | vec4 position; 6 | }; 7 | 8 | layout(std140, set = 3, binding = 0) buffer DirectionLights { 9 | DirectionLight l[]; 10 | } 11 | lights; 12 | 13 | void getLightData(in uint lightIndex, out float lightIntensity, 14 | out float lightDistance, out vec3 lightDir) { 15 | DirectionLight data = lights.l[lightIndex]; 16 | 17 | lightIntensity = data.compressedData.x; 18 | lightDistance = 100000.0; 19 | lightDir = normalize(vec3(data.position) - vec3(0.0)); 20 | } 21 | 22 | bool isLightVisibleFromTheSurface(vec3 worldNormal, vec3 lightDir) { 23 | return dot(worldNormal, lightDir) > 0; 24 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/shading_data.glsl: -------------------------------------------------------------------------------- 1 | 2 | struct ShadingData { 3 | vec3 baseColor; 4 | float metallic; 5 | float specular; 6 | float roughness; 7 | }; 8 | 9 | ShadingData buildShadingData(vec3 materialDiffuse, float materialMetalness, 10 | float materialRoughness, float materialSpecular) { 11 | // TODO should pass from pbr material 12 | float metalnessIntensity = 1.0; 13 | float roughnessIntensity = 0.1125; 14 | 15 | ShadingData shading; 16 | 17 | shading.baseColor = materialDiffuse; 18 | shading.metallic = materialMetalness * metalnessIntensity; 19 | shading.specular = materialSpecular; 20 | shading.roughness = materialRoughness * roughnessIntensity; 21 | 22 | return shading; 23 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgpu-rtx", 3 | "version": "0.0.1", 4 | "description": "", 5 | "homepage": "https://github.com/yyc-git/WebGPU-RTX", 6 | "license": "MIT", 7 | "main": "", 8 | "scripts": { 9 | "start": "http-server -c-1", 10 | "watch": "bsb -clean-world -make-world -w", 11 | "test:watch": "jest --watch --config jest.json", 12 | "build": "bsb -clean-world -make-world", 13 | "runTest": "node lib/js/src/RTXMain.js" 14 | }, 15 | "devDependencies": { 16 | "http-server": "^0.12.0" 17 | }, 18 | "dependencies": { 19 | "raytracing-framework": "^0.0.3", 20 | "bs-platform": "^7.2.2", 21 | "clang-format": "^1.4.0", 22 | "wonder-bs-most": "^0.0.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/indirect_ray.glsl: -------------------------------------------------------------------------------- 1 | 2 | vec3 shootIndirectRay(accelerationStructureEXT topLevelAS, vec3 origin, 3 | vec3 rayDir, float tMin) { 4 | float tMax = 1.0e38f; // The farthest distance we'll count as a hit 5 | uint flags = gl_RayFlagsNoneEXT; 6 | 7 | prd.hitValue = vec3(0.0); 8 | 9 | traceRayEXT(topLevelAS, // acceleration structure 10 | flags, // rayFlags 11 | 0xFF, // cullMask 12 | 0, // sbtRecordOffset 13 | 0, // sbtRecordStride 14 | 0, // missIndex 15 | origin, // ray origin 16 | tMin, // ray min range 17 | rayDir, // ray direction 18 | tMax, // ray max range 19 | 0 // payload (location = 0) 20 | ); 21 | 22 | return prd.hitValue; 23 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/shadow_ray.glsl: -------------------------------------------------------------------------------- 1 | bool shadowRayVisibility(accelerationStructureEXT topLevelAS, uint missIndex, 2 | vec3 origin, vec3 rayDir, float tMin, float tMax) { 3 | uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | 4 | gl_RayFlagsSkipClosestHitShaderEXT; 5 | isShadowed = true; 6 | 7 | traceRayEXT(topLevelAS, // acceleration structure 8 | flags, // rayFlags 9 | 0xFF, // cullMask 10 | 0, // sbtRecordOffset 11 | 0, // sbtRecordStride 12 | missIndex, // missIndex 13 | origin, // ray origin 14 | tMin, // ray min range 15 | rayDir, // ray direction 16 | tMax, // ray max range 17 | 1 // payload (location = 1) 18 | ); 19 | return isShadowed; 20 | } -------------------------------------------------------------------------------- /src/pass/gbuffer/shaders/gbuffer.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #pragma shader_stage(fragment) 3 | 4 | #include "../../shaders/pbr_material.glsl" 5 | 6 | layout(location = 0) in vec3 vPosition; 7 | layout(location = 1) in vec3 vNormal; 8 | layout(location = 2) in vec4 vClipPosition; 9 | layout(location = 3) in vec4 vLastClipPosition; 10 | 11 | layout(location = 0) out vec4 gPositionRoughness; 12 | layout(location = 1) out vec4 gNormalMetalness; 13 | layout(location = 2) out vec4 gDiffusePositionW; 14 | layout(location = 3) out vec4 gMotionVectorDepthSpecular; 15 | 16 | void main() { 17 | gPositionRoughness = vec4(vPosition, getMaterialRoughness()); 18 | gNormalMetalness = vec4(normalize(vNormal), getMaterialMetalness()); 19 | gDiffusePositionW = vec4(getMaterialDiffuse(), 0.0); 20 | 21 | gMotionVectorDepthSpecular = 22 | vec4(((vClipPosition.xy / vClipPosition.w) - 23 | (vLastClipPosition.xy / vLastClipPosition.w)), 24 | gl_FragCoord.z, getMaterialSpecular()); 25 | } -------------------------------------------------------------------------------- /src/pass/bmfr/shaders/utils.glsl: -------------------------------------------------------------------------------- 1 | 2 | uint convertBufferTwoDIndexToOneDIndex(uint twoDIndexX, uint twoDIndexY, 3 | uint bufferSizeX) { 4 | return twoDIndexY * bufferSizeX + twoDIndexX; 5 | } 6 | 7 | float getAlbedoMinLimit() { return 0.01; } 8 | 9 | vec3 demodulateAlbedo(vec3 currentColor, vec3 diffuse) { 10 | float minLimit = getAlbedoMinLimit(); 11 | 12 | return vec3( 13 | diffuse.x < minLimit ? currentColor.x : currentColor.x / diffuse.x, 14 | diffuse.y < minLimit ? currentColor.y : currentColor.y / diffuse.y, 15 | diffuse.z < minLimit ? currentColor.z : currentColor.z / diffuse.z); 16 | } 17 | 18 | vec3 modulateAlbedo(vec3 currentColor, vec3 diffuse) { 19 | float minLimit = getAlbedoMinLimit(); 20 | 21 | return vec3( 22 | diffuse.x < minLimit ? currentColor.x : currentColor.x * diffuse.x, 23 | diffuse.y < minLimit ? currentColor.y : currentColor.y * diffuse.y, 24 | diffuse.z < minLimit ? currentColor.z : currentColor.z * diffuse.z); 25 | } 26 | -------------------------------------------------------------------------------- /src/pass/gbuffer/shaders/gbuffer.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #pragma shader_stage(vertex) 3 | 4 | #include "../../shaders/camera.glsl" 5 | 6 | layout(location = 0) in vec3 position; 7 | layout(location = 1) in vec3 normal; 8 | 9 | layout(location = 0) out vec3 vPosition; 10 | layout(location = 1) out vec3 vNormal; 11 | layout(location = 2) out vec4 vClipPosition; 12 | layout(location = 3) out vec4 vLastClipPosition; 13 | 14 | layout(std140, set = 0, binding = 0) uniform Model { 15 | mat3 normalMatrix; 16 | mat4 modelMatrix; 17 | mat4 lastModelMatrix; 18 | } 19 | uModel; 20 | 21 | void main() { 22 | vec4 worldPosition = uModel.modelMatrix * vec4(position, 1.0); 23 | vPosition = vec3(worldPosition); 24 | vNormal = uModel.normalMatrix * normal; 25 | 26 | vec4 clipPosition = getProjectionMatrix() * getViewMatrix() * worldPosition; 27 | vClipPosition = clipPosition; 28 | vLastClipPosition = getLastViewProjectionMatrix() * uModel.lastModelMatrix * 29 | vec4(position, 1.0); 30 | 31 | gl_Position = clipPosition; 32 | gl_Position.y = -gl_Position.y; 33 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/random.glsl: -------------------------------------------------------------------------------- 1 | // Generate a random unsigned int from two unsigned int values, using 16 pairs 2 | // of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis, 3 | // "GPU Random Numbers via the Tiny Encryption Algorithm" 4 | uint tea(uint val0, uint val1) { 5 | uint v0 = val0; 6 | uint v1 = val1; 7 | uint s0 = 0; 8 | 9 | for (uint n = 0; n < 16; n++) { 10 | s0 += 0x9e3779b9; 11 | v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); 12 | v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); 13 | } 14 | 15 | return v0; 16 | } 17 | 18 | // Generate a random unsigned int in [0, 2^24) given the previous RNG state 19 | // using the Numerical Recipes linear congruential generator 20 | uint lcg(inout uint prev) { 21 | uint LCG_A = 1664525u; 22 | uint LCG_C = 1013904223u; 23 | prev = (LCG_A * prev + LCG_C); 24 | return prev & 0x00FFFFFF; 25 | } 26 | 27 | // Generate a random float in [0, 1) given the previous RNG state 28 | float rnd(inout uint prev) { return (float(lcg(prev)) / float(0x01000000)); } 29 | -------------------------------------------------------------------------------- /src/pass/taa/shaders/taa_firstFrame.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #pragma shader_stage(fragment) 3 | 4 | #include "../../shaders/definition.glsl" 5 | #include "../../shaders/jitter.glsl" 6 | #include "../../shaders/utils.glsl" 7 | #include "./taa_definition.glsl" 8 | #include "./taa_utils.glsl" 9 | 10 | layout(location = 0) in vec2 uv; 11 | // layout(location = 0) out vec4 outColor; 12 | 13 | layout(binding = 0) uniform sampler sampler0; 14 | layout(binding = 1) uniform texture2D gMotionVectorDepthSpecularTexture; 15 | 16 | layout(set = 1, binding = 2) uniform ScreenDimension { vec2 resolution; } 17 | screenDimension; 18 | 19 | layout(set = 1, binding = 3) uniform Taa { vec2 jitter; } 20 | uTaa; 21 | 22 | void main() { 23 | vec2 unjitteredUV = getUnJitterdUV(uv, uTaa.jitter); 24 | 25 | vec4 currentColor = getCurrentColor(unjitteredUV, screenDimension.resolution); 26 | 27 | #ifdef USE_TONEMAP 28 | currentColor.xyz = toneMap(currentColor.xyz); 29 | #endif 30 | 31 | currentColor.xyz = rgb2YCoCgR(currentColor.xyz); 32 | 33 | // outColor = currentColor; 34 | 35 | setPrevColor(uv, screenDimension.resolution, currentColor); 36 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/indirect_utils.glsl: -------------------------------------------------------------------------------- 1 | 2 | // Utility function to get a vector perpendicular to an input vector 3 | // (from "Efficient Construction of Perpendicular Vectors Without Branching") 4 | vec3 getPerpendicularVector(vec3 u) { 5 | vec3 a = abs(u); 6 | uint xm = ((a.x - a.y) < 0 && (a.x - a.z) < 0) ? 1 : 0; 7 | uint ym = (a.y - a.z) < 0 ? (1 ^ xm) : 0; 8 | uint zm = 1 ^ (xm | ym); 9 | return cross(u, vec3(xm, ym, zm)); 10 | } 11 | 12 | // // Takes our seed, updates it, and returns a pseudorandom float in [0..1] 13 | // float _nextRand(inout uint s) { 14 | // s = (1664525u * s + 1013904223u); 15 | // return float(s & 0x00FFFFFF) / float(0x01000000); 16 | // } 17 | 18 | vec3 getCosHemisphereSample(float r1, float r2, vec3 hitNorm) { 19 | // Get 2 random numbers to select our sample with 20 | vec2 randVal = vec2(r1, r2); 21 | 22 | // Cosine weighted hemisphere sample from RNG 23 | vec3 bitangent = getPerpendicularVector(hitNorm); 24 | vec3 tangent = cross(bitangent, hitNorm); 25 | float r = sqrt(randVal.x); 26 | float phi = 2.0f * 3.14159265f * randVal.y; 27 | 28 | // Get our cosine-weighted hemisphere lobe sample direction 29 | return tangent * (r * cos(phi).x) + bitangent * (r * sin(phi)) + 30 | hitNorm.xyz * sqrt(1 - randVal.x); 31 | } 32 | -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/pbr_compute.glsl: -------------------------------------------------------------------------------- 1 | // vec3 computeDiffuse(vec3 matDiffuse, vec3 lightDir, vec3 normal) { 2 | // // Lambertian 3 | // float dotNL = max(dot(normal, lightDir), 0.0); 4 | // vec3 c = matDiffuse * dotNL; 5 | // // if (getMaterialIllum(mat) >= 1) 6 | // // return c + _getMaterialAmbient(mat); 7 | // return c; 8 | // } 9 | 10 | // vec3 computeSpecular(vec3 matSpecular, float shininess, vec3 viewDir, 11 | // vec3 lightDir, vec3 normal) { 12 | // // if (getMaterialIllum(mat) < 2) 13 | // // return vec3(0); 14 | 15 | // // Compute specular only if not in shadow 16 | // const float kPi = 3.14159265; 17 | // const float kShininess = max(shininess, 4.0); 18 | 19 | // // Specular 20 | // const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); 21 | // vec3 V = normalize(-viewDir); 22 | // vec3 R = reflect(-lightDir, normal); 23 | // float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); 24 | 25 | // return matSpecular * specular; 26 | // } 27 | 28 | // vec3 computeColor(float lightIntensity, float attenuation, vec3 diffuse, 29 | // vec3 specular) { 30 | // // return vec3(lightIntensity * attenuation * (diffuse + specular)); 31 | // return vec3(lightIntensity * attenuation * diffuse); 32 | // } -------------------------------------------------------------------------------- /src/pass/accumulation/shaders/accumulation.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #pragma shader_stage(fragment) 3 | 4 | #include "../../shaders/utils.glsl" 5 | 6 | layout(location = 0) in vec2 uv; 7 | layout(location = 0) out vec4 outColor; 8 | 9 | layout(std140, set = 0, binding = 0) buffer PixelBuffer { vec4 pixels[]; } 10 | pixelBuffer; 11 | 12 | layout(std140, set = 0, binding = 1) buffer AccumulationPixelBuffer { 13 | vec4 pixels[]; 14 | } 15 | accumulationPixelBuffer; 16 | 17 | layout(std140, set = 0, binding = 2) uniform AccumulationCommonData { 18 | float accumFrameCount; 19 | float useDenoise; 20 | } 21 | accumulationCommonData; 22 | 23 | layout(set = 0, binding = 3) uniform ScreenDimension { vec2 resolution; } 24 | screenDimension; 25 | 26 | void main() { 27 | uint accumFrameCount = uint(accumulationCommonData.accumFrameCount); 28 | uint pixelIndex = getPixelIndex(uv, screenDimension.resolution); 29 | 30 | bool useDenoise = accumulationCommonData.useDenoise != 0.0; 31 | 32 | if (useDenoise) { 33 | outColor = pixelBuffer.pixels[pixelIndex]; 34 | } else { 35 | vec4 accumulationColor = accumulationPixelBuffer.pixels[pixelIndex] + 36 | pixelBuffer.pixels[pixelIndex]; 37 | 38 | accumulationPixelBuffer.pixels[pixelIndex] = accumulationColor; 39 | 40 | vec4 finalColor = accumulationColor / accumFrameCount; 41 | 42 | pixelBuffer.pixels[pixelIndex] = finalColor; 43 | 44 | outColor = finalColor; 45 | } 46 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/ray-closest-hit-indirect-gi.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_EXT_scalar_block_layout : enable 5 | #pragma shader_stage(closest) 6 | 7 | #include "../../shaders/camera.glsl" 8 | #include "../../shaders/common_data.glsl" 9 | #include "get_hit_shading_data.glsl" 10 | #include "shading_data.glsl" 11 | 12 | #include "random.glsl" 13 | #include "raycommon.glsl" 14 | 15 | #include "light.glsl" 16 | #include "pbr_compute.glsl" 17 | 18 | #include "disney.glsl" 19 | 20 | layout(location = 1) rayPayloadEXT bool isShadowed; 21 | 22 | #include "shadow_ray.glsl" 23 | 24 | #include "ggx_direct.glsl" 25 | 26 | #include "indirect_utils.glsl" 27 | 28 | layout(location = 0) rayPayloadInEXT hitPayload prd; 29 | 30 | #include "indirect_ray.glsl" 31 | 32 | #include "ggx_indirect.glsl" 33 | 34 | layout(set = 1, binding = 0) uniform accelerationStructureEXT topLevelAS; 35 | 36 | layout(std140, set = 1, binding = 2) uniform CommonData { vec4 compressedData; } 37 | pushC; 38 | 39 | void main() { 40 | vec4 commonDataCompressedData = pushC.compressedData; 41 | uint lightCount = getLightCount(commonDataCompressedData); 42 | 43 | const float tMin = 0.1; 44 | 45 | HitShadingData data = getHitShadingData(gl_InstanceID, gl_PrimitiveID); 46 | 47 | ShadingData shading = 48 | buildShadingData(data.materialDiffuse, data.materialMetalness, 49 | data.materialRoughness, data.materialSpecular); 50 | 51 | prd.hitValue += computeDirectLight( 52 | prd.seed, prd.evalDisneyType, tMin, lightCount, data.worldPosition, 53 | data.worldNormal, data.V, shading, topLevelAS); 54 | 55 | prd.V = data.V; 56 | prd.worldPosition = data.worldPosition; 57 | prd.worldNormal = data.worldNormal; 58 | 59 | prd.shading = shading; 60 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/ggx_direct.glsl: -------------------------------------------------------------------------------- 1 | 2 | vec3 computeDirectLight(uint seed, 3 | // 0:both, 1:diffuse, 2:specular 4 | uint evalDisneyType, float tMin, uint lightCount, 5 | vec3 worldPosition, vec3 worldNormal, vec3 V, 6 | ShadingData shading, 7 | 8 | accelerationStructureEXT topLevelAS) { 9 | uint lightIndexToSample = min(uint(rnd(seed) * lightCount), lightCount - 1); 10 | // uint lightIndexToSample = 0; 11 | 12 | vec3 lightDir; 13 | float lightIntensity; 14 | float lightDistance; 15 | 16 | getLightData(lightIndexToSample, lightIntensity, lightDistance, lightDir); 17 | 18 | // Tracing shadow ray only if the light is visible from the surface 19 | if (isLightVisibleFromTheSurface(worldNormal, lightDir)) { 20 | 21 | float tMax = lightDistance; 22 | // vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * 23 | // gl_HitTEXT; 24 | vec3 origin = worldPosition; 25 | vec3 rayDir = lightDir; 26 | 27 | bool isShadowed = 28 | shadowRayVisibility(topLevelAS, 1, origin, rayDir, tMin, tMax); 29 | 30 | if (isShadowed) { 31 | return vec3(0.0); 32 | } 33 | } 34 | 35 | float pdf = 1 / float(lightCount); 36 | 37 | const vec3 N = worldNormal; 38 | const vec3 L = lightDir; 39 | const vec3 H = normalize(V + L); 40 | 41 | const float NdotH = max(0.0, dot(N, H)); 42 | const float NdotL = max(0.0, dot(L, N)); 43 | const float HdotL = max(0.0, dot(H, L)); 44 | const float NdotV = max(0.0, dot(N, V)); 45 | 46 | // const float bsdfPdf = DisneyPdf(NdotH, NdotL, HdotL); 47 | 48 | vec3 f; 49 | switch (evalDisneyType) { 50 | case 1: 51 | f = evalDiffuse(NdotL, NdotV, HdotL, shading); 52 | break; 53 | case 2: 54 | f = evalSpecular(NdotL, NdotV, NdotH, HdotL, shading); 55 | break; 56 | case 0: 57 | default: 58 | f = eval(NdotL, NdotV, NdotH, HdotL, shading); 59 | break; 60 | } 61 | 62 | return lightIntensity * f / pdf; 63 | } -------------------------------------------------------------------------------- /src/pass/taa/TAAJitter.re: -------------------------------------------------------------------------------- 1 | open Js.Typed_array; 2 | 3 | let generateHaltonJiters = [%bs.raw 4 | (frameCount, windowWidth, windowHeight) => {| 5 | /** 6 | * Generate a number in the Halton Sequence at a given index. This is 7 | * shamelessly stolen from the pseudocode on the Wikipedia page 8 | * 9 | * @param base the base to use for the Halton Sequence 10 | * @param index the index into the sequence 11 | */ 12 | var _haltonNumber = function(base, index) { 13 | let result = 0; 14 | let f = 1; 15 | while (index > 0) { 16 | f /= base; 17 | result += f * (index % base); 18 | index = Math.floor(index / base); 19 | } 20 | 21 | return result; 22 | } 23 | 24 | /** 25 | * Generate jitter amounts based on the Halton Sequence. Jitters are 26 | * normailized to be between -1 and 1 27 | * 28 | * @param length the number of offsets to generate 29 | */ 30 | var _generateHaltonJiters = function(length) { 31 | let jitters = []; 32 | 33 | for (let i = 1; i <= length; i++) 34 | jitters.push([(_haltonNumber(2, i) - 0.5) * 2, (_haltonNumber(3, i) - 0.5) * 2]); 35 | 36 | return jitters; 37 | } 38 | 39 | return _generateHaltonJiters(frameCount).map(([ jitterX, jitterY ]) =>{ 40 | return [ 41 | jitterX / windowWidth, 42 | jitterY / windowHeight 43 | ] 44 | }) 45 | |} 46 | ]; 47 | 48 | // let jitterProjectionMatrix = (projectionMatrix, state) => { 49 | // let (jitterX, jitterY) = 50 | // Pass.getJitter(Pass.getAccumulatedFrameIndex(state), state); 51 | 52 | // let result = projectionMatrix |> Matrix4.copy; 53 | 54 | // // Float32Array.unsafe_set(result, 8, jitterX); 55 | // // Float32Array.unsafe_set(result, 9, jitterY); 56 | 57 | // // Log.printComplete( 58 | // // "pro jitter:", 59 | // // ( Float32Array.unsafe_get(result, 8), Float32Array.unsafe_get(result, 9) ) 60 | // // ); 61 | // // Log.printComplete( 62 | // // "jitter camera:", 63 | // // (jitterX, jitterY) 64 | // // ); 65 | 66 | // // Float32Array.unsafe_set( 67 | // // result, 68 | // // 8, 69 | // // Float32Array.unsafe_get(result, 8) +. jitterX, 70 | // // ); 71 | // // Float32Array.unsafe_set( 72 | // // result, 73 | // // 9, 74 | // // Float32Array.unsafe_get(result, 9) +. jitterY, 75 | // // ); 76 | 77 | // result; 78 | // }; -------------------------------------------------------------------------------- /src/RTXMain.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | open WonderBsMost.Most; 6 | 7 | let window = 8 | Window.make({ 9 | "width": 640, 10 | "height": 480, 11 | "title": "WebGPU", 12 | "resizable": false, 13 | }); 14 | 15 | RaytracingFramework.Director.load(window) 16 | |> subscribe({ 17 | "next": ((adapter, device, context, queue, swapChainFormat)) => { 18 | let swapChain = 19 | context 20 | |> Context.configureSwapChain({ 21 | "device": device, 22 | "format": swapChainFormat, 23 | }); 24 | 25 | StateData.getState() 26 | |> RTXScene.buildScene 27 | |> RaytracingFramework.Director.addInitFunc(RTXScene.init(device, window)) 28 | |> RaytracingFramework.Director.addUpdateFunc(RTXScene.update(device, queue, window)) 29 | |> RaytracingFramework.Director.addPassFuncs( 30 | GBufferPass.init(device, window), 31 | GBufferPass.execute(device, queue), 32 | ) 33 | |> RaytracingFramework.Director.addPassFuncs( 34 | RayTracingPass.init(device, queue), 35 | RayTracingPass.execute(device, window, queue), 36 | ) 37 | // |> RaytracingFramework.Director.addPassFuncs( 38 | // BMFRPreprocessPass.init(device, swapChainFormat), 39 | // BMFRPreprocessPass.execute(device, queue, swapChain), 40 | // ) 41 | |> RaytracingFramework.Director.addPassFuncs( 42 | BMFRRegressionPass.init(device), 43 | BMFRRegressionPass.execute(device, queue, window), 44 | ) 45 | |> RaytracingFramework.Director.addPassFuncs( 46 | BMFRPostprocessPass.init(device, swapChainFormat), 47 | BMFRPostprocessPass.execute(device, queue, swapChain), 48 | ) 49 | |> RaytracingFramework.Director.addPassFuncs( 50 | TAAPass.init(device, window, swapChainFormat), 51 | TAAPass.execute(device, queue, swapChain), 52 | ) 53 | |> RaytracingFramework.Director.addPassFuncs( 54 | AccumulationPass.init(device, swapChainFormat), 55 | AccumulationPass.execute(device, queue, swapChain), 56 | ) 57 | |> RaytracingFramework.Director.start(window, swapChain); 58 | }, 59 | "error": e => { 60 | Log.log(e); 61 | 62 | (); 63 | }, 64 | "complete": () => { 65 | (); 66 | }, 67 | }); 68 | -------------------------------------------------------------------------------- /src/pass/taa/shaders/taa_utils.glsl: -------------------------------------------------------------------------------- 1 | 2 | layout(std140, set = 1, binding = 0) buffer PixelBuffer { vec4 pixels[]; } 3 | pixelBuffer; 4 | layout(std140, set = 1, binding = 1) buffer HistoryPixelBuffer { 5 | vec4 pixels[]; 6 | } 7 | historyPixelBuffer; 8 | 9 | vec4 getCurrentColor(vec2 unjitteredUV, vec2 resolution) { 10 | uint currentColorPixelIndex = getPixelIndex(unjitteredUV, resolution); 11 | 12 | return pixelBuffer.pixels[currentColorPixelIndex]; 13 | } 14 | 15 | void setCurrentColor(vec2 unjitteredUV, vec2 resolution, vec4 currentColor) { 16 | pixelBuffer.pixels[getPixelIndex(unjitteredUV, resolution)] = currentColor; 17 | } 18 | 19 | vec4 getPrevColor(vec2 jitteredUV, vec2 resolution) { 20 | return historyPixelBuffer.pixels[getPixelIndex(jitteredUV, resolution)]; 21 | } 22 | 23 | void setPrevColor(vec2 jitteredUV, vec2 resolution, vec4 prevColor) { 24 | historyPixelBuffer.pixels[getPixelIndex(jitteredUV, resolution)] = prevColor; 25 | } 26 | 27 | vec3 rgb2YCoCgR(vec3 rgbColor) { 28 | vec3 yCoCgRColor; 29 | 30 | yCoCgRColor.y = rgbColor.r - rgbColor.b; 31 | float temp = rgbColor.b + yCoCgRColor.y / 2; 32 | yCoCgRColor.z = rgbColor.g - temp; 33 | yCoCgRColor.x = temp + yCoCgRColor.z / 2; 34 | 35 | return yCoCgRColor; 36 | } 37 | 38 | vec3 yCoCgR2RGB(vec3 yCoCgRColor) { 39 | vec3 rgbColor; 40 | 41 | float temp = yCoCgRColor.x - yCoCgRColor.z / 2; 42 | rgbColor.g = yCoCgRColor.z + temp; 43 | rgbColor.b = temp - yCoCgRColor.y / 2; 44 | rgbColor.r = rgbColor.b + yCoCgRColor.y; 45 | 46 | return rgbColor; 47 | } 48 | 49 | float luminance(in vec3 color) { 50 | #ifdef USE_TONEMAP 51 | return color.r; 52 | #else 53 | return dot(color, vec3(0.25f, 0.50f, 0.25f)); 54 | #endif 55 | } 56 | 57 | vec3 toneMap(vec3 color) { 58 | #ifdef USE_MIXED_TONE_MAP 59 | float luma = luminance(color); 60 | if (luma <= MIXED_TONE_MAP_LINEAR_UPPER_BOUND) { 61 | return color; 62 | } else { 63 | return color * 64 | (MIXED_TONE_MAP_LINEAR_UPPER_BOUND * 65 | MIXED_TONE_MAP_LINEAR_UPPER_BOUND - 66 | luma) / 67 | (luma * (2 * MIXED_TONE_MAP_LINEAR_UPPER_BOUND - 1 - luma)); 68 | } 69 | #else 70 | return color / (1 + luminance(color)); 71 | #endif 72 | } 73 | 74 | vec3 unToneMap(vec3 color) { 75 | #ifdef USE_MIXED_TONE_MAP 76 | float luma = luminance(color); 77 | if (luma <= MIXED_TONE_MAP_LINEAR_UPPER_BOUND) { 78 | return color; 79 | } else { 80 | return color * 81 | (MIXED_TONE_MAP_LINEAR_UPPER_BOUND * 82 | MIXED_TONE_MAP_LINEAR_UPPER_BOUND - 83 | (2 * MIXED_TONE_MAP_LINEAR_UPPER_BOUND - 1) * luma) / 84 | (luma * (1 - luma)); 85 | } 86 | #else 87 | return color / (1 - luminance(color)); 88 | #endif 89 | } 90 | -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/disney.glsl: -------------------------------------------------------------------------------- 1 | 2 | #define PI 3.141592653589793 3 | #define TWO_PI 6.283185307179586 4 | #define INV_PI 0.3183098861837907 5 | 6 | float _sqr(float f) { return f * f; } 7 | 8 | float _gtr1(float NdotH, float a) { 9 | if (a >= 1.0) 10 | return INV_PI; 11 | float a2 = a * a; 12 | float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; 13 | return (a2 - 1.0) / (PI * log(a2) * t); 14 | } 15 | 16 | float _gtr2(float NdotH, float a) { 17 | float a2 = a * a; 18 | float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; 19 | return a2 / (PI * t * t); 20 | } 21 | 22 | float _smithGGX_G(float NdotV, float a) { 23 | float a2 = a * a; 24 | float b = NdotV * NdotV; 25 | return 1.0 / (NdotV + sqrt(a2 + b - a2 * b)); 26 | } 27 | 28 | float _schlickFresnelReflectance(float u) { 29 | float m = clamp(1.0 - u, 0.0, 1.0); 30 | float m2 = m * m; 31 | return m2 * m2 * m; 32 | } 33 | 34 | float computeDiffusePdf(in const float NdotL) { return NdotL * (1.0 / PI); } 35 | 36 | float computeSpecularPdf(in const float NdotH, in const float HdotL, 37 | in ShadingData shading) { 38 | const float r_pdf = _gtr2(NdotH, shading.roughness) * NdotH / (4.0 * HdotL); 39 | const float c_pdf = _gtr1(NdotH, 0.001) * NdotH / (4.0 * HdotL); 40 | 41 | return c_pdf * 0.001 + r_pdf; 42 | } 43 | 44 | vec3 evalDiffuse(in float NdotL, in const float NdotV, in const float HdotL, 45 | in ShadingData shading) { 46 | if (NdotL <= 0.0 || NdotV <= 0.0) 47 | return vec3(0); 48 | 49 | const vec3 cd_lin = shading.baseColor; 50 | 51 | // Diffuse fresnel - go from 1 at normal incidence to 0.5 at grazing 52 | // and mix in diffuse retro-reflection based on roughness 53 | const float f_wo = _schlickFresnelReflectance(NdotV); 54 | const float f_wi = _schlickFresnelReflectance(NdotL); 55 | 56 | const float fd90 = 0.5 + 2.0 * HdotL * HdotL * shading.roughness; 57 | const float fd = mix(1.0, fd90, f_wo) * mix(1.0, fd90, f_wi); 58 | 59 | const vec3 f = ((1.0 / PI) * fd * cd_lin) * (1.0 - shading.metallic); 60 | 61 | return f * NdotL; 62 | } 63 | 64 | vec3 evalSpecular(in float NdotL, in const float NdotV, in const float NdotH, 65 | in const float HdotL, in ShadingData shading) { 66 | if (NdotL <= 0.0 || NdotV <= 0.0) 67 | return vec3(0); 68 | 69 | const vec3 cd_lin = shading.baseColor; 70 | 71 | const vec3 c_spec0 = 72 | mix(shading.specular * vec3(0.3), cd_lin, shading.metallic); 73 | 74 | const float ds = _gtr2(NdotH, shading.roughness); 75 | const float fh = _schlickFresnelReflectance(HdotL); 76 | const vec3 fs = mix(c_spec0, vec3(1), fh); 77 | 78 | float gs = 0.0; 79 | const float ro2 = _sqr(shading.roughness * 0.5 + 0.5); 80 | gs = _smithGGX_G(NdotV, ro2); 81 | gs *= _smithGGX_G(NdotL, ro2); 82 | 83 | // clearcoat (ior = 1.5 -> F0 = 0.04) 84 | const float dr = _gtr1(NdotH, 0.04); 85 | const float fr = mix(0.04, 1.0, fh); 86 | const float gr = _smithGGX_G(NdotV, 0.25) * _smithGGX_G(NdotL, 0.25); 87 | 88 | const vec3 f = gs * fs * ds + 0.001 * gr * fr * dr; 89 | 90 | return f * NdotL; 91 | } 92 | 93 | vec3 eval(in float NdotL, in const float NdotV, in const float NdotH, 94 | in const float HdotL, in ShadingData shading) { 95 | return evalDiffuse(NdotL, NdotV, HdotL, shading) + 96 | evalSpecular(NdotL, NdotV, NdotH, HdotL, shading); 97 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/ggx_indirect.glsl: -------------------------------------------------------------------------------- 1 | 2 | float _computeSpecularLobeProb(ShadingData shading) { 3 | 4 | const vec3 cd_lin = shading.baseColor; 5 | const float cd_lum = dot(cd_lin, vec3(0.3, 0.6, 0.1)); 6 | const vec3 c_spec0 = 7 | mix(shading.specular * vec3(0.3), cd_lin, shading.metallic); 8 | const float cs_lum = dot(c_spec0, vec3(0.3, 0.6, 0.1)); 9 | 10 | return cs_lum / (cs_lum + (1.0 - shading.metallic) * cd_lum); 11 | } 12 | 13 | vec3 _getGGXMicrofacet(float r1, float r2, vec3 worldNormal, vec3 V, 14 | ShadingData shading) { 15 | // float r1 = rnd(seed); 16 | // float r2 = rnd(seed); 17 | 18 | // Get an orthonormal basis from the normal 19 | vec3 N = worldNormal; 20 | vec3 B = getPerpendicularVector(worldNormal); 21 | vec3 T = cross(B, worldNormal); 22 | 23 | const float a = shading.roughness; 24 | const float cosTheta = sqrt((1.0 - r2) / (1.0 + (a * a - 1.0) * r2)); 25 | const float sinTheta = sqrt(max(0.0, 1.0 - (cosTheta * cosTheta))); 26 | const float phi = r1 * TWO_PI; 27 | vec3 H = normalize(vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta)); 28 | H = H.x * T + H.y * B + H.z * N; 29 | // H = dot(H, V) <= 0.0 ? H * -1.0 : H; 30 | 31 | return H; 32 | } 33 | 34 | vec3 _computeSpecular(float r1, float r2, float tMin, vec3 worldPosition, 35 | vec3 worldNormal, vec3 V, ShadingData shading, 36 | float specularLobeProb, 37 | accelerationStructureEXT topLevelAS) { 38 | const vec3 H = _getGGXMicrofacet(r1, r2, worldNormal, V, shading); 39 | 40 | const vec3 L = reflect(-V, H); 41 | 42 | prd.evalDisneyType = 0; 43 | vec3 bounceColor = shootIndirectRay(topLevelAS, worldPosition, L, tMin); 44 | 45 | const vec3 N = worldNormal; 46 | 47 | const float NdotH = max(0.0, dot(N, H)); 48 | const float NdotL = max(0.0, dot(L, N)); 49 | const float HdotL = max(0.0, dot(H, L)); 50 | const float NdotV = max(0.0, dot(N, V)); 51 | 52 | return bounceColor * evalSpecular(NdotL, NdotV, NdotH, HdotL, shading) / 53 | (computeSpecularPdf(NdotH, HdotL, shading) * specularLobeProb); 54 | } 55 | 56 | vec3 _computeDiffuse(float r1, float r2, float tMin, vec3 worldPosition, 57 | vec3 worldNormal, vec3 V, ShadingData shading, 58 | float specularLobeProb, 59 | accelerationStructureEXT topLevelAS) { 60 | vec3 bounceDir = getCosHemisphereSample(r1, r2, worldNormal); 61 | 62 | prd.evalDisneyType = 1; 63 | vec3 bounceColor = 64 | shootIndirectRay(topLevelAS, worldPosition, bounceDir, tMin); 65 | 66 | const vec3 L = bounceDir; 67 | const vec3 N = worldNormal; 68 | const vec3 H = normalize(V + L); 69 | 70 | const float NdotL = max(0.0, dot(L, N)); 71 | const float HdotL = max(0.0, dot(H, L)); 72 | const float NdotV = max(0.0, dot(N, V)); 73 | 74 | return bounceColor * evalDiffuse(NdotL, NdotV, HdotL, shading) / 75 | (computeDiffusePdf(NdotL) * (1.0 - specularLobeProb)); 76 | } 77 | 78 | vec3 computeIndirectLight(uint seed, float tMin, 79 | 80 | vec3 V, vec3 worldPosition, vec3 worldNormal, 81 | ShadingData shading, 82 | accelerationStructureEXT topLevelAS) { 83 | 84 | float specularLobeProb = _computeSpecularLobeProb(shading); 85 | bool chooseSpecular = (rnd(seed) < specularLobeProb); 86 | 87 | const uint indirectLightSpecularSampleCount = 30; 88 | const uint indirectLightDiffuseSampleCount = 30; 89 | 90 | float sampleRandomArr[indirectLightSpecularSampleCount]; 91 | 92 | for (uint i = 0; i < indirectLightSpecularSampleCount; i++) { 93 | sampleRandomArr[i] = 94 | float(i + 0.1) / (indirectLightSpecularSampleCount + 0.1); 95 | } 96 | 97 | if (chooseSpecular) { 98 | vec3 indirectSpecularColor = vec3(0.0); 99 | 100 | for (uint ss1 = 0; ss1 < indirectLightSpecularSampleCount; ++ss1) { 101 | indirectSpecularColor += _computeSpecular( 102 | rnd(seed), sampleRandomArr[ss1 % indirectLightSpecularSampleCount], 103 | tMin, worldPosition, worldNormal, V, shading, specularLobeProb, 104 | topLevelAS); 105 | } 106 | 107 | indirectSpecularColor /= indirectLightSpecularSampleCount; 108 | 109 | return indirectSpecularColor; 110 | } 111 | 112 | vec3 indirectDiffuseColor = vec3(0.0); 113 | 114 | for (uint ss2 = 0; ss2 < indirectLightDiffuseSampleCount; ++ss2) { 115 | indirectDiffuseColor += 116 | _computeDiffuse(rnd(seed), rnd(seed), tMin, worldPosition, worldNormal, 117 | V, shading, specularLobeProb, topLevelAS); 118 | } 119 | 120 | indirectDiffuseColor /= indirectLightDiffuseSampleCount; 121 | 122 | return indirectDiffuseColor; 123 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/get_hit_shading_data.glsl: -------------------------------------------------------------------------------- 1 | 2 | struct InstanceData { 3 | // TODO perf: remove compressedData by pack to normalMatrix 4 | 5 | /* 6 | because scalar not work(not support float objId; mat4 modelMatrix;), 7 | so all aligned to vec4 8 | */ 9 | 10 | // include vertexIndex, materialIndex 11 | vec4 compressedData; 12 | 13 | mat3 normalMatrix; 14 | mat4 modelMatrix; 15 | }; 16 | 17 | struct Vertex { 18 | vec4 position; 19 | vec4 normal; 20 | // TODO perf: pack texCoord to position,normal 21 | // vec4 texCoord; 22 | }; 23 | 24 | /* 25 | extract this to avoid duplicate instead of move this into InstanceData. 26 | */ 27 | struct GeometryOffsetData { 28 | uint vertexOffset; 29 | uint indexOffset; 30 | }; 31 | 32 | struct PBRMaterial { 33 | vec4 diffuse; 34 | 35 | // include metalness, roughness, specular 36 | vec4 compressedData; 37 | }; 38 | 39 | hitAttributeEXT vec3 attribs; 40 | 41 | layout(std140, set = 1, binding = 4) buffer SceneDesc { InstanceData i[]; } 42 | sceneDesc; 43 | 44 | layout(scalar, set = 1, binding = 5) buffer SceneGeometryOffsetData { 45 | GeometryOffsetData o[]; 46 | } 47 | sceneGeometryOffsetData; 48 | 49 | // TODO use array of blocks!how to upload data??? 50 | layout(scalar, set = 1, binding = 6) buffer Vertices { Vertex v[]; } 51 | vertices; 52 | layout(scalar, set = 1, binding = 7) buffer Indices { uint i[]; } 53 | indices; 54 | 55 | layout(std140, set = 1, binding = 8) buffer MatColorBufferObject { 56 | PBRMaterial m[]; 57 | } 58 | materials; 59 | 60 | vec4 _getInstanceDataCompressedData(InstanceData instanceData) { 61 | return instanceData.compressedData; 62 | } 63 | 64 | uint _getGeometryIndex(vec4 compressedData) { return uint(compressedData.x); } 65 | 66 | uint _getMaterialIndex(vec4 compressedData) { return uint(compressedData.y); } 67 | 68 | uint _getVertexOffset(GeometryOffsetData geometryOffsetData) { 69 | return geometryOffsetData.vertexOffset; 70 | } 71 | 72 | uint _getIndexOffset(GeometryOffsetData geometryOffsetData) { 73 | return geometryOffsetData.indexOffset; 74 | } 75 | 76 | mat3 _getNormalMatrix(InstanceData instanceData) { 77 | return instanceData.normalMatrix; 78 | } 79 | 80 | mat4 _getModelMatrix(InstanceData instanceData) { 81 | return instanceData.modelMatrix; 82 | } 83 | 84 | InstanceData _getInstanceData(uint instanceIndex) { 85 | return sceneDesc.i[instanceIndex]; 86 | } 87 | 88 | GeometryOffsetData _getGeometryOffsetData(uint geometryIndex) { 89 | return sceneGeometryOffsetData.o[geometryIndex]; 90 | } 91 | 92 | PBRMaterial _getMaterial(uint materialIndex) { 93 | return materials.m[materialIndex]; 94 | } 95 | 96 | vec3 _getMaterialDiffuse(PBRMaterial mat) { return vec3(mat.diffuse); } 97 | 98 | float _getMaterialMetalness(PBRMaterial mat) { return mat.compressedData.x; } 99 | 100 | float _getMaterialRoughness(PBRMaterial mat) { return mat.compressedData.y; } 101 | 102 | float _getMaterialSpecular(PBRMaterial mat) { return mat.compressedData.z; } 103 | 104 | ivec3 _getTriangleIndices(uint indexOffset, uint primitiveIndex) { 105 | return ivec3(indices.i[indexOffset + 3 * primitiveIndex + 0], 106 | indices.i[indexOffset + 3 * primitiveIndex + 1], 107 | indices.i[indexOffset + 3 * primitiveIndex + 2]); 108 | } 109 | 110 | Vertex _getTriangleVertex(uint vertexOffset, uint index) { 111 | return vertices.v[vertexOffset + index]; 112 | } 113 | 114 | struct HitShadingData { 115 | vec3 worldPosition; 116 | vec3 worldNormal; 117 | vec3 V; 118 | vec3 materialDiffuse; 119 | // vec3 materialSpecularColor; 120 | float materialMetalness; 121 | float materialRoughness; 122 | float materialSpecular; 123 | }; 124 | 125 | HitShadingData getHitShadingData(uint instanceIndex, uint primitiveIndex) { 126 | InstanceData instanceData = _getInstanceData(instanceIndex); 127 | 128 | vec4 instanceDataCompressedData = 129 | _getInstanceDataCompressedData(instanceData); 130 | uint geometryIndex = _getGeometryIndex(instanceDataCompressedData); 131 | uint materialIndex = _getMaterialIndex(instanceDataCompressedData); 132 | GeometryOffsetData geometryOffsetData = _getGeometryOffsetData(geometryIndex); 133 | uint vertexOffset = _getVertexOffset(geometryOffsetData); 134 | uint indexOffset = _getIndexOffset(geometryOffsetData); 135 | 136 | // Indices of the triangle 137 | ivec3 ind = _getTriangleIndices(indexOffset, primitiveIndex); 138 | 139 | // Vertex of the triangle 140 | Vertex v0 = _getTriangleVertex(vertexOffset, ind.x); 141 | Vertex v1 = _getTriangleVertex(vertexOffset, ind.y); 142 | Vertex v2 = _getTriangleVertex(vertexOffset, ind.z); 143 | 144 | const vec3 barycentrics = 145 | vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); 146 | 147 | // Computing the normal at hit position 148 | vec3 localNormal = vec3(v0.normal) * barycentrics.x + 149 | vec3(v1.normal) * barycentrics.y + 150 | vec3(v2.normal) * barycentrics.z; 151 | 152 | // Computing the coordinates of the hit position 153 | vec3 localPos = vec3(v0.position) * barycentrics.x + 154 | vec3(v1.position) * barycentrics.y + 155 | vec3(v2.position) * barycentrics.z; 156 | 157 | PBRMaterial mat = _getMaterial(materialIndex); 158 | 159 | HitShadingData data; 160 | data.worldPosition = 161 | vec3(_getModelMatrix(instanceData) * vec4(localPos, 1.0)); 162 | data.worldNormal = normalize(_getNormalMatrix(instanceData) * localNormal); 163 | data.V = normalize(uCamera.cameraPosition.xyz - data.worldPosition); 164 | data.materialDiffuse = _getMaterialDiffuse(mat); 165 | data.materialMetalness = _getMaterialMetalness(mat); 166 | data.materialRoughness = _getMaterialRoughness(mat); 167 | data.materialSpecular = _getMaterialSpecular(mat); 168 | 169 | return data; 170 | } 171 | -------------------------------------------------------------------------------- /src/pass/taa/shaders/taa_otherFrame.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #pragma shader_stage(fragment) 3 | 4 | #include "../../shaders/definition.glsl" 5 | #include "../../shaders/jitter.glsl" 6 | #include "../../shaders/utils.glsl" 7 | #include "./taa_definition.glsl" 8 | #include "./taa_utils.glsl" 9 | 10 | layout(location = 0) in vec2 uv; 11 | // layout(location = 0) out vec4 outColor; 12 | 13 | layout(binding = 0) uniform sampler sampler0; 14 | layout(binding = 1) uniform texture2D gMotionVectorDepthSpecularTexture; 15 | 16 | layout(set = 1, binding = 2) uniform ScreenDimension { vec2 resolution; } 17 | screenDimension; 18 | 19 | layout(set = 1, binding = 3) uniform Taa { vec2 jitter; } 20 | uTaa; 21 | 22 | float linearDepth(float depth) { 23 | return (2.0 * NEAR_Z) / (FAR_Z + NEAR_Z - depth * (FAR_Z - NEAR_Z)); 24 | } 25 | 26 | vec2 getClosestMotionVector(vec2 jitteredUV, vec2 resolution) { 27 | vec2 closestOffset = vec2(0.0f, 0.0f); 28 | float closestDepth = FAR_Z; 29 | 30 | for (int y = -1; y <= 1; ++y) { 31 | for (int x = -1; x <= 1; ++x) { 32 | vec2 sampleOffset = 33 | vec2(float(x) / resolution.x, float(y) / resolution.y); 34 | vec2 sampleUV = jitteredUV + sampleOffset; 35 | sampleUV = saturateVec2(sampleUV); 36 | 37 | float NeighborhoodDepthSamp = 38 | texture(sampler2D(gMotionVectorDepthSpecularTexture, sampler0), 39 | sampleUV) 40 | .z; 41 | 42 | NeighborhoodDepthSamp = linearDepth(NeighborhoodDepthSamp); 43 | 44 | // #if USE_REVERSE_Z 45 | // if (NeighborhoodDepthSamp > closestDepth) 46 | // #else 47 | if (NeighborhoodDepthSamp < closestDepth) 48 | // #endif 49 | { 50 | closestDepth = NeighborhoodDepthSamp; 51 | closestOffset = vec2(x, y); 52 | } 53 | } 54 | } 55 | closestOffset /= resolution; 56 | 57 | return texture(sampler2D(gMotionVectorDepthSpecularTexture, sampler0), 58 | jitteredUV + closestOffset) 59 | .xy; 60 | } 61 | 62 | void sampleNeighborhoods(in vec2 unjitteredUV, in vec2 resolution, out vec3 m1, 63 | out vec3 m2, out vec3 minNeighbor, 64 | out vec3 maxNeighbor) { 65 | maxNeighbor = vec3(-99999999.0f, -99999999.0f, -99999999.0f); 66 | minNeighbor = vec3(9999999.0f, 9999999.0f, 9999999.0f); 67 | m1 = vec3(0.0); 68 | m2 = vec3(0.0); 69 | 70 | for (int y = -1; y <= 1; y++) { 71 | for (int x = -1; x <= 1; x++) { 72 | vec2 neighborUv = 73 | saturateVec2(unjitteredUV + 74 | vec2(float(x) / resolution.x, float(y) / resolution.y)); 75 | 76 | vec3 neighborTexel = getCurrentColor(neighborUv, resolution).xyz; 77 | 78 | #ifdef USE_TONEMAP 79 | neighborTexel = toneMap(neighborTexel); 80 | #endif 81 | 82 | neighborTexel = rgb2YCoCgR(neighborTexel); 83 | 84 | minNeighbor = min(minNeighbor, neighborTexel); 85 | maxNeighbor = max(maxNeighbor, neighborTexel); 86 | m1 += neighborTexel; 87 | m2 += neighborTexel * neighborTexel; 88 | } 89 | } 90 | } 91 | 92 | void varianceClip(in vec3 m1, in vec3 m2, out vec3 aabbMin, out vec3 aabbMax) { 93 | const uint N = 9; 94 | const float VarianceClipGamma = 1.0f; 95 | 96 | vec3 mu = m1 / N; 97 | vec3 sigma = sqrt(abs(m2 / N - mu * mu)); 98 | 99 | aabbMin = mu - VarianceClipGamma * sigma; 100 | aabbMax = mu + VarianceClipGamma * sigma; 101 | } 102 | 103 | vec3 clipAABB(vec3 aabbMin, vec3 aabbMax, vec3 prevColor) { 104 | // note: only clips towards aabb center (but fast!) 105 | vec3 p_clip = 0.5 * (aabbMax + aabbMin); 106 | vec3 e_clip = 0.5 * (aabbMax - aabbMin); 107 | 108 | vec3 v_clip = prevColor - p_clip; 109 | vec3 v_unit = v_clip.xyz / e_clip; 110 | vec3 a_unit = abs(v_unit); 111 | float ma_unit = max(a_unit.x, max(a_unit.y, a_unit.z)); 112 | 113 | if (ma_unit > 1.0) 114 | return p_clip + v_clip / ma_unit; 115 | else 116 | return prevColor; // point inside aabb 117 | } 118 | 119 | vec3 accumulateByExponentMovingAverage(float lenMotionVector, vec3 currentColor, 120 | vec3 prevColor) { 121 | const float BlendWeightLowerBound = 0.03; 122 | const float BlendWeightUpperBound = 0.12; 123 | const float BlendWeightVelocityScale = 100.0 * 60.0; 124 | 125 | float weight = mix(BlendWeightLowerBound, BlendWeightUpperBound, 126 | saturateFloat(lenMotionVector * BlendWeightVelocityScale)); 127 | 128 | return mix(prevColor, currentColor, weight); 129 | } 130 | 131 | void main() { 132 | vec2 jitterdUV = getJitterdUV(uv, uTaa.jitter); 133 | vec2 unjitteredUV = getUnJitterdUV(uv, uTaa.jitter); 134 | 135 | vec2 motionVector = 136 | getClosestMotionVector(jitterdUV, screenDimension.resolution); 137 | 138 | float lenMotionVector = length(motionVector); 139 | 140 | vec3 currentColor = 141 | getCurrentColor(unjitteredUV, screenDimension.resolution).xyz; 142 | 143 | #ifdef USE_TONEMAP 144 | currentColor = toneMap(currentColor); 145 | #endif 146 | 147 | currentColor = rgb2YCoCgR(currentColor); 148 | 149 | vec3 prevColor = 150 | getPrevColor(jitterdUV - motionVector, screenDimension.resolution).xyz; 151 | 152 | #ifdef USE_TONEMAP 153 | prevColor = toneMap(prevColor); 154 | #endif 155 | 156 | prevColor = rgb2YCoCgR(prevColor); 157 | 158 | vec3 m1; 159 | vec3 m2; 160 | vec3 minNeighbor; 161 | vec3 maxNeighbor; 162 | sampleNeighborhoods(unjitteredUV, screenDimension.resolution, m1, m2, 163 | minNeighbor, maxNeighbor); 164 | 165 | vec3 aabbMin; 166 | vec3 aabbMax; 167 | varianceClip(m1, m2, aabbMin, aabbMax); 168 | 169 | prevColor = clipAABB(aabbMin, aabbMax, prevColor); 170 | 171 | vec3 color = accumulateByExponentMovingAverage(lenMotionVector, currentColor, 172 | prevColor); 173 | color = yCoCgR2RGB(color); 174 | 175 | #ifdef USE_TONEMAP 176 | color = unToneMap(color); 177 | #endif 178 | 179 | // outColor = vec4(color, 1.0); 180 | 181 | setCurrentColor(uv, screenDimension.resolution, vec4(color, 1.0)); 182 | 183 | setPrevColor(uv, screenDimension.resolution, vec4(color, 1.0)); 184 | } -------------------------------------------------------------------------------- /src/pass/ray_tracing/shaders/ray-generation.rgen: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_EXT_scalar_block_layout : enable 5 | #pragma shader_stage(raygen) 6 | 7 | #include "../../shaders/camera.glsl" 8 | #include "../../shaders/common_data.glsl" 9 | #include "define.glsl" 10 | #include "reduce_noise_data.glsl" 11 | #include "shading_data.glsl" 12 | 13 | #include "raycommon.glsl" 14 | 15 | #include "light.glsl" 16 | #include "pbr_compute.glsl" 17 | #include "random.glsl" 18 | 19 | #include "disney.glsl" 20 | #include "disney_utils.glsl" 21 | 22 | #include "indirect_utils.glsl" 23 | 24 | #include "../../shaders/sample_utils.glsl" 25 | 26 | layout(location = 1) rayPayloadEXT bool isShadowed; 27 | 28 | #include "shadow_ray.glsl" 29 | 30 | #include "ggx_direct.glsl" 31 | 32 | layout(location = 0) rayPayloadEXT hitPayload prd; 33 | 34 | #include "indirect_ray.glsl" 35 | 36 | #include "ggx_indirect.glsl" 37 | 38 | layout(binding = 0) uniform sampler sampler0; 39 | layout(binding = 1) uniform texture2D gPositionRoughnessTexture; 40 | layout(binding = 2) uniform texture2D gNormalMetalnessTexture; 41 | layout(binding = 3) uniform texture2D gDiffusePositionWTexture; 42 | layout(binding = 4) uniform texture2D gMotionVectorDepthSpecularTexture; 43 | 44 | layout(set = 1, binding = 0) uniform accelerationStructureEXT topLevelAS; 45 | layout(std140, set = 1, binding = 1) buffer PixelBuffer { vec4 pixels[]; } 46 | pixelBuffer; 47 | 48 | layout(std140, set = 1, binding = 2) uniform CommonData { vec4 compressedData; } 49 | pushC; 50 | 51 | layout(std140, set = 1, binding = 3) uniform RayTracingCommonData { 52 | vec4 compressedData; 53 | } 54 | rayTracingCommonData; 55 | 56 | vec2 getLanuchIndex(uvec3 launchID, uvec3 launchSize) { 57 | const vec2 pixelCenter = vec2(launchID.xy) + vec2(0.5); 58 | const vec2 inUV = pixelCenter / vec2(launchSize.xy); 59 | 60 | // // return inUV * 2.0 - 1.0; 61 | return inUV; 62 | } 63 | 64 | bool isNotBackground(vec4 worldPosition) { return worldPosition.w == 0.0; } 65 | 66 | void main() { 67 | vec4 commonDataCompressedData = pushC.compressedData; 68 | uint frame = getFrame(commonDataCompressedData); 69 | uint lightCount = getLightCount(commonDataCompressedData); 70 | // bool doIndirectGI = getDoIndirectGI(commonDataCompressedData); 71 | // bool doIndirectGI = false; 72 | 73 | const uint bounceCount = 2; 74 | const bool doIndirectGI = true; 75 | const float tMin = 0.1; 76 | 77 | uint seed = 78 | tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, frame); 79 | 80 | prd.seed = seed; 81 | 82 | vec2 lanuchIndex = getLanuchIndex(gl_LaunchIDEXT, gl_LaunchSizeEXT); 83 | 84 | vec4 positionRoughness = 85 | texture(sampler2D(gPositionRoughnessTexture, sampler0), lanuchIndex); 86 | vec4 diffusePositionW = 87 | texture(sampler2D(gDiffusePositionWTexture, sampler0), lanuchIndex); 88 | vec4 normalMetalness = 89 | texture(sampler2D(gNormalMetalnessTexture, sampler0), lanuchIndex); 90 | vec4 motionVectorDepthSpecular = texture( 91 | sampler2D(gMotionVectorDepthSpecularTexture, sampler0), lanuchIndex); 92 | 93 | vec4 worldPosition = vec4(positionRoughness.xyz, diffusePositionW.a); 94 | vec3 worldNormal = normalMetalness.xyz; 95 | vec3 materialDiffuse = diffusePositionW.rgb; 96 | // vec3 materialSpecularColor = vec3(0.5, 0.0, 0.5); 97 | float materialMetalness = normalMetalness.w; 98 | float materialRoughness = positionRoughness.w; 99 | float materialSpecular = motionVectorDepthSpecular.w; 100 | 101 | ShadingData shading = buildShadingData(materialDiffuse, materialMetalness, 102 | materialRoughness, materialSpecular); 103 | 104 | vec3 hitValue = vec3(0.0); 105 | 106 | if (isNotBackground(worldPosition)) { 107 | vec3 V = computeV(uCamera.cameraPosition.xyz, worldPosition.xyz); 108 | 109 | hitValue += computeDirectLight(seed, 0, tMin, lightCount, worldPosition.xyz, 110 | worldNormal, V, shading, topLevelAS); 111 | 112 | // if(luminance(hitValue) >= maxValue ){ 113 | 114 | // hitValue = vec3(clamp(hitValue.x, 0.0, maxValue), 115 | // clamp(hitValue.y, 0.0, maxValue), 116 | // clamp(hitValue.z, 0.0, maxValue)); 117 | // } 118 | 119 | prd.worldPosition = worldPosition.xyz; 120 | prd.worldNormal = worldNormal; 121 | 122 | prd.shading = shading; 123 | 124 | prd.V = V; 125 | 126 | if (doIndirectGI) { 127 | float roughnessBias = 0.0; 128 | 129 | for (uint bb = 0; bb < bounceCount; bb++) { 130 | ShadingData shadingForEachBounce = prd.shading; 131 | 132 | // Increase Roughness Per Bounce for reduce fireflies: 133 | // https://twitter.com/YuriyODonnell/status/1199253959086612480 134 | // http://cg.ivd.kit.edu/publications/p2013/PSR_Kaplanyan_2013/PSR_Kaplanyan_2013.pdf 135 | // http://jcgt.org/published/0007/04/01/paper.pdf 136 | float oldRoughness = shadingForEachBounce.roughness; 137 | shadingForEachBounce.roughness = min(1.0, oldRoughness + roughnessBias); 138 | roughnessBias += oldRoughness * 0.75f; 139 | 140 | // TODO fix when use normal map: 141 | // Use the same normal for the normal-mapped and non-normal mapped 142 | // vectors... This means we could get light 143 | // leaks at secondary surfaces with normal maps due to indirect rays 144 | // going below the surface. This isn't a huge issue, but this is a 145 | // (TODO: fix) 146 | vec3 indirectLight = computeIndirectLight( 147 | seed, tMin, prd.V, prd.worldPosition, prd.worldNormal, 148 | shadingForEachBounce, topLevelAS); 149 | 150 | // if(luminance(indirectLight) <= maxValue ){ 151 | 152 | // hitValue += indirectLight; 153 | 154 | // } 155 | 156 | // const vec3 indirectLightClampMaxValue = vec3(18.0); 157 | 158 | // indirectLight = 159 | // clamp(indirectLight, vec3(0.0), indirectLightClampMaxValue); 160 | 161 | hitValue += indirectLight; 162 | } 163 | } 164 | } else { 165 | // TODO refactor: add miss color to common data buffer? 166 | hitValue = vec3(0.15); 167 | } 168 | 169 | const uint pixelIndex = 170 | gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x; 171 | 172 | pixelBuffer.pixels[pixelIndex] = vec4(hitValue, 1.0); 173 | } -------------------------------------------------------------------------------- /src/pass/accumulation/AccumulationPass.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | open StateType; 6 | 7 | let init = (device, swapChainFormat, state) => { 8 | let (resolutionBufferData, resolutionBuffer) = 9 | RTXBuffer.ResolutionBuffer.unsafeGetBufferData(state); 10 | let (pixelBufferSize, pixelBuffer) = 11 | RTXBuffer.PixelBuffer.unsafeGetBufferData(state); 12 | let (accumulationPixelBufferSize, accumulationPixelBuffer) = 13 | RTXBuffer.AccumulationPixelBuffer.unsafeGetBufferData(state); 14 | let (accumulationCommonDataBufferData, accumulationCommonDataBuffer) = 15 | RTXBuffer.AccumulationCommonDataBuffer.unsafeGetBufferData(state); 16 | 17 | let bindGroupLayout = 18 | device 19 | |> Device.createBindGroupLayout({ 20 | "entries": [| 21 | BindGroupLayout.layoutBinding( 22 | ~binding=0, 23 | ~visibility=ShaderStage.fragment, 24 | ~type_="storage-buffer", 25 | (), 26 | ), 27 | BindGroupLayout.layoutBinding( 28 | ~binding=1, 29 | ~visibility=ShaderStage.fragment, 30 | ~type_="storage-buffer", 31 | (), 32 | ), 33 | BindGroupLayout.layoutBinding( 34 | ~binding=2, 35 | ~visibility=ShaderStage.fragment, 36 | ~type_="uniform-buffer", 37 | (), 38 | ), 39 | BindGroupLayout.layoutBinding( 40 | ~binding=3, 41 | ~visibility=ShaderStage.fragment, 42 | ~type_="uniform-buffer", 43 | (), 44 | ), 45 | |], 46 | }); 47 | 48 | let bindGroup = 49 | device 50 | |> Device.createBindGroup({ 51 | "layout": bindGroupLayout, 52 | "entries": [| 53 | BindGroup.binding( 54 | ~binding=0, 55 | ~buffer=pixelBuffer, 56 | ~offset=0, 57 | ~size=pixelBufferSize, 58 | (), 59 | ), 60 | BindGroup.binding( 61 | ~binding=1, 62 | ~buffer=accumulationPixelBuffer, 63 | ~offset=0, 64 | ~size=accumulationPixelBufferSize, 65 | (), 66 | ), 67 | BindGroup.binding( 68 | ~binding=2, 69 | ~buffer=accumulationCommonDataBuffer, 70 | ~offset=0, 71 | ~size= 72 | RTXBuffer.AccumulationCommonDataBuffer.getBufferSize( 73 | accumulationCommonDataBufferData, 74 | ), 75 | (), 76 | ), 77 | BindGroup.binding( 78 | ~binding=3, 79 | ~buffer=resolutionBuffer, 80 | ~offset=0, 81 | ~size= 82 | RTXBuffer.ResolutionBuffer.getBufferSize( 83 | resolutionBufferData, 84 | ), 85 | (), 86 | ), 87 | |], 88 | }); 89 | 90 | let state = 91 | state |> Pass.AccumulationPass.setStaticBindGroupData(0, bindGroup); 92 | 93 | let baseShaderPath = "src/pass/accumulation/shaders"; 94 | 95 | let vertexShaderModule = 96 | device 97 | |> Device.createShaderModule({ 98 | "code": 99 | WebGPUUtils.loadShaderFile( 100 | {j|$(baseShaderPath)/accumulation.vert|j}, 101 | ), 102 | }); 103 | let fragmentShaderModule = 104 | device 105 | |> Device.createShaderModule({ 106 | "code": 107 | WebGPUUtils.loadShaderFile( 108 | {j|$(baseShaderPath)/accumulation.frag|j}, 109 | ), 110 | }); 111 | 112 | let pipeline = 113 | device 114 | |> Device.createRenderPipeline( 115 | Pipeline.Render.descriptor( 116 | ~layout= 117 | device 118 | |> Device.createPipelineLayout({ 119 | "bindGroupLayouts": [|bindGroupLayout|], 120 | }), 121 | ~vertexStage={ 122 | Pipeline.Render.vertexStage( 123 | ~module_=vertexShaderModule, 124 | ~entryPoint="main", 125 | ); 126 | }, 127 | ~fragmentStage={ 128 | Pipeline.Render.fragmentStage( 129 | ~module_=fragmentShaderModule, 130 | ~entryPoint="main", 131 | ); 132 | }, 133 | ~primitiveTopology="triangle-list", 134 | ~vertexState= 135 | Pipeline.Render.vertexState(~indexFormat="uint32", ()), 136 | ~rasterizationState=Pipeline.Render.rasterizationState(), 137 | ~colorStates=[| 138 | Pipeline.Render.colorState( 139 | ~format=swapChainFormat, 140 | ~alphaBlend=Pipeline.Render.blendDescriptor(), 141 | ~colorBlend=Pipeline.Render.blendDescriptor(), 142 | ), 143 | |], 144 | (), 145 | ), 146 | ); 147 | 148 | state |> Pass.AccumulationPass.setPipeline(pipeline); 149 | }; 150 | 151 | let execute = (device, queue, swapChain, state) => { 152 | let backBufferView = swapChain |> SwapChain.getCurrentTextureView(); 153 | 154 | let commandEncoder = 155 | device |> Device.createCommandEncoder(CommandEncoder.descriptor()); 156 | let renderPass = 157 | commandEncoder 158 | |> CommandEncoder.beginRenderPass( 159 | { 160 | PassEncoder.Render.descriptor( 161 | ~colorAttachments=[| 162 | { 163 | "clearColor": { 164 | "r": 0.0, 165 | "g": 0.0, 166 | "b": 0.0, 167 | "a": 1.0, 168 | }, 169 | "loadOp": "clear", 170 | "storeOp": "store", 171 | "attachment": backBufferView, 172 | }, 173 | |], 174 | (), 175 | ); 176 | }, 177 | ); 178 | 179 | let (staticBindGroupData, pipeline) = ( 180 | Pass.AccumulationPass.unsafeGetStaticBindGroupData(state), 181 | Pass.AccumulationPass.unsafeGetPipeline(state), 182 | ); 183 | 184 | renderPass |> PassEncoder.Render.setPipeline(pipeline); 185 | 186 | let {setSlot, bindGroup}: staticBindGroupData = staticBindGroupData; 187 | 188 | renderPass |> PassEncoder.Render.setBindGroup(setSlot, bindGroup); 189 | 190 | renderPass |> PassEncoder.Render.draw(3, 1, 0, 0); 191 | renderPass |> PassEncoder.Render.endPass; 192 | 193 | queue |> Queue.submit([|commandEncoder |> CommandEncoder.finish|]); 194 | 195 | state; 196 | }; 197 | -------------------------------------------------------------------------------- /src/pass/bmfr/regression/BMFRRegressionPass.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | open StateType; 6 | 7 | let init = (device, state) => { 8 | let (resolutionBufferData, resolutionBuffer) = 9 | RTXBuffer.ResolutionBuffer.unsafeGetBufferData(state); 10 | let (pixelBufferSize, pixelBuffer) = 11 | RTXBuffer.PixelBuffer.unsafeGetBufferData(state); 12 | let (tmpDataBufferSize, tmpDataBuffer) = 13 | RTXBuffer.Regression.TmpDataBuffer.unsafeGetBufferData(state); 14 | let (outDataBufferSize, outDataBuffer) = 15 | RTXBuffer.Regression.OutDataBuffer.unsafeGetBufferData(state); 16 | let (commonDataBufferData, commonDataBuffer) = 17 | RTXBuffer.Regression.CommonDataBuffer.unsafeGetBufferData(state); 18 | 19 | let gbufferBindGroupLayout = 20 | device 21 | |> Device.createBindGroupLayout({ 22 | "entries": [| 23 | BindGroupLayout.layoutBinding( 24 | ~binding=0, 25 | ~visibility=ShaderStage.compute, 26 | ~type_="sampler", 27 | (), 28 | ), 29 | BindGroupLayout.layoutBinding( 30 | ~binding=1, 31 | ~visibility=ShaderStage.compute, 32 | ~type_="sampled-texture", 33 | (), 34 | ), 35 | BindGroupLayout.layoutBinding( 36 | ~binding=2, 37 | ~visibility=ShaderStage.compute, 38 | ~type_="sampled-texture", 39 | (), 40 | ), 41 | BindGroupLayout.layoutBinding( 42 | ~binding=3, 43 | ~visibility=ShaderStage.compute, 44 | ~type_="sampled-texture", 45 | (), 46 | ), 47 | |], 48 | }); 49 | 50 | let otherBindGroupLayout = 51 | device 52 | |> Device.createBindGroupLayout({ 53 | "entries": [| 54 | BindGroupLayout.layoutBinding( 55 | ~binding=0, 56 | ~visibility=ShaderStage.compute, 57 | ~type_="storage-buffer", 58 | (), 59 | ), 60 | BindGroupLayout.layoutBinding( 61 | ~binding=1, 62 | ~visibility=ShaderStage.compute, 63 | ~type_="storage-buffer", 64 | (), 65 | ), 66 | BindGroupLayout.layoutBinding( 67 | ~binding=2, 68 | ~visibility=ShaderStage.compute, 69 | ~type_="storage-buffer", 70 | (), 71 | ), 72 | BindGroupLayout.layoutBinding( 73 | ~binding=3, 74 | ~visibility=ShaderStage.compute, 75 | ~type_="uniform-buffer", 76 | (), 77 | ), 78 | BindGroupLayout.layoutBinding( 79 | ~binding=4, 80 | ~visibility=ShaderStage.compute, 81 | ~type_="uniform-buffer", 82 | (), 83 | ), 84 | |], 85 | }); 86 | 87 | let gbufferBindGroup = 88 | device 89 | |> Device.createBindGroup({ 90 | "layout": gbufferBindGroupLayout, 91 | "entries": [| 92 | BindGroup.binding( 93 | ~binding=0, 94 | ~sampler=GBufferUtils.createLinearSampler(device), 95 | ~size=0, 96 | (), 97 | ), 98 | BindGroup.binding( 99 | ~binding=1, 100 | ~textureView= 101 | Pass.unsafeGetTextureView( 102 | "positionRoughnessRenderTargetView", 103 | state, 104 | ), 105 | ~size=0, 106 | (), 107 | ), 108 | BindGroup.binding( 109 | ~binding=2, 110 | ~textureView= 111 | Pass.unsafeGetTextureView( 112 | "normalMetalnessRenderTargetView", 113 | state, 114 | ), 115 | ~size=0, 116 | (), 117 | ), 118 | BindGroup.binding( 119 | ~binding=3, 120 | ~textureView= 121 | Pass.unsafeGetTextureView( 122 | "diffusePositionWRenderTargetView", 123 | state, 124 | ), 125 | ~size=0, 126 | (), 127 | ), 128 | |], 129 | }); 130 | 131 | let otherBindGroup = 132 | device 133 | |> Device.createBindGroup({ 134 | "layout": otherBindGroupLayout, 135 | "entries": [| 136 | BindGroup.binding( 137 | ~binding=0, 138 | ~buffer=pixelBuffer, 139 | ~offset=0, 140 | ~size=pixelBufferSize, 141 | (), 142 | ), 143 | BindGroup.binding( 144 | ~binding=1, 145 | ~buffer=tmpDataBuffer, 146 | ~offset=0, 147 | ~size=tmpDataBufferSize, 148 | (), 149 | ), 150 | BindGroup.binding( 151 | ~binding=2, 152 | ~buffer=outDataBuffer, 153 | ~offset=0, 154 | ~size=outDataBufferSize, 155 | (), 156 | ), 157 | BindGroup.binding( 158 | ~binding=3, 159 | ~buffer=resolutionBuffer, 160 | ~offset=0, 161 | ~size= 162 | RTXBuffer.ResolutionBuffer.getBufferSize( 163 | resolutionBufferData, 164 | ), 165 | (), 166 | ), 167 | BindGroup.binding( 168 | ~binding=4, 169 | ~buffer=commonDataBuffer, 170 | ~offset=0, 171 | ~size= 172 | RTXBuffer.Regression.CommonDataBuffer.getBufferSize( 173 | commonDataBufferData, 174 | ), 175 | (), 176 | ), 177 | |], 178 | }); 179 | 180 | let state = 181 | state 182 | |> Pass.RegressionPass.addStaticBindGroupData(0, gbufferBindGroup) 183 | |> Pass.RegressionPass.addStaticBindGroupData(1, otherBindGroup); 184 | 185 | let baseShaderPath = "src/pass/bmfr/regression/shaders"; 186 | 187 | let computeShaderModule = 188 | device 189 | |> Device.createShaderModule({ 190 | "code": 191 | WebGPUUtils.loadShaderFile( 192 | {j|$(baseShaderPath)/regression.comp|j}, 193 | ), 194 | }); 195 | 196 | let pipeline = 197 | device 198 | |> Device.createComputePipeline( 199 | Pipeline.Compute.descriptor( 200 | ~layout= 201 | device 202 | |> Device.createPipelineLayout({ 203 | "bindGroupLayouts": [| 204 | gbufferBindGroupLayout, 205 | otherBindGroupLayout, 206 | |], 207 | }), 208 | ~computeStage={ 209 | Pipeline.Compute.computeStage( 210 | ~module_=computeShaderModule, 211 | ~entryPoint="main", 212 | ); 213 | }, 214 | ), 215 | ); 216 | 217 | state |> Pass.RegressionPass.setPipeline(pipeline); 218 | }; 219 | 220 | let execute = (device, queue, window, state) => { 221 | Pass.AccumulationPass.canDenoise(state) 222 | ? { 223 | Log.log("denoise"); 224 | 225 | let commandEncoder = 226 | device |> Device.createCommandEncoder(CommandEncoder.descriptor()); 227 | let renderPass = 228 | commandEncoder 229 | |> CommandEncoder.beginComputePass( 230 | { 231 | PassEncoder.Compute.descriptor(); 232 | }, 233 | ); 234 | 235 | let (staticBindGroupDataArr, pipeline) = ( 236 | Pass.RegressionPass.getStaticBindGroupDataArr(state), 237 | Pass.RegressionPass.unsafeGetPipeline(state), 238 | ); 239 | 240 | renderPass |> PassEncoder.Compute.setPipeline(pipeline); 241 | 242 | staticBindGroupDataArr 243 | |> Js.Array.forEach(({setSlot, bindGroup}: staticBindGroupData) => { 244 | renderPass |> PassEncoder.Compute.setBindGroup(setSlot, bindGroup) 245 | }); 246 | 247 | let w = RTXBuffer.Regression.computeHorizentalBlocksCount(window); 248 | let h = RTXBuffer.Regression.computeVerticalBlocksCount(window); 249 | renderPass |> PassEncoder.Compute.dispatchX(w * h); 250 | renderPass |> PassEncoder.Compute.endPass; 251 | 252 | queue |> Queue.submit([|commandEncoder |> CommandEncoder.finish|]); 253 | 254 | state; 255 | } 256 | : { 257 | state; 258 | }; 259 | }; 260 | -------------------------------------------------------------------------------- /src/pass/bmfr/preprocess/shaders/preprocess.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_EXT_nonuniform_qualifier : enable 3 | #extension GL_EXT_scalar_block_layout : enable 4 | #pragma shader_stage(fragment) 5 | 6 | #define POSITION_LIMIT_SQUARED 0.01f 7 | #define NORMAL_LIMIT_SQUARED 1.0f 8 | #define BLEND_ALPHA 0.2f 9 | #define PIXEL_OFFSET 0.5f 10 | 11 | #include "../../../shaders/common_data.glsl" 12 | #include "../../../shaders/utils.glsl" 13 | #include "../../shaders/utils.glsl" 14 | 15 | layout(location = 0) in vec2 uv; 16 | // layout(location = 0) out vec4 outColor; 17 | 18 | layout(binding = 0) uniform sampler2D gPositionRoughnessTexture; 19 | layout(binding = 1) uniform sampler2D gNormalMetalnessTexture; 20 | layout(binding = 2) uniform sampler2D gMotionVectorDepthSpecularTexture; 21 | layout(binding = 3) uniform sampler2D gDiffusePositionWTexture; 22 | 23 | layout(std140, set = 1, binding = 0) buffer CurNoisyPixelBuffer { 24 | vec4 pixels[]; 25 | } 26 | curNoisyPixelBuffer; 27 | layout(std140, set = 1, binding = 1) buffer PrevNoisyPixelBuffer { 28 | vec4 pixels[]; 29 | } 30 | prevNoisyPixelBuffer; 31 | 32 | layout(std140, set = 1, binding = 2) buffer PrevPositionBuffer { 33 | // vec3 positions[]; 34 | vec4 positions[]; 35 | } 36 | prevPositionBuffer; 37 | 38 | layout(std140, set = 1, binding = 3) buffer PrevNormalBuffer { 39 | // vec3 normals[]; 40 | vec4 normals[]; 41 | } 42 | prevNormalBuffer; 43 | 44 | layout(scalar, set = 1, binding = 4) buffer AcceptBoolBuffer { 45 | uint acceptBools[]; 46 | } 47 | acceptBoolBuffer; 48 | 49 | layout(scalar, set = 1, binding = 5) buffer PrevFramePixelIndicesBuffer { 50 | vec2 prevFramePixelIndices[]; 51 | } 52 | prevFramePixelIndicesBuffer; 53 | 54 | layout(set = 1, binding = 6) uniform ScreenDimension { vec2 resolution; } 55 | screenDimension; 56 | 57 | layout(std140, set = 1, binding = 7) uniform CommonData { vec4 compressedData; } 58 | pushC; 59 | 60 | vec2 convertUVToPixelIndices(vec2 uv, vec2 resolution) { 61 | return uv * resolution; 62 | } 63 | 64 | uint convertPixelIndicesToPixelIndex(ivec2 pixelIndices, vec2 resolution) { 65 | return convertBufferTwoDIndexToOneDIndex(pixelIndices.x, pixelIndices.y, 66 | uint(resolution.x)); 67 | } 68 | 69 | // TODO refactor: extract first frame shader 70 | void main() { 71 | vec4 commonDataCompressedData = pushC.compressedData; 72 | uint frame = getFrame(commonDataCompressedData); 73 | 74 | vec3 worldPosition = texture(gPositionRoughnessTexture, uv).xyz; 75 | vec3 worldNormal = texture(gNormalMetalnessTexture, uv).xyz; 76 | 77 | uint pixelIndex = getPixelIndex(uv, screenDimension.resolution); 78 | 79 | vec3 currentColor = curNoisyPixelBuffer.pixels[pixelIndex].rgb; 80 | 81 | vec3 diffuse = texture(gDiffusePositionWTexture, uv).xyz; 82 | 83 | currentColor = demodulateAlbedo(currentColor, diffuse); 84 | 85 | // Default previous frame pixel is the same pixel 86 | vec2 prevFramePixelIndicesFloat = 87 | convertUVToPixelIndices(uv, screenDimension.resolution); 88 | 89 | // Change this to non zero if previous frame is not discarded completely 90 | uint storeAccept = 0x00; 91 | 92 | // blendAlpha 1.f means that only current frame color is used 93 | // The value is changed if sample from previous frame can be used 94 | float blendAlpha = 1.0; 95 | vec3 previousColor = vec3(0.0, 0.0, 0.0); 96 | 97 | float sampleSpp = 0.0; 98 | float totalWeight = 0.0; 99 | 100 | if (frame > 0) { 101 | // TODO getClosestMotionVector? 102 | vec2 motionVector = texture(gMotionVectorDepthSpecularTexture, uv).xy; 103 | 104 | float positionLimitSquared = POSITION_LIMIT_SQUARED; 105 | float normalLimitSquared = NORMAL_LIMIT_SQUARED; 106 | 107 | /* TODO optimize: reduce noise when move camera/gameObject and avoid ghost 108 | too! 109 | 110 | solution: 111 | 1.change limit when move 112 | 2.add more check 113 | e.g. 114 | 所以我们在做Sample 115 | Reprojection的时候需要check当前帧的纹理颜色,世界坐标位置,法线,模型索引,屏幕空间深度等,去尽可能的丢弃无效的历史样本。 116 | float positionLimitSquared = POSITION_LIMIT_SQUARED; 117 | float normalLimitSquared = NORMAL_LIMIT_SQUARED; 118 | float lenMotionVector = length(motionVector); 119 | const float b1 = 0.01; 120 | const float b2 = 1.00; 121 | const float velocityScale = 100.0 * 60.0; 122 | float positionLimitSquared = 123 | mix(b1, b2, saturateFloat(lenMotionVector * velocityScale)); 124 | */ 125 | 126 | vec2 prevFrameUnJitteredUV = uv - motionVector; 127 | 128 | if (prevFrameUnJitteredUV.x > 1.0 || prevFrameUnJitteredUV.x < 0.0 || 129 | prevFrameUnJitteredUV.y > 1.0 || prevFrameUnJitteredUV.y < 0.0) { 130 | // change spp to 1 131 | curNoisyPixelBuffer.pixels[pixelIndex] = vec4(currentColor, 1.0); 132 | acceptBoolBuffer.acceptBools[pixelIndex] = 0; 133 | 134 | // outColor = vec4(currentColor, 1.0); 135 | 136 | return; 137 | } 138 | 139 | prevFramePixelIndicesFloat = convertUVToPixelIndices( 140 | prevFrameUnJitteredUV, screenDimension.resolution); 141 | 142 | prevFramePixelIndicesFloat -= vec2(PIXEL_OFFSET, PIXEL_OFFSET); 143 | 144 | ivec2 prevFramePixelIndicesInt = ivec2(prevFramePixelIndicesFloat); 145 | 146 | // These are needed for the bilinear sampling 147 | ivec2 offsets[4] = { 148 | ivec2(0, 0), 149 | ivec2(1, 0), 150 | ivec2(0, 1), 151 | ivec2(1, 1), 152 | }; 153 | 154 | vec2 prevPixelFract = 155 | prevFramePixelIndicesFloat - vec2(prevFramePixelIndicesInt); 156 | 157 | vec2 oneMinusPrevPixelFract = 1.0 - prevPixelFract; 158 | float weights[4]; 159 | 160 | weights[0] = oneMinusPrevPixelFract.x * oneMinusPrevPixelFract.y; 161 | weights[1] = prevPixelFract.x * oneMinusPrevPixelFract.y; 162 | weights[2] = oneMinusPrevPixelFract.x * prevPixelFract.y; 163 | weights[3] = prevPixelFract.x * prevPixelFract.y; 164 | totalWeight = 0.0; 165 | 166 | // Bilinear sampling 167 | for (int i = 0; i < 4; ++i) { 168 | ivec2 sampleLocation = prevFramePixelIndicesInt + offsets[i]; 169 | 170 | uint samplePixelIndex = convertPixelIndicesToPixelIndex( 171 | sampleLocation, screenDimension.resolution); 172 | 173 | // Check if previous frame color can be used based on its screen location 174 | if (sampleLocation.x >= 0 && sampleLocation.y >= 0 && 175 | sampleLocation.x < screenDimension.resolution.x && 176 | sampleLocation.y < screenDimension.resolution.y) { 177 | vec3 prevWorldPosition = 178 | vec3(prevPositionBuffer.positions[samplePixelIndex]); 179 | 180 | // Compute world distance squared 181 | vec3 positionDifference = prevWorldPosition - worldPosition; 182 | float positionDistanceSquared = 183 | dot(positionDifference, positionDifference); 184 | 185 | // World position distance discard 186 | if (positionDistanceSquared < positionLimitSquared) { 187 | 188 | vec3 prevWorldNormal = 189 | vec3(prevNormalBuffer.normals[samplePixelIndex]); 190 | 191 | // Distance of the normals 192 | // NOTE: could use some other distance metric (e.g. angle), but we use 193 | // hard experimentally found threshold -> means that the metric 194 | // doesn't matter. 195 | vec3 normalDifference = prevWorldNormal - worldNormal; 196 | float normalDistanceSquared = dot(normalDifference, normalDifference); 197 | 198 | // Normal distance discard 199 | if (normalDistanceSquared < normalLimitSquared) { 200 | // Pixel passes all tests so store it to accept bools 201 | storeAccept |= 1 << i; 202 | vec4 prevData = prevNoisyPixelBuffer.pixels[samplePixelIndex]; 203 | 204 | sampleSpp += weights[i] * prevData.w; 205 | 206 | previousColor += weights[i] * prevData.xyz; 207 | totalWeight += weights[i]; 208 | } 209 | } 210 | } 211 | } 212 | 213 | if (totalWeight > 0.0) { 214 | 215 | previousColor /= totalWeight; 216 | sampleSpp /= totalWeight; 217 | // Blend_alpha is dymically decided so that the result is average of all 218 | // samples until the cap defined by BLEND_ALPHA is reached 219 | blendAlpha = 1.0 / (sampleSpp + 1.f); 220 | blendAlpha = max(blendAlpha, BLEND_ALPHA); 221 | } 222 | } 223 | 224 | float newSpp = 1.0; 225 | if (blendAlpha < 1.0) { 226 | newSpp += sampleSpp; 227 | } 228 | 229 | vec3 newColor = mix(previousColor, currentColor, blendAlpha); 230 | 231 | curNoisyPixelBuffer.pixels[pixelIndex] = vec4(newColor, newSpp); 232 | acceptBoolBuffer.acceptBools[pixelIndex] = storeAccept; 233 | prevFramePixelIndicesBuffer.prevFramePixelIndices[pixelIndex] = 234 | prevFramePixelIndicesFloat; 235 | 236 | prevNoisyPixelBuffer.pixels[pixelIndex] = vec4(newColor, newSpp); 237 | prevPositionBuffer.positions[pixelIndex] = vec4(worldPosition, 0.0); 238 | prevNormalBuffer.normals[pixelIndex] = vec4(worldNormal, 0.0); 239 | 240 | // outColor = vec4(newColor, 1.0); 241 | } -------------------------------------------------------------------------------- /src/pass/bmfr/postprocess/shaders/postprocess.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_EXT_nonuniform_qualifier : enable 3 | #extension GL_EXT_scalar_block_layout : enable 4 | #pragma shader_stage(fragment) 5 | 6 | /* TODO fix: when move camera, the noise increase! 7 | 8 | description 9 | when move camera, the noise increase; 10 | when stop moving camera, the noise decrease; 11 | 12 | reason 13 | because when move camera, postprocess pass has many noise!!! 14 | 15 | 16 | solution 17 | increase POSITION_LIMIT_SQUARED,NORMAL_LIMIT_SQUARED when move can decrease 18 | noise, but cause more ghost!!! 19 | 20 | so need other solutions!!! 21 | */ 22 | 23 | #define POSITION_LIMIT_SQUARED 0.01f 24 | #define NORMAL_LIMIT_SQUARED 1.0f 25 | #define BLEND_ALPHA 0.1f 26 | #define PIXEL_OFFSET 0.5f 27 | 28 | #include "../../../shaders/common_data.glsl" 29 | #include "../../../shaders/utils.glsl" 30 | #include "../../shaders/utils.glsl" 31 | 32 | layout(location = 0) in vec2 uv; 33 | // layout(location = 0) out vec4 outColor; 34 | 35 | layout(binding = 0) uniform sampler sampler0; 36 | layout(binding = 1) uniform texture2D gPositionRoughnessTexture; 37 | layout(binding = 2) uniform texture2D gNormalMetalnessTexture; 38 | layout(binding = 3) uniform texture2D gMotionVectorDepthSpecularTexture; 39 | 40 | layout(std140, set = 1, binding = 0) buffer CurNoisyPixelBuffer { 41 | vec4 pixels[]; 42 | } 43 | curNoisyPixelBuffer; 44 | layout(std140, set = 1, binding = 1) buffer PrevNoisyPixelBuffer { 45 | vec4 pixels[]; 46 | } 47 | prevNoisyPixelBuffer; 48 | 49 | layout(std140, set = 1, binding = 2) buffer PrevPositionBuffer { 50 | // vec3 positions[]; 51 | vec4 positions[]; 52 | } 53 | prevPositionBuffer; 54 | 55 | layout(std140, set = 1, binding = 3) buffer PrevNormalBuffer { 56 | // vec3 normals[]; 57 | vec4 normals[]; 58 | } 59 | prevNormalBuffer; 60 | 61 | // layout(scalar, set = 1, binding = 4) buffer AcceptBoolBuffer { 62 | // uint acceptBools[]; 63 | // } 64 | // acceptBoolBuffer; 65 | 66 | // layout(scalar, set = 1, binding = 5) buffer PrevFramePixelIndicesBuffer { 67 | // vec2 prevFramePixelIndices[]; 68 | // } 69 | // prevFramePixelIndicesBuffer; 70 | 71 | layout(set = 1, binding = 4) uniform ScreenDimension { vec2 resolution; } 72 | screenDimension; 73 | 74 | layout(std140, set = 1, binding = 5) uniform CommonData { vec4 compressedData; } 75 | pushC; 76 | 77 | vec2 convertUVToPixelIndices(vec2 uv, vec2 resolution) { 78 | return uv * resolution; 79 | } 80 | 81 | uint convertPixelIndicesToPixelIndex(ivec2 pixelIndices, vec2 resolution) { 82 | return convertBufferTwoDIndexToOneDIndex(pixelIndices.x, pixelIndices.y, 83 | uint(resolution.x)); 84 | } 85 | 86 | // TODO refactor: extract first frame shader 87 | void main() { 88 | vec4 commonDataCompressedData = pushC.compressedData; 89 | uint frame = getFrame(commonDataCompressedData); 90 | 91 | vec3 worldPosition = 92 | texture(sampler2D(gPositionRoughnessTexture, sampler0), uv).xyz; 93 | vec3 worldNormal = 94 | texture(sampler2D(gNormalMetalnessTexture, sampler0), uv).xyz; 95 | 96 | uint pixelIndex = getPixelIndex(uv, screenDimension.resolution); 97 | 98 | vec3 currentColor = curNoisyPixelBuffer.pixels[pixelIndex].rgb; 99 | 100 | // Default previous frame pixel is the same pixel 101 | vec2 prevFramePixelIndicesFloat = 102 | convertUVToPixelIndices(uv, screenDimension.resolution); 103 | 104 | // // Change this to non zero if previous frame is not discarded completely 105 | // uint storeAccept = 0x00; 106 | 107 | // blendAlpha 1.f means that only current frame color is used 108 | // The value is changed if sample from previous frame can be used 109 | float blendAlpha = 1.0; 110 | vec3 previousColor = vec3(0.0, 0.0, 0.0); 111 | 112 | float sampleSpp = 0.0; 113 | float totalWeight = 0.0; 114 | 115 | if (frame > 0) { 116 | // TODO getClosestMotionVector? 117 | vec2 motionVector = 118 | texture(sampler2D(gMotionVectorDepthSpecularTexture, sampler0), uv).xy; 119 | 120 | float positionLimitSquared = POSITION_LIMIT_SQUARED; 121 | float normalLimitSquared = NORMAL_LIMIT_SQUARED; 122 | 123 | /* TODO optimize: reduce noise when move camera/gameObject and avoid ghost 124 | too! 125 | 126 | solution: 127 | 1.change limit when move 128 | 2.add more check 129 | e.g. 130 | 所以我们在做Sample 131 | Reprojection的时候需要check当前帧的纹理颜色,世界坐标位置,法线,模型索引,屏幕空间深度等,去尽可能的丢弃无效的历史样本。 132 | float positionLimitSquared = POSITION_LIMIT_SQUARED; 133 | float normalLimitSquared = NORMAL_LIMIT_SQUARED; 134 | float lenMotionVector = length(motionVector); 135 | const float b1 = 0.01; 136 | const float b2 = 1.00; 137 | const float velocityScale = 100.0 * 60.0; 138 | float positionLimitSquared = 139 | mix(b1, b2, saturateFloat(lenMotionVector * velocityScale)); 140 | */ 141 | 142 | vec2 prevFrameUnJitteredUV = uv - motionVector; 143 | 144 | if (prevFrameUnJitteredUV.x > 1.0 || prevFrameUnJitteredUV.x < 0.0 || 145 | prevFrameUnJitteredUV.y > 1.0 || prevFrameUnJitteredUV.y < 0.0) { 146 | // change spp to 1 147 | curNoisyPixelBuffer.pixels[pixelIndex] = vec4(currentColor, 1.0); 148 | // acceptBoolBuffer.acceptBools[pixelIndex] = 0; 149 | 150 | // outColor = vec4(currentColor, 1.0); 151 | 152 | return; 153 | } 154 | 155 | prevFramePixelIndicesFloat = convertUVToPixelIndices( 156 | prevFrameUnJitteredUV, screenDimension.resolution); 157 | 158 | prevFramePixelIndicesFloat -= vec2(PIXEL_OFFSET, PIXEL_OFFSET); 159 | 160 | ivec2 prevFramePixelIndicesInt = ivec2(prevFramePixelIndicesFloat); 161 | 162 | // These are needed for the bilinear sampling 163 | ivec2 offsets[4] = { 164 | ivec2(0, 0), 165 | ivec2(1, 0), 166 | ivec2(0, 1), 167 | ivec2(1, 1), 168 | }; 169 | 170 | vec2 prevPixelFract = 171 | prevFramePixelIndicesFloat - vec2(prevFramePixelIndicesInt); 172 | 173 | vec2 oneMinusPrevPixelFract = 1.0 - prevPixelFract; 174 | float weights[4]; 175 | 176 | weights[0] = oneMinusPrevPixelFract.x * oneMinusPrevPixelFract.y; 177 | weights[1] = prevPixelFract.x * oneMinusPrevPixelFract.y; 178 | weights[2] = oneMinusPrevPixelFract.x * prevPixelFract.y; 179 | weights[3] = prevPixelFract.x * prevPixelFract.y; 180 | totalWeight = 0.0; 181 | 182 | // Bilinear sampling 183 | for (int i = 0; i < 4; ++i) { 184 | ivec2 sampleLocation = prevFramePixelIndicesInt + offsets[i]; 185 | 186 | uint samplePixelIndex = convertPixelIndicesToPixelIndex( 187 | sampleLocation, screenDimension.resolution); 188 | 189 | // Check if previous frame color can be used based on its screen location 190 | if (sampleLocation.x >= 0 && sampleLocation.y >= 0 && 191 | sampleLocation.x < screenDimension.resolution.x && 192 | sampleLocation.y < screenDimension.resolution.y) { 193 | vec3 prevWorldPosition = 194 | vec3(prevPositionBuffer.positions[samplePixelIndex]); 195 | 196 | // Compute world distance squared 197 | vec3 positionDifference = prevWorldPosition - worldPosition; 198 | float positionDistanceSquared = 199 | dot(positionDifference, positionDifference); 200 | 201 | // World position distance discard 202 | if (positionDistanceSquared < positionLimitSquared) { 203 | 204 | vec3 prevWorldNormal = 205 | vec3(prevNormalBuffer.normals[samplePixelIndex]); 206 | 207 | // Distance of the normals 208 | // NOTE: could use some other distance metric (e.g. angle), but we use 209 | // hard experimentally found threshold -> means that the metric 210 | // doesn't matter. 211 | vec3 normalDifference = prevWorldNormal - worldNormal; 212 | float normalDistanceSquared = dot(normalDifference, normalDifference); 213 | 214 | // Normal distance discard 215 | if (normalDistanceSquared < normalLimitSquared) { 216 | // Pixel passes all tests so store it to accept bools 217 | // storeAccept |= 1 << i; 218 | vec4 prevData = prevNoisyPixelBuffer.pixels[samplePixelIndex]; 219 | 220 | sampleSpp += weights[i] * prevData.w; 221 | 222 | previousColor += weights[i] * prevData.xyz; 223 | totalWeight += weights[i]; 224 | } 225 | } 226 | } 227 | } 228 | 229 | if (totalWeight > 0.0) { 230 | 231 | previousColor /= totalWeight; 232 | sampleSpp /= totalWeight; 233 | // Blend_alpha is dymically decided so that the result is average of all 234 | // samples until the cap defined by BLEND_ALPHA is reached 235 | blendAlpha = 1.0 / (sampleSpp + 1.f); 236 | blendAlpha = max(blendAlpha, BLEND_ALPHA); 237 | } 238 | } 239 | 240 | float newSpp = 1.0; 241 | if (blendAlpha < 1.0) { 242 | newSpp += sampleSpp; 243 | } 244 | 245 | vec3 newColor = mix(previousColor, currentColor, blendAlpha); 246 | 247 | curNoisyPixelBuffer.pixels[pixelIndex] = vec4(newColor, newSpp); 248 | // acceptBoolBuffer.acceptBools[pixelIndex] = storeAccept; 249 | // prevFramePixelIndicesBuffer.prevFramePixelIndices[pixelIndex] = 250 | // prevFramePixelIndicesFloat; 251 | 252 | prevNoisyPixelBuffer.pixels[pixelIndex] = vec4(newColor, newSpp); 253 | prevPositionBuffer.positions[pixelIndex] = vec4(worldPosition, 0.0); 254 | prevNormalBuffer.normals[pixelIndex] = vec4(worldNormal, 0.0); 255 | 256 | // outColor = vec4(newColor, 1.0); 257 | } -------------------------------------------------------------------------------- /src/pass/bmfr/postprocess/BMFRPostprocessPass.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | open StateType; 6 | 7 | let init = (device, swapChainFormat, state) => { 8 | let (resolutionBufferData, resolutionBuffer) = 9 | RTXBuffer.ResolutionBuffer.unsafeGetBufferData(state); 10 | let (pixelBufferSize, pixelBuffer) = 11 | RTXBuffer.PixelBuffer.unsafeGetBufferData(state); 12 | let (prevNoisyPixelBufferSize, prevNoisyPixelBuffer) = 13 | RTXBuffer.PrevNoisyPixelBuffer.unsafeGetBufferData(state); 14 | let (prevPositionBufferSize, prevPositionBuffer) = 15 | RTXBuffer.PrevPositionBuffer.unsafeGetBufferData(state); 16 | let (prevNormalBufferSize, prevNormalBuffer) = 17 | RTXBuffer.PrevNormalBuffer.unsafeGetBufferData(state); 18 | let (commonDataBufferData, commonDataBuffer) = 19 | RTXBuffer.CommonDataBuffer.unsafeGetBufferData(state); 20 | 21 | let gbufferBindGroupLayout = 22 | device 23 | |> Device.createBindGroupLayout({ 24 | "entries": [| 25 | BindGroupLayout.layoutBinding( 26 | ~binding=0, 27 | ~visibility=ShaderStage.fragment, 28 | ~type_="sampler", 29 | (), 30 | ), 31 | BindGroupLayout.layoutBinding( 32 | ~binding=1, 33 | ~visibility=ShaderStage.fragment, 34 | ~type_="sampled-texture", 35 | (), 36 | ), 37 | BindGroupLayout.layoutBinding( 38 | ~binding=2, 39 | ~visibility=ShaderStage.fragment, 40 | ~type_="sampled-texture", 41 | (), 42 | ), 43 | BindGroupLayout.layoutBinding( 44 | ~binding=3, 45 | ~visibility=ShaderStage.fragment, 46 | ~type_="sampled-texture", 47 | (), 48 | ), 49 | |], 50 | }); 51 | 52 | let otherBindGroupLayout = 53 | device 54 | |> Device.createBindGroupLayout({ 55 | "entries": [| 56 | BindGroupLayout.layoutBinding( 57 | ~binding=0, 58 | ~visibility=ShaderStage.fragment, 59 | ~type_="storage-buffer", 60 | (), 61 | ), 62 | BindGroupLayout.layoutBinding( 63 | ~binding=1, 64 | ~visibility=ShaderStage.fragment, 65 | ~type_="storage-buffer", 66 | (), 67 | ), 68 | BindGroupLayout.layoutBinding( 69 | ~binding=2, 70 | ~visibility=ShaderStage.fragment, 71 | ~type_="storage-buffer", 72 | (), 73 | ), 74 | BindGroupLayout.layoutBinding( 75 | ~binding=3, 76 | ~visibility=ShaderStage.fragment, 77 | ~type_="storage-buffer", 78 | (), 79 | ), 80 | BindGroupLayout.layoutBinding( 81 | ~binding=4, 82 | ~visibility=ShaderStage.fragment, 83 | ~type_="uniform-buffer", 84 | (), 85 | ), 86 | BindGroupLayout.layoutBinding( 87 | ~binding=5, 88 | ~visibility=ShaderStage.fragment, 89 | ~type_="uniform-buffer", 90 | (), 91 | ), 92 | |], 93 | }); 94 | 95 | let gbufferBindGroup = 96 | device 97 | |> Device.createBindGroup({ 98 | "layout": gbufferBindGroupLayout, 99 | "entries": [| 100 | BindGroup.binding( 101 | ~binding=0, 102 | ~sampler=GBufferUtils.createLinearSampler(device), 103 | ~size=0, 104 | (), 105 | ), 106 | BindGroup.binding( 107 | ~binding=1, 108 | ~textureView= 109 | Pass.unsafeGetTextureView( 110 | "positionRoughnessRenderTargetView", 111 | state, 112 | ), 113 | ~size=0, 114 | (), 115 | ), 116 | BindGroup.binding( 117 | ~binding=2, 118 | ~textureView= 119 | Pass.unsafeGetTextureView( 120 | "normalMetalnessRenderTargetView", 121 | state, 122 | ), 123 | ~size=0, 124 | (), 125 | ), 126 | BindGroup.binding( 127 | ~binding=3, 128 | ~textureView= 129 | Pass.unsafeGetTextureView( 130 | "motionVectorDepthSpecularRenderTargetView", 131 | state, 132 | ), 133 | ~size=0, 134 | (), 135 | ), 136 | |], 137 | }); 138 | 139 | let otherBindGroup = 140 | device 141 | |> Device.createBindGroup({ 142 | "layout": otherBindGroupLayout, 143 | "entries": [| 144 | BindGroup.binding( 145 | ~binding=0, 146 | ~buffer=pixelBuffer, 147 | ~offset=0, 148 | ~size=pixelBufferSize, 149 | (), 150 | ), 151 | BindGroup.binding( 152 | ~binding=1, 153 | ~buffer=prevNoisyPixelBuffer, 154 | ~offset=0, 155 | ~size=prevNoisyPixelBufferSize, 156 | (), 157 | ), 158 | BindGroup.binding( 159 | ~binding=2, 160 | ~buffer=prevPositionBuffer, 161 | ~offset=0, 162 | ~size=prevPositionBufferSize, 163 | (), 164 | ), 165 | BindGroup.binding( 166 | ~binding=3, 167 | ~buffer=prevNormalBuffer, 168 | ~offset=0, 169 | ~size=prevNormalBufferSize, 170 | (), 171 | ), 172 | BindGroup.binding( 173 | ~binding=4, 174 | ~buffer=resolutionBuffer, 175 | ~offset=0, 176 | ~size= 177 | RTXBuffer.ResolutionBuffer.getBufferSize( 178 | resolutionBufferData, 179 | ), 180 | (), 181 | ), 182 | BindGroup.binding( 183 | ~binding=5, 184 | ~buffer=commonDataBuffer, 185 | ~offset=0, 186 | ~size= 187 | RTXBuffer.CommonDataBuffer.getBufferSize( 188 | commonDataBufferData, 189 | ), 190 | (), 191 | ), 192 | |], 193 | }); 194 | 195 | let state = 196 | state 197 | |> Pass.PostprocessPass.addStaticBindGroupData(0, gbufferBindGroup) 198 | |> Pass.PostprocessPass.addStaticBindGroupData(1, otherBindGroup); 199 | 200 | let baseShaderPath = "src/pass/bmfr/postprocess/shaders"; 201 | 202 | let vertexShaderModule = 203 | device 204 | |> Device.createShaderModule({ 205 | "code": 206 | WebGPUUtils.loadShaderFile( 207 | {j|$(baseShaderPath)/postprocess.vert|j}, 208 | ), 209 | }); 210 | let fragmentShaderModule = 211 | device 212 | |> Device.createShaderModule({ 213 | "code": 214 | WebGPUUtils.loadShaderFile( 215 | {j|$(baseShaderPath)/postprocess.frag|j}, 216 | ), 217 | }); 218 | 219 | let pipeline = 220 | device 221 | |> Device.createRenderPipeline( 222 | Pipeline.Render.descriptor( 223 | ~layout= 224 | device 225 | |> Device.createPipelineLayout({ 226 | "bindGroupLayouts": [| 227 | gbufferBindGroupLayout, 228 | otherBindGroupLayout, 229 | |], 230 | }), 231 | ~vertexStage={ 232 | Pipeline.Render.vertexStage( 233 | ~module_=vertexShaderModule, 234 | ~entryPoint="main", 235 | ); 236 | }, 237 | ~fragmentStage={ 238 | Pipeline.Render.fragmentStage( 239 | ~module_=fragmentShaderModule, 240 | ~entryPoint="main", 241 | ); 242 | }, 243 | ~primitiveTopology="triangle-list", 244 | ~vertexState= 245 | Pipeline.Render.vertexState(~indexFormat="uint32", ()), 246 | ~rasterizationState=Pipeline.Render.rasterizationState(), 247 | ~colorStates=[| 248 | Pipeline.Render.colorState( 249 | ~format=swapChainFormat, 250 | ~alphaBlend=Pipeline.Render.blendDescriptor(), 251 | ~colorBlend=Pipeline.Render.blendDescriptor(), 252 | ), 253 | |], 254 | (), 255 | ), 256 | ); 257 | 258 | state |> Pass.PostprocessPass.setPipeline(pipeline); 259 | }; 260 | 261 | let execute = (device, queue, swapChain, state) => { 262 | Pass.AccumulationPass.canDenoise(state) 263 | ? { 264 | let backBufferView = swapChain |> SwapChain.getCurrentTextureView(); 265 | 266 | let commandEncoder = 267 | device |> Device.createCommandEncoder(CommandEncoder.descriptor()); 268 | let renderPass = 269 | commandEncoder 270 | |> CommandEncoder.beginRenderPass( 271 | { 272 | PassEncoder.Render.descriptor( 273 | ~colorAttachments=[| 274 | { 275 | "clearColor": { 276 | "r": 0.0, 277 | "g": 0.0, 278 | "b": 0.0, 279 | "a": 1.0, 280 | }, 281 | "loadOp": "clear", 282 | "storeOp": "store", 283 | "attachment": backBufferView, 284 | }, 285 | |], 286 | (), 287 | ); 288 | }, 289 | ); 290 | 291 | let (staticBindGroupDataArr, pipeline) = ( 292 | Pass.PostprocessPass.getStaticBindGroupDataArr(state), 293 | Pass.PostprocessPass.unsafeGetPipeline(state), 294 | ); 295 | 296 | renderPass |> PassEncoder.Render.setPipeline(pipeline); 297 | 298 | staticBindGroupDataArr 299 | |> Js.Array.forEach(({setSlot, bindGroup}: staticBindGroupData) => { 300 | renderPass |> PassEncoder.Render.setBindGroup(setSlot, bindGroup) 301 | }); 302 | 303 | renderPass |> PassEncoder.Render.draw(3, 1, 0, 0); 304 | renderPass |> PassEncoder.Render.endPass; 305 | 306 | queue |> Queue.submit([|commandEncoder |> CommandEncoder.finish|]); 307 | 308 | state; 309 | } 310 | : { 311 | state; 312 | }; 313 | }; 314 | -------------------------------------------------------------------------------- /src/pass/taa/TAAPass.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | open StateType; 6 | 7 | let _initFrameData = 8 | ( 9 | device, 10 | swapChainFormat, 11 | ( 12 | (resolutionBufferSize, resolutionBuffer), 13 | (pixelBufferSize, pixelBuffer), 14 | (historyPixelBufferSize, historyPixelBuffer), 15 | (taaBufferSize, taaBuffer), 16 | ), 17 | (fragmentShaderName, addStaticBindGroupDataFunc, setPipelineFunc), 18 | state, 19 | ) => { 20 | let gbufferBindGroupLayout = 21 | device 22 | |> Device.createBindGroupLayout({ 23 | "entries": [| 24 | BindGroupLayout.layoutBinding( 25 | ~binding=0, 26 | ~visibility=ShaderStage.fragment, 27 | ~type_="sampler", 28 | (), 29 | ), 30 | BindGroupLayout.layoutBinding( 31 | ~binding=1, 32 | ~visibility=ShaderStage.fragment, 33 | ~type_="sampled-texture", 34 | (), 35 | ), 36 | |], 37 | }); 38 | 39 | let otherBindGroupLayout = 40 | device 41 | |> Device.createBindGroupLayout({ 42 | "entries": [| 43 | BindGroupLayout.layoutBinding( 44 | ~binding=0, 45 | ~visibility=ShaderStage.fragment, 46 | ~type_="storage-buffer", 47 | (), 48 | ), 49 | BindGroupLayout.layoutBinding( 50 | ~binding=1, 51 | ~visibility=ShaderStage.fragment, 52 | ~type_="storage-buffer", 53 | (), 54 | ), 55 | BindGroupLayout.layoutBinding( 56 | ~binding=2, 57 | ~visibility=ShaderStage.fragment, 58 | ~type_="uniform-buffer", 59 | (), 60 | ), 61 | BindGroupLayout.layoutBinding( 62 | ~binding=3, 63 | ~visibility=ShaderStage.fragment, 64 | ~type_="uniform-buffer", 65 | (), 66 | ), 67 | |], 68 | }); 69 | 70 | let gbufferBindGroup = 71 | device 72 | |> Device.createBindGroup({ 73 | "layout": gbufferBindGroupLayout, 74 | "entries": [| 75 | BindGroup.binding( 76 | ~binding=0, 77 | ~sampler=GBufferUtils.createLinearSampler(device), 78 | ~size=0, 79 | (), 80 | ), 81 | BindGroup.binding( 82 | ~binding=1, 83 | ~textureView= 84 | Pass.unsafeGetTextureView( 85 | "motionVectorDepthSpecularRenderTargetView", 86 | state, 87 | ), 88 | ~size=0, 89 | (), 90 | ), 91 | |], 92 | }); 93 | 94 | let otherBindGroup = 95 | device 96 | |> Device.createBindGroup({ 97 | "layout": otherBindGroupLayout, 98 | "entries": [| 99 | BindGroup.binding( 100 | ~binding=0, 101 | ~buffer=pixelBuffer, 102 | ~offset=0, 103 | ~size=pixelBufferSize, 104 | (), 105 | ), 106 | BindGroup.binding( 107 | ~binding=1, 108 | ~buffer=historyPixelBuffer, 109 | ~offset=0, 110 | ~size=historyPixelBufferSize, 111 | (), 112 | ), 113 | BindGroup.binding( 114 | ~binding=2, 115 | ~buffer=resolutionBuffer, 116 | ~offset=0, 117 | ~size=resolutionBufferSize, 118 | (), 119 | ), 120 | BindGroup.binding( 121 | ~binding=3, 122 | ~buffer=taaBuffer, 123 | ~offset=0, 124 | ~size=taaBufferSize, 125 | (), 126 | ), 127 | |], 128 | }); 129 | 130 | let state = 131 | state 132 | |> addStaticBindGroupDataFunc(0, gbufferBindGroup) 133 | |> addStaticBindGroupDataFunc(1, otherBindGroup); 134 | 135 | let baseShaderPath = "src/pass/taa/shaders"; 136 | 137 | let vertexShaderModule = 138 | device 139 | |> Device.createShaderModule({ 140 | "code": WebGPUUtils.loadShaderFile({j|$(baseShaderPath)/taa.vert|j}), 141 | }); 142 | let fragmentShaderModule = 143 | device 144 | |> Device.createShaderModule({ 145 | "code": 146 | WebGPUUtils.loadShaderFile( 147 | {j|$(baseShaderPath)/$(fragmentShaderName).frag|j}, 148 | ), 149 | }); 150 | 151 | let pipeline = 152 | device 153 | |> Device.createRenderPipeline( 154 | Pipeline.Render.descriptor( 155 | ~layout= 156 | device 157 | |> Device.createPipelineLayout({ 158 | "bindGroupLayouts": [| 159 | gbufferBindGroupLayout, 160 | otherBindGroupLayout, 161 | |], 162 | }), 163 | ~vertexStage={ 164 | Pipeline.Render.vertexStage( 165 | ~module_=vertexShaderModule, 166 | ~entryPoint="main", 167 | ); 168 | }, 169 | ~fragmentStage={ 170 | Pipeline.Render.fragmentStage( 171 | ~module_=fragmentShaderModule, 172 | ~entryPoint="main", 173 | ); 174 | }, 175 | ~primitiveTopology="triangle-list", 176 | ~vertexState= 177 | Pipeline.Render.vertexState(~indexFormat="uint32", ()), 178 | ~rasterizationState=Pipeline.Render.rasterizationState(), 179 | ~colorStates=[| 180 | Pipeline.Render.colorState( 181 | ~format=swapChainFormat, 182 | ~alphaBlend=Pipeline.Render.blendDescriptor(), 183 | ~colorBlend=Pipeline.Render.blendDescriptor(), 184 | ), 185 | |], 186 | (), 187 | ), 188 | ); 189 | 190 | state |> setPipelineFunc(pipeline); 191 | }; 192 | 193 | let _initFirstFrameData = 194 | ( 195 | device, 196 | swapChainFormat, 197 | ( 198 | (resolutionBufferSize, resolutionBuffer), 199 | (pixelBufferSize, pixelBuffer), 200 | (historyPixelBufferSize, historyPixelBuffer), 201 | (taaBufferSize, taaBuffer), 202 | ), 203 | state, 204 | ) => { 205 | _initFrameData( 206 | device, 207 | swapChainFormat, 208 | ( 209 | (resolutionBufferSize, resolutionBuffer), 210 | (pixelBufferSize, pixelBuffer), 211 | (historyPixelBufferSize, historyPixelBuffer), 212 | (taaBufferSize, taaBuffer), 213 | ), 214 | ( 215 | "taa_firstFrame", 216 | Pass.TAAPass.addFirstFrameStaticBindGroupData, 217 | Pass.TAAPass.setFirstFramePipeline, 218 | ), 219 | state, 220 | ); 221 | }; 222 | 223 | let _initOtherFrameData = 224 | ( 225 | device, 226 | swapChainFormat, 227 | ( 228 | (resolutionBufferSize, resolutionBuffer), 229 | (pixelBufferSize, pixelBuffer), 230 | (historyPixelBufferSize, historyPixelBuffer), 231 | (taaBufferSize, taaBuffer), 232 | ), 233 | state, 234 | ) => { 235 | _initFrameData( 236 | device, 237 | swapChainFormat, 238 | ( 239 | (resolutionBufferSize, resolutionBuffer), 240 | (pixelBufferSize, pixelBuffer), 241 | (historyPixelBufferSize, historyPixelBuffer), 242 | (taaBufferSize, taaBuffer), 243 | ), 244 | ( 245 | "taa_otherFrame", 246 | Pass.TAAPass.addOtherFrameStaticBindGroupData, 247 | Pass.TAAPass.setOtherFramePipeline, 248 | ), 249 | state, 250 | ); 251 | }; 252 | 253 | let init = (device, window, swapChainFormat, state) => { 254 | let (resolutionBufferData, resolutionBuffer) = 255 | RTXBuffer.ResolutionBuffer.unsafeGetBufferData(state); 256 | let (pixelBufferSize, pixelBuffer) = 257 | RTXBuffer.PixelBuffer.unsafeGetBufferData(state); 258 | let (historyPixelBufferSize, historyPixelBuffer) = 259 | RTXBuffer.HistoryPixelBuffer.unsafeGetBufferData(state); 260 | let (taaBufferData, taaBuffer) = 261 | RTXBuffer.TAABuffer.unsafeGetBufferData(state); 262 | 263 | state 264 | |> Pass.TAAPass.markFirstFrame 265 | |> _initFirstFrameData( 266 | device, 267 | swapChainFormat, 268 | ( 269 | ( 270 | RTXBuffer.ResolutionBuffer.getBufferSize(resolutionBufferData), 271 | resolutionBuffer, 272 | ), 273 | (pixelBufferSize, pixelBuffer), 274 | (historyPixelBufferSize, historyPixelBuffer), 275 | (RTXBuffer.TAABuffer.getBufferSize(taaBufferData), taaBuffer), 276 | ), 277 | ) 278 | |> _initOtherFrameData( 279 | device, 280 | swapChainFormat, 281 | ( 282 | ( 283 | RTXBuffer.ResolutionBuffer.getBufferSize(resolutionBufferData), 284 | resolutionBuffer, 285 | ), 286 | (pixelBufferSize, pixelBuffer), 287 | (historyPixelBufferSize, historyPixelBuffer), 288 | (RTXBuffer.TAABuffer.getBufferSize(taaBufferData), taaBuffer), 289 | ), 290 | ); 291 | }; 292 | 293 | let execute = (device, queue, swapChain, state) => { 294 | let backBufferView = swapChain |> SwapChain.getCurrentTextureView(); 295 | 296 | let commandEncoder = 297 | device |> Device.createCommandEncoder(CommandEncoder.descriptor()); 298 | let renderPass = 299 | commandEncoder 300 | |> CommandEncoder.beginRenderPass( 301 | { 302 | PassEncoder.Render.descriptor( 303 | ~colorAttachments=[| 304 | { 305 | "clearColor": { 306 | "r": 0.0, 307 | "g": 0.0, 308 | "b": 0.0, 309 | "a": 1.0, 310 | }, 311 | "loadOp": "clear", 312 | "storeOp": "store", 313 | "attachment": backBufferView, 314 | }, 315 | |], 316 | (), 317 | ); 318 | }, 319 | ); 320 | 321 | let (staticBindGroupDataArr, pipeline) = 322 | Pass.TAAPass.isFirstFrame(state) 323 | ? ( 324 | Pass.TAAPass.getFirstFrameStaticBindGroupDataArr(state), 325 | Pass.TAAPass.unsafeGetFirstFramePipeline(state), 326 | ) 327 | : ( 328 | Pass.TAAPass.getOtherFrameStaticBindGroupDataArr(state), 329 | Pass.TAAPass.unsafeGetOtherFramePipeline(state), 330 | ); 331 | 332 | renderPass |> PassEncoder.Render.setPipeline(pipeline); 333 | 334 | staticBindGroupDataArr 335 | |> Js.Array.forEach(({setSlot, bindGroup}: staticBindGroupData) => { 336 | renderPass |> PassEncoder.Render.setBindGroup(setSlot, bindGroup) 337 | }); 338 | 339 | renderPass |> PassEncoder.Render.draw(3, 1, 0, 0); 340 | renderPass |> PassEncoder.Render.endPass; 341 | 342 | queue |> Queue.submit([|commandEncoder |> CommandEncoder.finish|]); 343 | 344 | state |> Pass.TAAPass.markNotFirstFrame; 345 | }; 346 | -------------------------------------------------------------------------------- /src/pass/bmfr/preprocess/BMFRPreprocessPass.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | open StateType; 6 | 7 | let init = (device, swapChainFormat, state) => { 8 | let (resolutionBufferData, resolutionBuffer) = 9 | RTXBuffer.ResolutionBuffer.unsafeGetBufferData(state); 10 | let (pixelBufferSize, pixelBuffer) = 11 | RTXBuffer.PixelBuffer.unsafeGetBufferData(state); 12 | let (prevNoisyPixelBufferSize, prevNoisyPixelBuffer) = 13 | RTXBuffer.PrevNoisyPixelBuffer.unsafeGetBufferData(state); 14 | let (prevPositionBufferSize, prevPositionBuffer) = 15 | RTXBuffer.PrevPositionBuffer.unsafeGetBufferData(state); 16 | let (prevNormalBufferSize, prevNormalBuffer) = 17 | RTXBuffer.PrevNormalBuffer.unsafeGetBufferData(state); 18 | let (acceptBoolBufferSize, acceptBoolBuffer) = 19 | RTXBuffer.AcceptBoolBuffer.unsafeGetBufferData(state); 20 | let (prevFramePixelIndicesBufferSize, prevFramePixelIndicesBuffer) = 21 | RTXBuffer.PrevFramePixelIndicesBuffer.unsafeGetBufferData(state); 22 | let (commonDataBufferData, commonDataBuffer) = 23 | RTXBuffer.CommonDataBuffer.unsafeGetBufferData(state); 24 | 25 | let gbufferBindGroupLayout = 26 | device 27 | |> Device.createBindGroupLayout({ 28 | "entries": [| 29 | BindGroupLayout.layoutBinding( 30 | ~binding=0, 31 | ~visibility=ShaderStage.fragment, 32 | ~type_="sampled-texture", 33 | (), 34 | ), 35 | BindGroupLayout.layoutBinding( 36 | ~binding=1, 37 | ~visibility=ShaderStage.fragment, 38 | ~type_="sampled-texture", 39 | (), 40 | ), 41 | BindGroupLayout.layoutBinding( 42 | ~binding=2, 43 | ~visibility=ShaderStage.fragment, 44 | ~type_="sampled-texture", 45 | (), 46 | ), 47 | BindGroupLayout.layoutBinding( 48 | ~binding=3, 49 | ~visibility=ShaderStage.fragment, 50 | ~type_="sampled-texture", 51 | (), 52 | ), 53 | |], 54 | }); 55 | 56 | let otherBindGroupLayout = 57 | device 58 | |> Device.createBindGroupLayout({ 59 | "entries": [| 60 | BindGroupLayout.layoutBinding( 61 | ~binding=0, 62 | ~visibility=ShaderStage.fragment, 63 | ~type_="storage-buffer", 64 | (), 65 | ), 66 | BindGroupLayout.layoutBinding( 67 | ~binding=1, 68 | ~visibility=ShaderStage.fragment, 69 | ~type_="storage-buffer", 70 | (), 71 | ), 72 | BindGroupLayout.layoutBinding( 73 | ~binding=2, 74 | ~visibility=ShaderStage.fragment, 75 | ~type_="storage-buffer", 76 | (), 77 | ), 78 | BindGroupLayout.layoutBinding( 79 | ~binding=3, 80 | ~visibility=ShaderStage.fragment, 81 | ~type_="storage-buffer", 82 | (), 83 | ), 84 | BindGroupLayout.layoutBinding( 85 | ~binding=4, 86 | ~visibility=ShaderStage.fragment, 87 | ~type_="storage-buffer", 88 | (), 89 | ), 90 | BindGroupLayout.layoutBinding( 91 | ~binding=5, 92 | ~visibility=ShaderStage.fragment, 93 | ~type_="storage-buffer", 94 | (), 95 | ), 96 | BindGroupLayout.layoutBinding( 97 | ~binding=6, 98 | ~visibility=ShaderStage.fragment, 99 | ~type_="uniform-buffer", 100 | (), 101 | ), 102 | BindGroupLayout.layoutBinding( 103 | ~binding=7, 104 | ~visibility=ShaderStage.fragment, 105 | ~type_="uniform-buffer", 106 | (), 107 | ), 108 | |], 109 | }); 110 | 111 | let gbufferBindGroup = 112 | device 113 | |> Device.createBindGroup({ 114 | "layout": gbufferBindGroupLayout, 115 | "entries": [| 116 | BindGroup.binding( 117 | ~binding=0, 118 | ~textureView= 119 | Pass.unsafeGetTextureView("positionRoughnessRenderTargetView", state), 120 | ~size=0, 121 | (), 122 | ), 123 | BindGroup.binding( 124 | ~binding=1, 125 | ~textureView= 126 | Pass.unsafeGetTextureView("normalMetalnessRenderTargetView", state), 127 | ~size=0, 128 | (), 129 | ), 130 | BindGroup.binding( 131 | ~binding=2, 132 | ~textureView= 133 | Pass.unsafeGetTextureView( 134 | "motionVectorDepthSpecularRenderTargetView", 135 | state, 136 | ), 137 | ~size=0, 138 | (), 139 | ), 140 | BindGroup.binding( 141 | ~binding=3, 142 | ~textureView= 143 | Pass.unsafeGetTextureView( 144 | "diffusePositionWRenderTargetView", 145 | state, 146 | ), 147 | ~size=0, 148 | (), 149 | ), 150 | |], 151 | }); 152 | 153 | let otherBindGroup = 154 | device 155 | |> Device.createBindGroup({ 156 | "layout": otherBindGroupLayout, 157 | "entries": [| 158 | BindGroup.binding( 159 | ~binding=0, 160 | ~buffer=pixelBuffer, 161 | ~offset=0, 162 | ~size=pixelBufferSize, 163 | (), 164 | ), 165 | BindGroup.binding( 166 | ~binding=1, 167 | ~buffer=prevNoisyPixelBuffer, 168 | ~offset=0, 169 | ~size=prevNoisyPixelBufferSize, 170 | (), 171 | ), 172 | BindGroup.binding( 173 | ~binding=2, 174 | ~buffer=prevPositionBuffer, 175 | ~offset=0, 176 | ~size=prevPositionBufferSize, 177 | (), 178 | ), 179 | BindGroup.binding( 180 | ~binding=3, 181 | ~buffer=prevNormalBuffer, 182 | ~offset=0, 183 | ~size=prevNormalBufferSize, 184 | (), 185 | ), 186 | BindGroup.binding( 187 | ~binding=4, 188 | ~buffer=acceptBoolBuffer, 189 | ~offset=0, 190 | ~size=acceptBoolBufferSize, 191 | (), 192 | ), 193 | BindGroup.binding( 194 | ~binding=5, 195 | ~buffer=prevFramePixelIndicesBuffer, 196 | ~offset=0, 197 | ~size=prevFramePixelIndicesBufferSize, 198 | (), 199 | ), 200 | BindGroup.binding( 201 | ~binding=6, 202 | ~buffer=resolutionBuffer, 203 | ~offset=0, 204 | ~size= 205 | RTXBuffer.ResolutionBuffer.getBufferSize( 206 | resolutionBufferData, 207 | ), 208 | (), 209 | ), 210 | BindGroup.binding( 211 | ~binding=7, 212 | ~buffer=commonDataBuffer, 213 | ~offset=0, 214 | ~size= 215 | RTXBuffer.CommonDataBuffer.getBufferSize( 216 | commonDataBufferData, 217 | ), 218 | (), 219 | ), 220 | |], 221 | }); 222 | 223 | let state = 224 | state 225 | |> Pass.PreprocessPass.addStaticBindGroupData(0, gbufferBindGroup) 226 | |> Pass.PreprocessPass.addStaticBindGroupData(1, otherBindGroup); 227 | 228 | let baseShaderPath = "src/pass/bmfr/preprocess/shaders"; 229 | 230 | let vertexShaderModule = 231 | device 232 | |> Device.createShaderModule({ 233 | "code": 234 | WebGPUUtils.loadShaderFile( 235 | {j|$(baseShaderPath)/preprocess.vert|j}, 236 | ), 237 | }); 238 | let fragmentShaderModule = 239 | device 240 | |> Device.createShaderModule({ 241 | "code": 242 | WebGPUUtils.loadShaderFile( 243 | {j|$(baseShaderPath)/preprocess.frag|j}, 244 | ), 245 | }); 246 | 247 | let pipeline = 248 | device 249 | |> Device.createRenderPipeline( 250 | Pipeline.Render.descriptor( 251 | ~layout= 252 | device 253 | |> Device.createPipelineLayout({ 254 | "bindGroupLayouts": [| 255 | gbufferBindGroupLayout, 256 | otherBindGroupLayout, 257 | |], 258 | }), 259 | ~vertexStage={ 260 | Pipeline.Render.vertexStage( 261 | ~module_=vertexShaderModule, 262 | ~entryPoint="main", 263 | ); 264 | }, 265 | ~fragmentStage={ 266 | Pipeline.Render.fragmentStage( 267 | ~module_=fragmentShaderModule, 268 | ~entryPoint="main", 269 | ); 270 | }, 271 | ~primitiveTopology="triangle-list", 272 | ~vertexState= 273 | Pipeline.Render.vertexState(~indexFormat="uint32", ()), 274 | ~rasterizationState=Pipeline.Render.rasterizationState(), 275 | ~colorStates=[| 276 | Pipeline.Render.colorState( 277 | ~format=swapChainFormat, 278 | ~alphaBlend=Pipeline.Render.blendDescriptor(), 279 | ~colorBlend=Pipeline.Render.blendDescriptor(), 280 | ), 281 | |], 282 | (), 283 | ), 284 | ); 285 | 286 | state |> Pass.PreprocessPass.setPipeline(pipeline); 287 | }; 288 | 289 | let execute = (device, queue, swapChain, state) => { 290 | let backBufferView = swapChain |> SwapChain.getCurrentTextureView(); 291 | 292 | let commandEncoder = 293 | device |> Device.createCommandEncoder(CommandEncoder.descriptor()); 294 | let renderPass = 295 | commandEncoder 296 | |> CommandEncoder.beginRenderPass( 297 | { 298 | PassEncoder.Render.descriptor( 299 | ~colorAttachments=[| 300 | { 301 | "clearColor": { 302 | "r": 0.0, 303 | "g": 0.0, 304 | "b": 0.0, 305 | "a": 1.0, 306 | }, 307 | "loadOp": "clear", 308 | "storeOp": "store", 309 | "attachment": backBufferView, 310 | }, 311 | |], 312 | (), 313 | ); 314 | }, 315 | ); 316 | 317 | let (staticBindGroupDataArr, pipeline) = ( 318 | Pass.PreprocessPass.getStaticBindGroupDataArr(state), 319 | Pass.PreprocessPass.unsafeGetPipeline(state), 320 | ); 321 | 322 | renderPass |> PassEncoder.Render.setPipeline(pipeline); 323 | 324 | staticBindGroupDataArr 325 | |> Js.Array.forEach(({setSlot, bindGroup}: staticBindGroupData) => { 326 | renderPass |> PassEncoder.Render.setBindGroup(setSlot, bindGroup) 327 | }); 328 | 329 | renderPass |> PassEncoder.Render.draw(3, 1, 0, 0); 330 | renderPass |> PassEncoder.Render.endPass; 331 | 332 | queue |> Queue.submit([|commandEncoder |> CommandEncoder.finish|]); 333 | 334 | state; 335 | }; 336 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@most/multicast@^1.2.4", "@most/multicast@^1.2.5": 6 | version "1.3.0" 7 | resolved "https://registry.yarnpkg.com/@most/multicast/-/multicast-1.3.0.tgz#e01574840df634478ac3fabd164c6e830fb3b966" 8 | integrity sha512-DWH8AShgp5bXn+auGzf5tzPxvpmEvQJd0CNsApOci1LDF4eAEcnw4HQOr2Jaa+L92NbDYFKBSXxll+i7r1ikvw== 9 | dependencies: 10 | "@most/prelude" "^1.4.0" 11 | 12 | "@most/prelude@^1.4.0", "@most/prelude@^1.4.1": 13 | version "1.7.3" 14 | resolved "https://registry.yarnpkg.com/@most/prelude/-/prelude-1.7.3.tgz#51db3f3ba3ed65431b6eea89ecb0a31826af640c" 15 | integrity sha512-qWWEnA22UP1lzFfKx75XMut6DUUXGRKe7qv2k+Bgs7ju8lwb5RjsZYyQZ+VcsYvHcIavHKzseLlBMLOe2CvUZw== 16 | 17 | async@^1.5.2: 18 | version "1.5.2" 19 | resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" 20 | integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= 21 | 22 | async@^2.6.2: 23 | version "2.6.3" 24 | resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" 25 | integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== 26 | dependencies: 27 | lodash "^4.17.14" 28 | 29 | balanced-match@^1.0.0: 30 | version "1.0.0" 31 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 32 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 33 | 34 | basic-auth@^1.0.3: 35 | version "1.1.0" 36 | resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" 37 | integrity sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ= 38 | 39 | brace-expansion@^1.1.7: 40 | version "1.1.11" 41 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 42 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 43 | dependencies: 44 | balanced-match "^1.0.0" 45 | concat-map "0.0.1" 46 | 47 | bs-platform@^7.2.2: 48 | version "7.3.2" 49 | resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-7.3.2.tgz#301f5c9b4e8cf5713cb60ca22e145e56e793affe" 50 | integrity sha512-seJL5g4anK9la4erv+B2o2sMHQCxDF6OCRl9en3hbaUos/S3JsusQ0sPp4ORsbx5eXfHLYBwPljwKXlgpXtsgQ== 51 | 52 | clang-format@^1.4.0: 53 | version "1.4.0" 54 | resolved "https://registry.yarnpkg.com/clang-format/-/clang-format-1.4.0.tgz#1ee2f10637eb5bb0bd7d0b82c949af68e848367e" 55 | integrity sha512-NrdyUnHJOGvMa60vbWk7GJTvOdhibj3uK5C0FlwdNG4301OUvqEJTFce9I9x8qw2odBbIVrJ+9xbsFS3a4FbDA== 56 | dependencies: 57 | async "^1.5.2" 58 | glob "^7.0.0" 59 | resolve "^1.1.6" 60 | 61 | colors@^1.4.0: 62 | version "1.4.0" 63 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" 64 | integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== 65 | 66 | concat-map@0.0.1: 67 | version "0.0.1" 68 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 69 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 70 | 71 | corser@^2.0.1: 72 | version "2.0.1" 73 | resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" 74 | integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c= 75 | 76 | debug@^3.1.1: 77 | version "3.2.6" 78 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 79 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 80 | dependencies: 81 | ms "^2.1.1" 82 | 83 | ecstatic@^3.3.2: 84 | version "3.3.2" 85 | resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48" 86 | integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog== 87 | dependencies: 88 | he "^1.1.1" 89 | mime "^1.6.0" 90 | minimist "^1.1.0" 91 | url-join "^2.0.5" 92 | 93 | eventemitter3@^4.0.0: 94 | version "4.0.4" 95 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" 96 | integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== 97 | 98 | follow-redirects@^1.0.0: 99 | version "1.12.1" 100 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.12.1.tgz#de54a6205311b93d60398ebc01cf7015682312b6" 101 | integrity sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg== 102 | 103 | fs.realpath@^1.0.0: 104 | version "1.0.0" 105 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 106 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 107 | 108 | glob@^7.0.0: 109 | version "7.1.6" 110 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 111 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 112 | dependencies: 113 | fs.realpath "^1.0.0" 114 | inflight "^1.0.4" 115 | inherits "2" 116 | minimatch "^3.0.4" 117 | once "^1.3.0" 118 | path-is-absolute "^1.0.0" 119 | 120 | he@^1.1.1: 121 | version "1.2.0" 122 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 123 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 124 | 125 | http-proxy@^1.18.0: 126 | version "1.18.1" 127 | resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" 128 | integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== 129 | dependencies: 130 | eventemitter3 "^4.0.0" 131 | follow-redirects "^1.0.0" 132 | requires-port "^1.0.0" 133 | 134 | http-server@^0.12.0: 135 | version "0.12.3" 136 | resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.12.3.tgz#ba0471d0ecc425886616cb35c4faf279140a0d37" 137 | integrity sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA== 138 | dependencies: 139 | basic-auth "^1.0.3" 140 | colors "^1.4.0" 141 | corser "^2.0.1" 142 | ecstatic "^3.3.2" 143 | http-proxy "^1.18.0" 144 | minimist "^1.2.5" 145 | opener "^1.5.1" 146 | portfinder "^1.0.25" 147 | secure-compare "3.0.1" 148 | union "~0.5.0" 149 | 150 | inflight@^1.0.4: 151 | version "1.0.6" 152 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 153 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 154 | dependencies: 155 | once "^1.3.0" 156 | wrappy "1" 157 | 158 | inherits@2: 159 | version "2.0.4" 160 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 161 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 162 | 163 | lodash@^4.17.14: 164 | version "4.17.19" 165 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" 166 | integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== 167 | 168 | mime@^1.6.0: 169 | version "1.6.0" 170 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 171 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 172 | 173 | minimatch@^3.0.4: 174 | version "3.0.4" 175 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 176 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 177 | dependencies: 178 | brace-expansion "^1.1.7" 179 | 180 | minimist@^1.1.0, minimist@^1.2.5: 181 | version "1.2.5" 182 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 183 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 184 | 185 | mkdirp@^0.5.1: 186 | version "0.5.5" 187 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" 188 | integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== 189 | dependencies: 190 | minimist "^1.2.5" 191 | 192 | most-subject@^5.3.0: 193 | version "5.3.0" 194 | resolved "https://registry.yarnpkg.com/most-subject/-/most-subject-5.3.0.tgz#3a6e3efd436fa93bd8b33c2a239c9088230a6102" 195 | integrity sha1-Om4+/UNvqTvYszwqI5yQiCMKYQI= 196 | dependencies: 197 | "@most/multicast" "^1.2.4" 198 | "@most/prelude" "^1.4.1" 199 | most "^1.1.0" 200 | 201 | most@^1.1.0, most@^1.7.0: 202 | version "1.8.1" 203 | resolved "https://registry.yarnpkg.com/most/-/most-1.8.1.tgz#0c752d26017ddcd50429651665dc229dbef439da" 204 | integrity sha512-sN3lHtEvVNq5ay/pT93fKQ2XVW2uwbUypSWGt/DYCxGKuyvxaNd8mProK0M4k6irqeh1WD3pWrg4RdrCPohqDQ== 205 | dependencies: 206 | "@most/multicast" "^1.2.5" 207 | "@most/prelude" "^1.4.0" 208 | symbol-observable "^1.0.2" 209 | 210 | ms@^2.1.1: 211 | version "2.1.2" 212 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 213 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 214 | 215 | once@^1.3.0: 216 | version "1.4.0" 217 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 218 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 219 | dependencies: 220 | wrappy "1" 221 | 222 | opener@^1.5.1: 223 | version "1.5.1" 224 | resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" 225 | integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== 226 | 227 | path-is-absolute@^1.0.0: 228 | version "1.0.1" 229 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 230 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 231 | 232 | path-parse@^1.0.6: 233 | version "1.0.6" 234 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 235 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 236 | 237 | portfinder@^1.0.25: 238 | version "1.0.26" 239 | resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70" 240 | integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ== 241 | dependencies: 242 | async "^2.6.2" 243 | debug "^3.1.1" 244 | mkdirp "^0.5.1" 245 | 246 | qs@^6.4.0: 247 | version "6.9.4" 248 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" 249 | integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== 250 | 251 | raytracing-framework@^0.0.3: 252 | version "0.0.3" 253 | resolved "https://registry.yarnpkg.com/raytracing-framework/-/raytracing-framework-0.0.3.tgz#70cda7b43449983e3e3329a55acd182cfddb94ef" 254 | integrity sha512-kJGDiJYjGmuzeVGevwVi3oFJxNfYVZR88hc8550KgNMJhOy9f0Ex6RMt26qbAqOaZzagAm1krn3AhfikVfTnyw== 255 | dependencies: 256 | bs-platform "^7.2.2" 257 | webgpu "0.1.16" 258 | wonder-bs-most "^0.0.3" 259 | 260 | requires-port@^1.0.0: 261 | version "1.0.0" 262 | resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" 263 | integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= 264 | 265 | resolve@^1.1.6: 266 | version "1.17.0" 267 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" 268 | integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== 269 | dependencies: 270 | path-parse "^1.0.6" 271 | 272 | secure-compare@3.0.1: 273 | version "3.0.1" 274 | resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3" 275 | integrity sha1-8aAymzCLIh+uN7mXTz1XjQypmeM= 276 | 277 | symbol-observable@^1.0.2: 278 | version "1.2.0" 279 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" 280 | integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== 281 | 282 | union@~0.5.0: 283 | version "0.5.0" 284 | resolved "https://registry.yarnpkg.com/union/-/union-0.5.0.tgz#b2c11be84f60538537b846edb9ba266ba0090075" 285 | integrity sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA== 286 | dependencies: 287 | qs "^6.4.0" 288 | 289 | url-join@^2.0.5: 290 | version "2.0.5" 291 | resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" 292 | integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= 293 | 294 | webgpu@0.1.16: 295 | version "0.1.16" 296 | resolved "https://registry.yarnpkg.com/webgpu/-/webgpu-0.1.16.tgz#dec416373e308181b28864b58c8a914461d7ceee" 297 | integrity sha512-KAXn/f8lnL8o4B718zzdfi1l0nEWQpuoWlC1L5WM/svAbeHjShCEI0l5ZcZBEEUm9FF3ZTgRjWk8iwbJfnGKTA== 298 | 299 | wonder-bs-most@^0.0.3: 300 | version "0.0.3" 301 | resolved "https://registry.yarnpkg.com/wonder-bs-most/-/wonder-bs-most-0.0.3.tgz#571f2f9ddf13c80a756350d9d813694d08c640cf" 302 | integrity sha512-vxCrHinx0qw4AO+vYsK+Drv7cZC5YSFZu1EuSMCS1gIjhq6G6FINl67zhlka97hfM/LJ48vXQ63KKjtMrWLzug== 303 | dependencies: 304 | most "^1.7.0" 305 | most-subject "^5.3.0" 306 | 307 | wrappy@1: 308 | version "1.0.2" 309 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 310 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 311 | -------------------------------------------------------------------------------- /src/pass/ray_tracing/RayTracingPass.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | open Js.Typed_array; 6 | 7 | open StateType; 8 | 9 | let _createShaderBindingTable = (baseShaderPath, device) => { 10 | let rayGenShaderModule = 11 | device 12 | |> Device.createShaderModule({ 13 | "code": 14 | WebGPUUtils.loadShaderFile( 15 | {j|$(baseShaderPath)/ray-generation.rgen|j}, 16 | ), 17 | }); 18 | let rayRChitShaderModule = 19 | device 20 | |> Device.createShaderModule({ 21 | "code": 22 | WebGPUUtils.loadShaderFile( 23 | {j|$(baseShaderPath)/ray-closest-hit-indirect-gi.rchit|j}, 24 | ), 25 | }); 26 | let rayMissShaderModule = 27 | device 28 | |> Device.createShaderModule({ 29 | "code": 30 | WebGPUUtils.loadShaderFile({j|$(baseShaderPath)/ray-miss.rmiss|j}), 31 | }); 32 | let rayMissShadowShaderModule = 33 | device 34 | |> Device.createShaderModule({ 35 | "code": 36 | WebGPUUtils.loadShaderFile( 37 | {j|$(baseShaderPath)/ray-miss-shadow.rmiss|j}, 38 | ), 39 | }); 40 | 41 | device 42 | |> Device.createRayTracingShaderBindingTable({ 43 | "stages": [| 44 | {"module": rayGenShaderModule, "stage": ShaderStage.ray_generation}, 45 | { 46 | "module": rayRChitShaderModule, 47 | "stage": ShaderStage.ray_closest_hit, 48 | }, 49 | {"module": rayMissShaderModule, "stage": ShaderStage.ray_miss}, 50 | {"module": rayMissShadowShaderModule, "stage": ShaderStage.ray_miss}, 51 | |], 52 | "groups": [| 53 | ShaderBindingTable.group(~type_="general", ~generalIndex=0, ()), 54 | ShaderBindingTable.group( 55 | ~type_="triangles-hit-group", 56 | ~closestHitIndex=1, 57 | (), 58 | ), 59 | ShaderBindingTable.group(~type_="general", ~generalIndex=2, ()), 60 | ShaderBindingTable.group(~type_="general", ~generalIndex=3, ()), 61 | |], 62 | }); 63 | }; 64 | 65 | let init = (device, queue, state) => { 66 | let gbufferBindGroupLayout = 67 | device 68 | |> Device.createBindGroupLayout({ 69 | "entries": [| 70 | BindGroupLayout.layoutBinding( 71 | ~binding=0, 72 | ~visibility=ShaderStage.ray_generation, 73 | ~type_="sampler", 74 | (), 75 | ), 76 | BindGroupLayout.layoutBinding( 77 | ~binding=1, 78 | ~visibility=ShaderStage.ray_generation, 79 | ~type_="sampled-texture", 80 | (), 81 | ), 82 | BindGroupLayout.layoutBinding( 83 | ~binding=2, 84 | ~visibility=ShaderStage.ray_generation, 85 | ~type_="sampled-texture", 86 | (), 87 | ), 88 | BindGroupLayout.layoutBinding( 89 | ~binding=3, 90 | ~visibility=ShaderStage.ray_generation, 91 | ~type_="sampled-texture", 92 | (), 93 | ), 94 | BindGroupLayout.layoutBinding( 95 | ~binding=4, 96 | ~visibility=ShaderStage.ray_generation, 97 | ~type_="sampled-texture", 98 | (), 99 | ), 100 | |], 101 | }); 102 | 103 | let rtBindGroupLayout = 104 | device 105 | |> Device.createBindGroupLayout({ 106 | "entries": [| 107 | BindGroupLayout.layoutBinding( 108 | ~binding=0, 109 | ~visibility= 110 | ShaderStage.ray_generation lor ShaderStage.ray_closest_hit, 111 | ~type_="acceleration-container", 112 | (), 113 | ), 114 | BindGroupLayout.layoutBinding( 115 | ~binding=1, 116 | ~visibility=ShaderStage.ray_generation, 117 | ~type_="storage-buffer", 118 | (), 119 | ), 120 | BindGroupLayout.layoutBinding( 121 | ~binding=2, 122 | ~visibility= 123 | ShaderStage.ray_generation lor ShaderStage.ray_closest_hit, 124 | ~type_="uniform-buffer", 125 | (), 126 | ), 127 | BindGroupLayout.layoutBinding( 128 | ~binding=3, 129 | ~visibility=ShaderStage.ray_generation, 130 | ~type_="uniform-buffer", 131 | (), 132 | ), 133 | BindGroupLayout.layoutBinding( 134 | ~binding=4, 135 | ~visibility=ShaderStage.ray_closest_hit, 136 | ~type_="storage-buffer", 137 | (), 138 | ), 139 | BindGroupLayout.layoutBinding( 140 | ~binding=5, 141 | ~visibility=ShaderStage.ray_closest_hit, 142 | ~type_="storage-buffer", 143 | (), 144 | ), 145 | BindGroupLayout.layoutBinding( 146 | ~binding=6, 147 | ~visibility=ShaderStage.ray_closest_hit, 148 | ~type_="storage-buffer", 149 | (), 150 | ), 151 | BindGroupLayout.layoutBinding( 152 | ~binding=7, 153 | ~visibility=ShaderStage.ray_closest_hit, 154 | ~type_="storage-buffer", 155 | (), 156 | ), 157 | BindGroupLayout.layoutBinding( 158 | ~binding=8, 159 | ~visibility=ShaderStage.ray_closest_hit, 160 | ~type_="storage-buffer", 161 | (), 162 | ), 163 | |], 164 | }); 165 | 166 | let cameraBindGroupLayout = 167 | device 168 | |> Device.createBindGroupLayout({ 169 | "entries": [| 170 | BindGroupLayout.layoutBinding( 171 | ~binding=0, 172 | ~visibility= 173 | ShaderStage.ray_generation lor ShaderStage.ray_closest_hit, 174 | ~type_="uniform-buffer", 175 | (), 176 | ), 177 | |], 178 | }); 179 | 180 | let directionLightBindGroupLayout = 181 | device 182 | |> Device.createBindGroupLayout({ 183 | "entries": [| 184 | BindGroupLayout.layoutBinding( 185 | ~binding=0, 186 | ~visibility= 187 | ShaderStage.ray_generation lor ShaderStage.ray_closest_hit, 188 | ~type_="storage-buffer", 189 | (), 190 | ), 191 | |], 192 | }); 193 | 194 | let gbufferBindGroup = 195 | device 196 | |> Device.createBindGroup({ 197 | "layout": gbufferBindGroupLayout, 198 | "entries": [| 199 | BindGroup.binding( 200 | ~binding=0, 201 | ~sampler=GBufferUtils.createLinearSampler(device), 202 | ~size=0, 203 | (), 204 | ), 205 | BindGroup.binding( 206 | ~binding=1, 207 | ~textureView= 208 | Pass.unsafeGetTextureView( 209 | "positionRoughnessRenderTargetView", 210 | state, 211 | ), 212 | ~size=0, 213 | (), 214 | ), 215 | BindGroup.binding( 216 | ~binding=2, 217 | ~textureView= 218 | Pass.unsafeGetTextureView( 219 | "normalMetalnessRenderTargetView", 220 | state, 221 | ), 222 | ~size=0, 223 | (), 224 | ), 225 | BindGroup.binding( 226 | ~binding=3, 227 | ~textureView= 228 | Pass.unsafeGetTextureView( 229 | "diffusePositionWRenderTargetView", 230 | state, 231 | ), 232 | ~size=0, 233 | (), 234 | ), 235 | BindGroup.binding( 236 | ~binding=4, 237 | ~textureView= 238 | Pass.unsafeGetTextureView( 239 | "motionVectorDepthSpecularRenderTargetView", 240 | state, 241 | ), 242 | ~size=0, 243 | (), 244 | ), 245 | |], 246 | }); 247 | 248 | let (geometryContainers, instanceContainer) = 249 | ManageAccelerationContainer.buildContainers(device, queue, state); 250 | 251 | let state = 252 | state 253 | |> OperateAccelerationContainer.setData( 254 | geometryContainers, 255 | instanceContainer, 256 | ); 257 | 258 | let (pixelBufferSize, pixelBuffer) = 259 | RTXBuffer.PixelBuffer.unsafeGetBufferData(state); 260 | 261 | let (commonDataBufferData, commonDataBuffer) = 262 | RTXBuffer.CommonDataBuffer.unsafeGetBufferData(state); 263 | 264 | let (rayTracingCommonDataBufferData, rayTracingCommonDataBuffer) = 265 | RTXBuffer.RayTracingCommonDataBuffer.unsafeGetBufferData(state); 266 | 267 | let (sceneDescBufferSize, sceneDescBuffer) = 268 | RTXBuffer.GetHitShadingData.SceneDescBuffer.unsafeGetBufferData(state); 269 | let (geometryOffsetDataBufferSize, geometryOffsetDataBuffer) = 270 | RTXBuffer.GetHitShadingData.GeometryOffsetDataBuffer.unsafeGetBufferData( 271 | state, 272 | ); 273 | let (vertexBufferSize, vertexBuffer) = 274 | RTXBuffer.GetHitShadingData.VertexBuffer.unsafeGetBufferData(state); 275 | let (indexBufferSize, indexBuffer) = 276 | RTXBuffer.GetHitShadingData.IndexBuffer.unsafeGetBufferData(state); 277 | let (pbrMaterialBufferSize, pbrMaterialBuffer) = 278 | RTXBuffer.GetHitShadingData.PBRMaterialBuffer.unsafeGetBufferData(state); 279 | 280 | let rtBindGroup = 281 | device 282 | |> Device.createBindGroup({ 283 | "layout": rtBindGroupLayout, 284 | "entries": [| 285 | BindGroup.binding( 286 | ~binding=0, 287 | ~accelerationContainer=instanceContainer, 288 | ~offset=0, 289 | ~size=0, 290 | (), 291 | ), 292 | BindGroup.binding( 293 | ~binding=1, 294 | ~buffer=pixelBuffer, 295 | ~offset=0, 296 | ~size=pixelBufferSize, 297 | (), 298 | ), 299 | BindGroup.binding( 300 | ~binding=2, 301 | ~buffer=commonDataBuffer, 302 | ~offset=0, 303 | ~size= 304 | RTXBuffer.CommonDataBuffer.getBufferSize( 305 | commonDataBufferData, 306 | ), 307 | (), 308 | ), 309 | BindGroup.binding( 310 | ~binding=3, 311 | ~buffer=rayTracingCommonDataBuffer, 312 | ~offset=0, 313 | ~size= 314 | RTXBuffer.RayTracingCommonDataBuffer.getBufferSize( 315 | rayTracingCommonDataBufferData, 316 | ), 317 | (), 318 | ), 319 | BindGroup.binding( 320 | ~binding=4, 321 | ~buffer=sceneDescBuffer, 322 | ~offset=0, 323 | ~size=sceneDescBufferSize, 324 | (), 325 | ), 326 | BindGroup.binding( 327 | ~binding=5, 328 | ~buffer=geometryOffsetDataBuffer, 329 | ~offset=0, 330 | ~size=geometryOffsetDataBufferSize, 331 | (), 332 | ), 333 | BindGroup.binding( 334 | ~binding=6, 335 | ~buffer=vertexBuffer, 336 | ~offset=0, 337 | ~size=vertexBufferSize, 338 | (), 339 | ), 340 | BindGroup.binding( 341 | ~binding=7, 342 | ~buffer=indexBuffer, 343 | ~offset=0, 344 | ~size=indexBufferSize, 345 | (), 346 | ), 347 | BindGroup.binding( 348 | ~binding=8, 349 | ~buffer=pbrMaterialBuffer, 350 | ~offset=0, 351 | ~size=pbrMaterialBufferSize, 352 | (), 353 | ), 354 | |], 355 | }); 356 | 357 | let (cameraBufferData, cameraBuffer) = 358 | RTXBuffer.CameraBuffer.unsafeGetCameraBufferData(state); 359 | 360 | let cameraBindGroup = 361 | device 362 | |> Device.createBindGroup({ 363 | "layout": cameraBindGroupLayout, 364 | "entries": [| 365 | BindGroup.binding( 366 | ~binding=0, 367 | ~buffer=cameraBuffer, 368 | ~offset=0, 369 | ~size=cameraBufferData |> Float32Array.byteLength, 370 | (), 371 | ), 372 | |], 373 | }); 374 | 375 | let (directionLightBufferSize, directionLightBuffer) = 376 | RTXBuffer.DirectionLightBuffer.buildData(device, state); 377 | 378 | let directionLightBindGroup = 379 | device 380 | |> Device.createBindGroup({ 381 | "layout": directionLightBindGroupLayout, 382 | "entries": [| 383 | BindGroup.binding( 384 | ~binding=0, 385 | ~buffer=directionLightBuffer, 386 | ~offset=0, 387 | ~size=directionLightBufferSize, 388 | (), 389 | ), 390 | |], 391 | }); 392 | 393 | let state = 394 | state 395 | |> Pass.RayTracingPass.addStaticBindGroupData(0, gbufferBindGroup) 396 | |> Pass.RayTracingPass.addStaticBindGroupData(1, rtBindGroup) 397 | |> Pass.RayTracingPass.addStaticBindGroupData(2, cameraBindGroup) 398 | |> Pass.RayTracingPass.addStaticBindGroupData(3, directionLightBindGroup); 399 | 400 | let pipeline = 401 | device 402 | |> Device.createRayTracingPipeline( 403 | Pipeline.RayTracing.descriptor( 404 | ~layout= 405 | device 406 | |> Device.createPipelineLayout({ 407 | "bindGroupLayouts": [| 408 | gbufferBindGroupLayout, 409 | rtBindGroupLayout, 410 | cameraBindGroupLayout, 411 | directionLightBindGroupLayout, 412 | |], 413 | }), 414 | ~rayTracingState={ 415 | Pipeline.RayTracing.rayTracingState( 416 | ~shaderBindingTable= 417 | _createShaderBindingTable( 418 | "src/pass/ray_tracing/shaders", 419 | device, 420 | ), 421 | ~maxRecursionDepth=1, 422 | ~maxPayloadSize= 423 | (3 * 5 + 1 * 3) 424 | * Float32Array._BYTES_PER_ELEMENT 425 | + 1 426 | * 2 427 | * Uint32Array._BYTES_PER_ELEMENT 428 | + 1 429 | * Float32Array._BYTES_PER_ELEMENT, 430 | ); 431 | }, 432 | ), 433 | ); 434 | 435 | let state = state |> Pass.RayTracingPass.setPipeline(pipeline); 436 | 437 | state; 438 | }; 439 | 440 | let execute = (device, window, queue, state) => { 441 | let commandEncoder = 442 | device |> Device.createCommandEncoder(CommandEncoder.descriptor()); 443 | let rtPass = 444 | commandEncoder 445 | |> CommandEncoder.beginRayTracingPass( 446 | { 447 | PassEncoder.RayTracing.descriptor(); 448 | }, 449 | ); 450 | rtPass 451 | |> PassEncoder.RayTracing.setPipeline( 452 | Pass.RayTracingPass.unsafeGetPipeline(state), 453 | ); 454 | Pass.RayTracingPass.getStaticBindGroupDataArr(state) 455 | |> Js.Array.forEach(({setSlot, bindGroup}: staticBindGroupData) => { 456 | rtPass |> PassEncoder.RayTracing.setBindGroup(setSlot, bindGroup) 457 | }); 458 | rtPass 459 | |> PassEncoder.RayTracing.traceRays( 460 | 0, // sbt ray-generation offset 461 | 1, // sbt ray-hit offset 462 | 2, // sbt ray-miss offset 463 | Window.getWidth(window), // query width dimension 464 | Window.getHeight(window), // query height dimension 465 | 1 // query depth dimension 466 | ); 467 | rtPass |> PassEncoder.RayTracing.endPass; 468 | 469 | queue |> Queue.submit([|commandEncoder |> CommandEncoder.finish|]); 470 | 471 | state; 472 | }; 473 | -------------------------------------------------------------------------------- /src/pass/bmfr/regression/shaders/regression.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_nonuniform_qualifier : enable 3 | #extension GL_EXT_scalar_block_layout : enable 4 | #pragma shader_stage(compute) 5 | 6 | #define BUFFER_COUNT 13 7 | #define FEATURES_COUNT 10 8 | #define FEATURES_NOT_SCALED 4 9 | #define BLOCK_PIXELS 1024 10 | #define LOCAL_SIZE 256 11 | #define BLOCK_EDGE_LENGTH 32 12 | #define NOISE_AMOUNT 0.01 13 | #define BLOCK_OFFSETS_COUNT 16 14 | 15 | #define INBLOCK_ID subVector *LOCAL_SIZE + groupThreadId 16 | #define BLOCK_OFFSET groupId.x *BUFFER_COUNT 17 | 18 | #include "../../../shaders/utils.glsl" 19 | #include "../../shaders/utils.glsl" 20 | #include "./barrier.glsl" 21 | 22 | layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in; 23 | 24 | shared float sumVec[256]; 25 | shared float uVec[1024]; 26 | shared float gchannel[1024]; 27 | shared float bchannel[1024]; 28 | shared float rmat[10][13]; // FEATURES * BUFFER_COUNT 29 | shared float uLengthSquared; 30 | shared float dotV; 31 | shared float blockMin; 32 | shared float blockMax; 33 | shared float vecLength; 34 | 35 | layout(binding = 0) uniform sampler sampler0; 36 | layout(binding = 1) uniform texture2D gPositionRoughnessTexture; 37 | layout(binding = 2) uniform texture2D gNormalMetalnessTexture; 38 | layout(binding = 3) uniform texture2D gDiffusePositionWTexture; 39 | 40 | layout(std140, set = 1, binding = 0) buffer CurNoisyPixelBuffer { 41 | vec4 pixels[]; 42 | } 43 | curNoisyPixelBuffer; 44 | 45 | // BLOCK_PIXELS * [(FEATURES_COUNT + color_channels) * blocks] 46 | layout(scalar, set = 1, binding = 1) buffer TmpDataBuffer { float data[]; } 47 | tmpDataBuffer; 48 | 49 | // where we perform QR decomposition 50 | layout(scalar, set = 1, binding = 2) buffer OutDataBuffer { float data[]; } 51 | outDataBuffer; 52 | 53 | layout(set = 1, binding = 3) uniform ScreenDimension { vec2 resolution; } 54 | screenDimension; 55 | 56 | layout(std140, set = 1, 57 | binding = 4) uniform CommonData { // uint frameIndex; 58 | // uint horizentalBlocksCount; 59 | vec4 compressedData; 60 | } 61 | pushC; 62 | 63 | int mirror(int index, int size) { 64 | if (index < 0) 65 | index = abs(index) - 1; 66 | else if (index >= size) 67 | index = 2 * size - index - 1; 68 | 69 | return index; 70 | } 71 | 72 | ivec2 mirror2(ivec2 index, ivec2 size) { 73 | index.x = mirror(index.x, size.x); 74 | index.y = mirror(index.y, size.y); 75 | 76 | return index; 77 | } 78 | 79 | ivec2 getPixelIndices(uint inblockId, uint groupIdX, uint horizentalBlocksCount, 80 | uint frameIndex, 81 | ivec2 blockOffsets[BLOCK_OFFSETS_COUNT]) { 82 | // go to group indices 83 | ivec2 uv = 84 | ivec2(groupIdX % horizentalBlocksCount, groupIdX / horizentalBlocksCount); 85 | // go to thread indices(32 * 32 in one group) 86 | uv *= BLOCK_EDGE_LENGTH; 87 | uv += ivec2(inblockId % BLOCK_EDGE_LENGTH, inblockId / BLOCK_EDGE_LENGTH); 88 | // offset 89 | uv += blockOffsets[frameIndex % BLOCK_OFFSETS_COUNT]; 90 | 91 | return uv; 92 | } 93 | 94 | uint convertDataBufferTwoDIndexToOneDIndex(uint twoDIndexX, uint twoDIndexY) { 95 | return convertBufferTwoDIndexToOneDIndex(twoDIndexX, twoDIndexY, 96 | BLOCK_PIXELS); 97 | } 98 | 99 | uint convertPixelIndicesToPixelIndex(ivec2 pixelIndices, vec2 resolution) { 100 | return convertBufferTwoDIndexToOneDIndex(pixelIndices.x, pixelIndices.y, 101 | uint(resolution.x)); 102 | } 103 | 104 | vec2 convertPixelIndicesToUV(vec2 pixelIndices, vec2 resolution) { 105 | return saturateVec2(pixelIndices / resolution); 106 | } 107 | 108 | void householderQRDecomposition(uint groupThreadId, uvec3 groupId) { 109 | // use IGNORE_LD_fEATURES 110 | // TODO not use IGNORE_LD_fEATURES 111 | 112 | int limit = 0; 113 | for (uint col = 0; col < FEATURES_COUNT; col++) { 114 | float tmpSumValue = 0; 115 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; 116 | ++subVector) { 117 | uint index = INBLOCK_ID; 118 | 119 | float tmp = outDataBuffer.data[convertDataBufferTwoDIndexToOneDIndex( 120 | index, col + BLOCK_OFFSET)]; 121 | uVec[index] = tmp; 122 | if (index >= limit + 1) { 123 | tmpSumValue += tmp * tmp; 124 | } 125 | } 126 | sumVec[groupThreadId] = tmpSumValue; 127 | groupMemoryBarrierWithGroupSync(); 128 | 129 | // parallel reduction sum 130 | if (groupThreadId < 128) 131 | sumVec[groupThreadId] += sumVec[groupThreadId + 128]; 132 | groupMemoryBarrierWithGroupSync(); 133 | if (groupThreadId < 64) 134 | sumVec[groupThreadId] += sumVec[groupThreadId + 64]; 135 | groupMemoryBarrierWithGroupSync(); 136 | if (groupThreadId < 32) 137 | sumVec[groupThreadId] += sumVec[groupThreadId + 32]; 138 | groupMemoryBarrierWithGroupSync(); 139 | if (groupThreadId < 16) 140 | sumVec[groupThreadId] += sumVec[groupThreadId + 16]; 141 | groupMemoryBarrierWithGroupSync(); 142 | if (groupThreadId < 8) 143 | sumVec[groupThreadId] += sumVec[groupThreadId + 8]; 144 | groupMemoryBarrierWithGroupSync(); 145 | if (groupThreadId < 4) 146 | sumVec[groupThreadId] += sumVec[groupThreadId + 4]; 147 | groupMemoryBarrierWithGroupSync(); 148 | if (groupThreadId < 2) 149 | sumVec[groupThreadId] += sumVec[groupThreadId + 2]; 150 | groupMemoryBarrierWithGroupSync(); 151 | if (groupThreadId == 0) 152 | vecLength = sumVec[0] + sumVec[1]; 153 | groupMemoryBarrierWithGroupSync(); 154 | 155 | float rValue; 156 | if (groupThreadId < limit) { 157 | rValue = uVec[groupThreadId]; 158 | } else if (groupThreadId == limit) { 159 | uLengthSquared = vecLength; 160 | vecLength = sqrt(vecLength + uVec[limit] * uVec[limit]); 161 | uVec[limit] -= vecLength; 162 | uLengthSquared += uVec[limit] * uVec[limit]; 163 | rValue = vecLength; 164 | } else if (groupThreadId > limit) { 165 | rValue = 0; 166 | } 167 | 168 | groupMemoryBarrierWithGroupSync(); 169 | 170 | if (vecLength > 0.01) { 171 | limit++; 172 | if (groupThreadId < FEATURES_COUNT) 173 | rmat[groupThreadId][col] = rValue; 174 | } else { 175 | if (groupThreadId < FEATURES_COUNT) 176 | rmat[groupThreadId][col] = 0.0; 177 | continue; 178 | } 179 | 180 | if (uLengthSquared < 0.001) { 181 | continue; 182 | } 183 | 184 | for (uint feature_buffer = col + 1; feature_buffer < BUFFER_COUNT; 185 | feature_buffer++) { 186 | float tmp_data_private_cache[BLOCK_PIXELS / LOCAL_SIZE]; 187 | float tmpSumValue = 0.0; 188 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; 189 | ++subVector) { 190 | uint index = INBLOCK_ID; 191 | if (index >= limit - 1) { 192 | float tmp = outDataBuffer.data[convertDataBufferTwoDIndexToOneDIndex( 193 | index, feature_buffer + BLOCK_OFFSET)]; 194 | tmp_data_private_cache[subVector] = tmp; 195 | tmpSumValue += tmp * uVec[index]; 196 | } 197 | } 198 | 199 | sumVec[groupThreadId] = tmpSumValue; 200 | groupMemoryBarrierWithGroupSync(); 201 | 202 | // parallel reduction sum 203 | if (groupThreadId < 128) 204 | sumVec[groupThreadId] += sumVec[groupThreadId + 128]; 205 | groupMemoryBarrierWithGroupSync(); 206 | if (groupThreadId < 64) 207 | sumVec[groupThreadId] += sumVec[groupThreadId + 64]; 208 | groupMemoryBarrierWithGroupSync(); 209 | if (groupThreadId < 32) 210 | sumVec[groupThreadId] += sumVec[groupThreadId + 32]; 211 | groupMemoryBarrierWithGroupSync(); 212 | if (groupThreadId < 16) 213 | sumVec[groupThreadId] += sumVec[groupThreadId + 16]; 214 | groupMemoryBarrierWithGroupSync(); 215 | if (groupThreadId < 8) 216 | sumVec[groupThreadId] += sumVec[groupThreadId + 8]; 217 | groupMemoryBarrierWithGroupSync(); 218 | if (groupThreadId < 4) 219 | sumVec[groupThreadId] += sumVec[groupThreadId + 4]; 220 | groupMemoryBarrierWithGroupSync(); 221 | if (groupThreadId < 2) 222 | sumVec[groupThreadId] += sumVec[groupThreadId + 2]; 223 | groupMemoryBarrierWithGroupSync(); 224 | if (groupThreadId == 0) 225 | dotV = sumVec[0] + sumVec[1]; 226 | groupMemoryBarrierWithGroupSync(); 227 | 228 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; 229 | ++subVector) { 230 | uint index = INBLOCK_ID; 231 | if (index >= limit - 1) { 232 | outDataBuffer.data[convertDataBufferTwoDIndexToOneDIndex( 233 | index, feature_buffer + BLOCK_OFFSET)] = 234 | tmp_data_private_cache[subVector] - 235 | 2.0 * uVec[index] * dotV / uLengthSquared; 236 | } 237 | } 238 | groupMemoryBarrierWithGroupSync(); 239 | } 240 | } 241 | 242 | uint tmpId; 243 | if (groupThreadId < FEATURES_COUNT) { 244 | rmat[groupThreadId][FEATURES_COUNT] = 245 | outDataBuffer.data[convertDataBufferTwoDIndexToOneDIndex( 246 | groupThreadId, FEATURES_COUNT + BLOCK_OFFSET)]; 247 | } else if ((tmpId = groupThreadId - FEATURES_COUNT) < FEATURES_COUNT) { 248 | rmat[tmpId][BUFFER_COUNT - 2] = 249 | outDataBuffer.data[convertDataBufferTwoDIndexToOneDIndex( 250 | tmpId, BUFFER_COUNT - 2 + BLOCK_OFFSET)]; 251 | } else if ((tmpId = tmpId - FEATURES_COUNT) < FEATURES_COUNT) { 252 | rmat[tmpId][BUFFER_COUNT - 1] = 253 | outDataBuffer.data[convertDataBufferTwoDIndexToOneDIndex( 254 | tmpId, BUFFER_COUNT - 1 + BLOCK_OFFSET)]; 255 | } 256 | groupMemoryBarrierWithGroupSync(); 257 | 258 | // Back substitution 259 | limit--; 260 | for (int i = BUFFER_COUNT - 4; i >= 0; i--) { 261 | if (rmat[limit][i] != 0.0) { 262 | if (groupThreadId < 3) { 263 | rmat[i][BUFFER_COUNT - groupThreadId - 1] = 264 | rmat[limit][BUFFER_COUNT - groupThreadId - 1] / rmat[limit][i]; 265 | } 266 | limit--; 267 | } else { 268 | if (groupThreadId < 3) { 269 | rmat[i][BUFFER_COUNT - groupThreadId - 1] = 0.0f; 270 | } 271 | } 272 | groupMemoryBarrierWithGroupSync(); 273 | if (groupThreadId < 3 * limit + 3) { 274 | uint rowId = limit - groupThreadId / 3; 275 | uint channel = BUFFER_COUNT - (groupThreadId % 3) - 1; 276 | rmat[rowId][channel] -= rmat[i][channel] * rmat[rowId][i]; 277 | } 278 | groupMemoryBarrierWithGroupSync(); 279 | } 280 | } 281 | 282 | void calculateFilteredColor(uint groupThreadId, uvec3 groupId, 283 | uint horizentalBlocksCount, 284 | 285 | uint frameIndex, 286 | ivec2 blockOffsets[BLOCK_OFFSETS_COUNT]) { 287 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; ++subVector) { 288 | uint index = INBLOCK_ID; 289 | uVec[index] = 0.0; 290 | gchannel[index] = 0.0; 291 | bchannel[index] = 0.0; 292 | } 293 | 294 | for (int col = 0; col < FEATURES_COUNT; col++) { 295 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; 296 | ++subVector) { 297 | uint index = INBLOCK_ID; 298 | 299 | float tmp = tmpDataBuffer.data[convertDataBufferTwoDIndexToOneDIndex( 300 | index, col + BLOCK_OFFSET)]; 301 | uVec[index] += rmat[col][FEATURES_COUNT] * tmp; 302 | gchannel[index] += rmat[col][FEATURES_COUNT + 1] * tmp; 303 | bchannel[index] += rmat[col][FEATURES_COUNT + 2] * tmp; 304 | } 305 | } 306 | 307 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; ++subVector) { 308 | uint index = INBLOCK_ID; 309 | ivec2 pixelIndices = getPixelIndices( 310 | index, groupId.x, horizentalBlocksCount, frameIndex, blockOffsets); 311 | 312 | if (pixelIndices.x < 0 || pixelIndices.y < 0 || 313 | pixelIndices.x >= screenDimension.resolution.x || 314 | pixelIndices.y >= screenDimension.resolution.y) { 315 | continue; 316 | } 317 | 318 | vec2 uv = convertPixelIndicesToUV(pixelIndices, screenDimension.resolution); 319 | 320 | uint pixelIndex = convertPixelIndicesToPixelIndex( 321 | pixelIndices, screenDimension.resolution); 322 | 323 | vec3 currentColor = vec3(uVec[index] < 0.0 ? 0.0 : uVec[index], 324 | gchannel[index] < 0.0 ? 0.0 : gchannel[index], 325 | bchannel[index] < 0.0 ? 0.0 : bchannel[index]); 326 | 327 | vec3 diffuse = 328 | texture(sampler2D(gDiffusePositionWTexture, sampler0), uv).xyz; 329 | currentColor = modulateAlbedo(currentColor, diffuse); 330 | 331 | curNoisyPixelBuffer.pixels[pixelIndex] = 332 | vec4(currentColor, curNoisyPixelBuffer.pixels[pixelIndex].w); 333 | } 334 | } 335 | 336 | void main() { 337 | uint groupThreadId = gl_LocalInvocationIndex; 338 | uvec3 groupId = gl_WorkGroupID; 339 | 340 | uint frame = uint(pushC.compressedData.x); 341 | uint horizentalBlocksCount = uint(pushC.compressedData.y); 342 | 343 | const ivec2 BLOCK_OFFSETS[BLOCK_OFFSETS_COUNT] = { 344 | ivec2(-30, -30), ivec2(-12, -22), ivec2(-24, -2), ivec2(-8, -16), 345 | ivec2(-26, -24), ivec2(-14, -4), ivec2(-4, -28), ivec2(-26, -16), 346 | ivec2(-4, -2), ivec2(-24, -32), ivec2(-10, -10), ivec2(-18, -18), 347 | ivec2(-12, -30), ivec2(-32, -4), ivec2(-2, -20), ivec2(-22, -12), 348 | }; 349 | 350 | // load features and colors to tmpData 351 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; ++subVector) { 352 | uint index = INBLOCK_ID; 353 | ivec2 pixelIndices = getPixelIndices( 354 | index, groupId.x, horizentalBlocksCount, frame, BLOCK_OFFSETS); 355 | pixelIndices = mirror2(pixelIndices, ivec2(screenDimension.resolution.x, 356 | screenDimension.resolution.y)); 357 | 358 | vec2 uv = convertPixelIndicesToUV(pixelIndices, screenDimension.resolution); 359 | 360 | vec3 worldPosition = 361 | texture(sampler2D(gPositionRoughnessTexture, sampler0), uv).xyz; 362 | vec3 worldNormal = 363 | texture(sampler2D(gNormalMetalnessTexture, sampler0), uv).xyz; 364 | 365 | uint pixelIndex = convertPixelIndicesToPixelIndex( 366 | pixelIndices, screenDimension.resolution); 367 | 368 | vec3 currentColor = curNoisyPixelBuffer.pixels[pixelIndex].rgb; 369 | 370 | tmpDataBuffer 371 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 0 + BLOCK_OFFSET)] = 372 | 1.0; 373 | tmpDataBuffer 374 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 1 + BLOCK_OFFSET)] = 375 | worldNormal.x; 376 | tmpDataBuffer 377 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 2 + BLOCK_OFFSET)] = 378 | worldNormal.y; 379 | tmpDataBuffer 380 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 3 + BLOCK_OFFSET)] = 381 | worldNormal.z; 382 | tmpDataBuffer 383 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 4 + BLOCK_OFFSET)] = 384 | worldPosition.x; 385 | tmpDataBuffer 386 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 5 + BLOCK_OFFSET)] = 387 | worldPosition.y; 388 | tmpDataBuffer 389 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 6 + BLOCK_OFFSET)] = 390 | worldPosition.z; 391 | tmpDataBuffer 392 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 7 + BLOCK_OFFSET)] = 393 | worldPosition.x * worldPosition.x; 394 | tmpDataBuffer 395 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 8 + BLOCK_OFFSET)] = 396 | worldPosition.y * worldPosition.y; 397 | tmpDataBuffer 398 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 9 + BLOCK_OFFSET)] = 399 | worldPosition.z * worldPosition.z; 400 | 401 | vec3 diffuse = 402 | texture(sampler2D(gDiffusePositionWTexture, sampler0), uv).xyz; 403 | currentColor = demodulateAlbedo(currentColor, diffuse); 404 | 405 | tmpDataBuffer 406 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 10 + BLOCK_OFFSET)] = 407 | currentColor.x; 408 | tmpDataBuffer 409 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 11 + BLOCK_OFFSET)] = 410 | currentColor.y; 411 | tmpDataBuffer 412 | .data[convertDataBufferTwoDIndexToOneDIndex(index, 12 + BLOCK_OFFSET)] = 413 | currentColor.z; 414 | } 415 | groupMemoryBarrierWithGroupSync(); 416 | 417 | // handle scaled feature data to out 418 | for (int feature_buffer = FEATURES_NOT_SCALED; 419 | feature_buffer < FEATURES_COUNT; ++feature_buffer) { 420 | uint subVector = 0; 421 | float tmpMax = tmpDataBuffer.data[convertDataBufferTwoDIndexToOneDIndex( 422 | INBLOCK_ID, feature_buffer + BLOCK_OFFSET)]; 423 | 424 | float tmpMin = tmpMax; 425 | for (++subVector; subVector < BLOCK_PIXELS / LOCAL_SIZE; ++subVector) { 426 | float value = tmpDataBuffer.data[convertDataBufferTwoDIndexToOneDIndex( 427 | INBLOCK_ID, feature_buffer + BLOCK_OFFSET)]; 428 | tmpMax = max(value, tmpMax); 429 | tmpMin = min(value, tmpMin); 430 | } 431 | sumVec[groupThreadId] = tmpMax; 432 | groupMemoryBarrierWithGroupSync(); 433 | 434 | // parallel reduction find max 435 | if (groupThreadId < 128) 436 | sumVec[groupThreadId] = 437 | max(sumVec[groupThreadId], sumVec[groupThreadId + 128]); 438 | groupMemoryBarrierWithGroupSync(); 439 | if (groupThreadId < 64) 440 | sumVec[groupThreadId] = 441 | max(sumVec[groupThreadId], sumVec[groupThreadId + 64]); 442 | groupMemoryBarrierWithGroupSync(); 443 | if (groupThreadId < 32) 444 | sumVec[groupThreadId] = 445 | max(sumVec[groupThreadId], sumVec[groupThreadId + 32]); 446 | groupMemoryBarrierWithGroupSync(); 447 | if (groupThreadId < 16) 448 | sumVec[groupThreadId] = 449 | max(sumVec[groupThreadId], sumVec[groupThreadId + 16]); 450 | groupMemoryBarrierWithGroupSync(); 451 | if (groupThreadId < 8) 452 | sumVec[groupThreadId] = 453 | max(sumVec[groupThreadId], sumVec[groupThreadId + 8]); 454 | groupMemoryBarrierWithGroupSync(); 455 | if (groupThreadId < 4) 456 | sumVec[groupThreadId] = 457 | max(sumVec[groupThreadId], sumVec[groupThreadId + 4]); 458 | groupMemoryBarrierWithGroupSync(); 459 | if (groupThreadId < 2) 460 | sumVec[groupThreadId] = 461 | max(sumVec[groupThreadId], sumVec[groupThreadId + 2]); 462 | groupMemoryBarrierWithGroupSync(); 463 | if (groupThreadId == 0) 464 | blockMax = max(sumVec[0], sumVec[1]); 465 | groupMemoryBarrierWithGroupSync(); 466 | 467 | sumVec[groupThreadId] = tmpMin; 468 | groupMemoryBarrierWithGroupSync(); 469 | 470 | // parallel reduction find min 471 | if (groupThreadId < 128) 472 | sumVec[groupThreadId] = 473 | min(sumVec[groupThreadId], sumVec[groupThreadId + 128]); 474 | groupMemoryBarrierWithGroupSync(); 475 | if (groupThreadId < 64) 476 | sumVec[groupThreadId] = 477 | min(sumVec[groupThreadId], sumVec[groupThreadId + 64]); 478 | groupMemoryBarrierWithGroupSync(); 479 | if (groupThreadId < 32) 480 | sumVec[groupThreadId] = 481 | min(sumVec[groupThreadId], sumVec[groupThreadId + 32]); 482 | groupMemoryBarrierWithGroupSync(); 483 | if (groupThreadId < 16) 484 | sumVec[groupThreadId] = 485 | min(sumVec[groupThreadId], sumVec[groupThreadId + 16]); 486 | groupMemoryBarrierWithGroupSync(); 487 | if (groupThreadId < 8) 488 | sumVec[groupThreadId] = 489 | min(sumVec[groupThreadId], sumVec[groupThreadId + 8]); 490 | groupMemoryBarrierWithGroupSync(); 491 | if (groupThreadId < 4) 492 | sumVec[groupThreadId] = 493 | min(sumVec[groupThreadId], sumVec[groupThreadId + 4]); 494 | groupMemoryBarrierWithGroupSync(); 495 | if (groupThreadId < 2) 496 | sumVec[groupThreadId] = 497 | min(sumVec[groupThreadId], sumVec[groupThreadId + 2]); 498 | groupMemoryBarrierWithGroupSync(); 499 | if (groupThreadId == 0) 500 | blockMin = min(sumVec[0], sumVec[1]); 501 | groupMemoryBarrierWithGroupSync(); 502 | 503 | // normalize feature 504 | if (blockMax - blockMin > 1.0) { 505 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; 506 | ++subVector) { 507 | uint oneDIndex = convertDataBufferTwoDIndexToOneDIndex( 508 | INBLOCK_ID, feature_buffer + BLOCK_OFFSET); 509 | float tmpData = 510 | (tmpDataBuffer.data[oneDIndex] - blockMin) / (blockMax - blockMin); 511 | 512 | outDataBuffer.data[oneDIndex] = tmpData; 513 | tmpDataBuffer.data[oneDIndex] = tmpData; 514 | } 515 | } else { 516 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; 517 | ++subVector) { 518 | uint oneDIndex = convertDataBufferTwoDIndexToOneDIndex( 519 | INBLOCK_ID, feature_buffer + BLOCK_OFFSET); 520 | float tmpData = tmpDataBuffer.data[oneDIndex] - blockMin; 521 | 522 | outDataBuffer.data[oneDIndex] = tmpData; 523 | tmpDataBuffer.data[oneDIndex] = tmpData; 524 | } 525 | } 526 | } 527 | 528 | // copy noise colors to out 529 | for (uint feature_buffer = FEATURES_COUNT; feature_buffer < BUFFER_COUNT; 530 | ++feature_buffer) { 531 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; 532 | ++subVector) { 533 | uint oneDIndex = convertDataBufferTwoDIndexToOneDIndex( 534 | INBLOCK_ID, feature_buffer + BLOCK_OFFSET); 535 | 536 | outDataBuffer.data[oneDIndex] = tmpDataBuffer.data[oneDIndex]; 537 | } 538 | } 539 | // copy not scaled features to out 540 | for (uint feature_buffer = 0; feature_buffer < FEATURES_NOT_SCALED; 541 | ++feature_buffer) { 542 | for (uint subVector = 0; subVector < BLOCK_PIXELS / LOCAL_SIZE; 543 | ++subVector) { 544 | uint oneDIndex = convertDataBufferTwoDIndexToOneDIndex( 545 | INBLOCK_ID, feature_buffer + BLOCK_OFFSET); 546 | 547 | outDataBuffer.data[oneDIndex] = tmpDataBuffer.data[oneDIndex]; 548 | } 549 | } 550 | groupMemoryBarrierWithGroupSync(); 551 | 552 | householderQRDecomposition(groupThreadId, groupId); 553 | 554 | calculateFilteredColor(groupThreadId, groupId, horizentalBlocksCount, 555 | 556 | frame, BLOCK_OFFSETS); 557 | } -------------------------------------------------------------------------------- /src/pass/gbuffer/GBufferPass.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | open Js.Typed_array; 6 | 7 | open StateType; 8 | 9 | let _mergeVertexData = ((vertices, normals)) => { 10 | let vertexCount = Geometry.computeVertexCount(vertices); 11 | 12 | // Log.print(("vertexCount:", vertexCount)) |> ignore; 13 | 14 | ArrayUtils.range(0, vertexCount) 15 | |> ArrayUtils.reduceOneParam( 16 | (. vertexBufferData, vertexIndex) => { 17 | // Log.print(("vertexIndex: ", vertexIndex)) |> ignore; 18 | let offset = vertexIndex * 6; 19 | let componentIndex = vertexIndex * 3; 20 | 21 | Float32Array.unsafe_set( 22 | vertexBufferData, 23 | offset, 24 | Array.unsafe_get(vertices, componentIndex), 25 | ); 26 | Float32Array.unsafe_set( 27 | vertexBufferData, 28 | offset + 1, 29 | Array.unsafe_get(vertices, componentIndex + 1), 30 | ); 31 | Float32Array.unsafe_set( 32 | vertexBufferData, 33 | offset + 2, 34 | Array.unsafe_get(vertices, componentIndex + 2), 35 | ); 36 | 37 | Float32Array.unsafe_set( 38 | vertexBufferData, 39 | offset + 3, 40 | Array.unsafe_get(normals, componentIndex), 41 | ); 42 | Float32Array.unsafe_set( 43 | vertexBufferData, 44 | offset + 4, 45 | Array.unsafe_get(normals, componentIndex + 1), 46 | ); 47 | Float32Array.unsafe_set( 48 | vertexBufferData, 49 | offset + 5, 50 | Array.unsafe_get(normals, componentIndex + 2), 51 | ); 52 | 53 | vertexBufferData; 54 | }, 55 | Float32Array.fromLength(vertexCount * 6), 56 | ); 57 | }; 58 | 59 | let _buildVertexAndIndexBufferMap = (device, allUniqueGeometries, state) => { 60 | allUniqueGeometries 61 | |> ArrayUtils.reduceOneParam( 62 | (. vertexAndIndexBufferMap, geometry) => { 63 | let vertexBufferData = 64 | Geometry.unsafeGetVertexData(geometry, state) |> _mergeVertexData; 65 | let indices = Geometry.unsafeGetIndexData(geometry, state); 66 | 67 | let vertexBuffer = 68 | device 69 | |> Device.createBuffer({ 70 | "size": vertexBufferData |> Float32Array.byteLength, 71 | "usage": BufferUsage.copy_dst lor BufferUsage.vertex, 72 | }); 73 | vertexBuffer |> Buffer.setSubFloat32Data(0, vertexBufferData); 74 | 75 | let indexBuffer = 76 | device 77 | |> Device.createBuffer({ 78 | "size": 79 | Js.Array.length(indices) * Uint32Array._BYTES_PER_ELEMENT, 80 | "usage": BufferUsage.copy_dst lor BufferUsage.index, 81 | }); 82 | indexBuffer |> Buffer.setSubUint32Data(0, Uint32Array.make(indices)); 83 | 84 | // Log.printComplete( 85 | // "vertex data:", 86 | // (geometry, vertexBufferData, indices), 87 | // ); 88 | 89 | vertexAndIndexBufferMap 90 | |> ImmutableSparseMap.set(geometry, (vertexBuffer, indexBuffer)); 91 | }, 92 | ImmutableSparseMap.createEmpty(), 93 | ); 94 | }; 95 | 96 | let _buildIndexCountMap = (allUniqueGeometries, state) => { 97 | allUniqueGeometries 98 | |> ArrayUtils.reduceOneParam( 99 | (. indexCountMap, geometry) => { 100 | indexCountMap 101 | |> ImmutableSparseMap.set( 102 | geometry, 103 | Geometry.unsafeGetIndexData(geometry, state) 104 | |> Geometry.computeIndexCount, 105 | ) 106 | }, 107 | ImmutableSparseMap.createEmpty(), 108 | ); 109 | }; 110 | 111 | let _buildVertexData = (device, allRenderGameObjects, state) => { 112 | let allUniqueGeometries = 113 | allRenderGameObjects 114 | |> Js.Array.map(renderGameObject => { 115 | GameObject.unsafeGetGeometry(renderGameObject, state) 116 | }) 117 | |> ArrayUtils2.removeDuplicateItems; 118 | 119 | ( 120 | _buildVertexAndIndexBufferMap(device, allUniqueGeometries, state), 121 | _buildIndexCountMap(allUniqueGeometries, state), 122 | ); 123 | }; 124 | 125 | let _createTextureData = (device, window, format, usage) => { 126 | let texture = 127 | device 128 | |> Device.createTexture( 129 | Texture.descriptor( 130 | ~size={ 131 | "width": Window.getWidth(window), 132 | "height": Window.getHeight(window), 133 | "depth": 1, 134 | }, 135 | ~arrayLayerCount=1, 136 | ~mipLevelCount=1, 137 | ~sampleCount=1, 138 | ~dimension="2d", 139 | ~format, 140 | ~usage, 141 | ), 142 | ); 143 | 144 | ( 145 | texture, 146 | texture |> Texture.createView(TextureView.descriptor(~format, ())), 147 | ); 148 | }; 149 | 150 | let _createRenderTargetData = (device, window, format) => { 151 | _createTextureData( 152 | device, 153 | window, 154 | format, 155 | TextureUsage.sampled lor TextureUsage.output_attachment, 156 | ); 157 | }; 158 | 159 | let init = (device, window, state) => { 160 | let modelBindGroupLayout = 161 | device 162 | |> Device.createBindGroupLayout({ 163 | "entries": [| 164 | BindGroupLayout.layoutBinding( 165 | ~binding=0, 166 | ~visibility=ShaderStage.vertex, 167 | ~type_="uniform-buffer", 168 | ~hasDynamicOffset=true, 169 | (), 170 | ), 171 | |], 172 | }); 173 | 174 | let pbrMaterialBindGroupLayout = 175 | device 176 | |> Device.createBindGroupLayout({ 177 | "entries": [| 178 | BindGroupLayout.layoutBinding( 179 | ~binding=0, 180 | ~visibility=ShaderStage.fragment, 181 | ~type_="uniform-buffer", 182 | ~hasDynamicOffset=true, 183 | (), 184 | ), 185 | |], 186 | }); 187 | 188 | let cameraBindGroupLayout = 189 | device 190 | |> Device.createBindGroupLayout({ 191 | "entries": [| 192 | BindGroupLayout.layoutBinding( 193 | ~binding=0, 194 | ~visibility=ShaderStage.vertex, 195 | ~type_="uniform-buffer", 196 | (), 197 | ), 198 | |], 199 | }); 200 | 201 | let allRenderGameObjects = RTXScene.getAllRenderGameObjects(state); 202 | 203 | let state = 204 | state |> Pass.GBufferPass.setRenderGameObjectArr(allRenderGameObjects); 205 | 206 | let ( 207 | offsetArrMap, 208 | modelBufferData, 209 | singleRenderGameObjectModelBufferSize, 210 | modelBuffer, 211 | ) = 212 | RTXBuffer.ModelBuffer.buildData(device, allRenderGameObjects, state); 213 | 214 | let state = 215 | state 216 | |> Pass.setUniformBufferData( 217 | "modelBuffer", 218 | (modelBufferData, modelBuffer), 219 | ); 220 | 221 | let modelBindGroup = 222 | device 223 | |> Device.createBindGroup({ 224 | "layout": modelBindGroupLayout, 225 | "entries": [| 226 | BindGroup.binding( 227 | ~binding=0, 228 | ~buffer=modelBuffer, 229 | ~offset=0, 230 | ~size=singleRenderGameObjectModelBufferSize, 231 | (), 232 | ), 233 | |], 234 | }); 235 | 236 | let state = 237 | state 238 | |> Pass.GBufferPass.addDynamicBindGroupData( 239 | 0, 240 | modelBindGroup, 241 | offsetArrMap, 242 | ); 243 | 244 | let singleRenderGameObjectPBRMaterialBufferSize = 245 | (4 + 4) * Float32Array._BYTES_PER_ELEMENT; 246 | let alignedPBRMaterialBufferBytes = 247 | ManageBuffer.UniformBuffer.getAlignedBufferBytes( 248 | singleRenderGameObjectPBRMaterialBufferSize, 249 | ); 250 | let alignedPBRMaterialBufferFloats = 251 | ManageBuffer.UniformBuffer.getAlignedBufferFloats( 252 | alignedPBRMaterialBufferBytes, 253 | ); 254 | let pbrMaterialBufferSize = 255 | (allRenderGameObjects |> Js.Array.length) * alignedPBRMaterialBufferBytes; 256 | 257 | let (pbrMaterialBufferData, _, offsetArrMap) = 258 | allRenderGameObjects 259 | |> ArrayUtils.reduceOneParam( 260 | (. (pbrMaterialBufferData, offset, offsetArrMap), renderGameObject) => { 261 | let material = 262 | GameObject.unsafeGetPBRMaterial(renderGameObject, state); 263 | 264 | let (pbrMaterialBufferData, newOffset) = 265 | pbrMaterialBufferData 266 | |> TypeArray.Float32Array.setFloatTuple3( 267 | offset, 268 | PBRMaterial.unsafeGetDiffuse(material, state), 269 | ); 270 | 271 | let (pbrMaterialBufferData, newOffset) = 272 | pbrMaterialBufferData 273 | |> TypeArray.Float32Array.setFloatTuple3( 274 | newOffset + 1, 275 | ( 276 | PBRMaterial.unsafeGetMetalness(material, state), 277 | PBRMaterial.unsafeGetRoughness(material, state), 278 | PBRMaterial.unsafeGetSpecular(material, state), 279 | ), 280 | ); 281 | 282 | ( 283 | pbrMaterialBufferData, 284 | offset + alignedPBRMaterialBufferFloats, 285 | offsetArrMap 286 | |> ImmutableSparseMap.set( 287 | renderGameObject, 288 | [| 289 | ManageBuffer.UniformBuffer.getAlignedBufferBytesFromFloats( 290 | offset, 291 | ), 292 | |], 293 | ), 294 | ); 295 | }, 296 | ( 297 | Float32Array.fromLength( 298 | pbrMaterialBufferSize / Float32Array._BYTES_PER_ELEMENT, 299 | ), 300 | 0, 301 | ImmutableSparseMap.createEmpty(), 302 | ), 303 | ); 304 | 305 | // Log.printComplete( 306 | // "pbrMaterialBufferData:", 307 | // (pbrMaterialBufferData, offsetArrMap), 308 | // ); 309 | 310 | let pbrMaterialBuffer = 311 | device 312 | |> Device.createBuffer({ 313 | "size": pbrMaterialBufferSize, 314 | "usage": BufferUsage.copy_dst lor BufferUsage.uniform, 315 | }); 316 | pbrMaterialBuffer |> Buffer.setSubFloat32Data(0, pbrMaterialBufferData); 317 | 318 | let pbrMaterialBindGroup = 319 | device 320 | |> Device.createBindGroup({ 321 | "layout": pbrMaterialBindGroupLayout, 322 | "entries": [| 323 | BindGroup.binding( 324 | ~binding=0, 325 | ~buffer=pbrMaterialBuffer, 326 | ~offset=0, 327 | ~size=singleRenderGameObjectPBRMaterialBufferSize, 328 | (), 329 | ), 330 | |], 331 | }); 332 | 333 | let state = 334 | state 335 | |> Pass.setUniformBufferData( 336 | "pbrMaterialBuffer", 337 | (pbrMaterialBufferData, pbrMaterialBuffer), 338 | ); 339 | 340 | let state = 341 | state 342 | |> Pass.GBufferPass.addDynamicBindGroupData( 343 | 1, 344 | pbrMaterialBindGroup, 345 | offsetArrMap, 346 | ); 347 | 348 | let (cameraBufferData, cameraBuffer) = 349 | RTXBuffer.CameraBuffer.unsafeGetCameraBufferData(state); 350 | 351 | let cameraBindGroup = 352 | device 353 | |> Device.createBindGroup({ 354 | "layout": cameraBindGroupLayout, 355 | "entries": [| 356 | BindGroup.binding( 357 | ~binding=0, 358 | ~buffer=cameraBuffer, 359 | ~offset=0, 360 | ~size=cameraBufferData |> Float32Array.byteLength, 361 | (), 362 | ), 363 | |], 364 | }); 365 | 366 | // Log.printComplete("cameraBufferData:", cameraBufferData); 367 | 368 | let state = 369 | state |> Pass.GBufferPass.addStaticBindGroupData(2, cameraBindGroup); 370 | 371 | let (vertexAndIndexBufferMap, indexCountMap) = 372 | _buildVertexData(device, allRenderGameObjects, state); 373 | 374 | let state = 375 | state 376 | |> Pass.GBufferPass.setVertexAndIndexBufferMap(vertexAndIndexBufferMap) 377 | |> Pass.GBufferPass.setIndexCountMap(indexCountMap); 378 | 379 | let baseShaderPath = "src/pass/gbuffer/shaders"; 380 | 381 | let vertexShaderModule = 382 | device 383 | |> Device.createShaderModule({ 384 | "code": 385 | WebGPUUtils.loadShaderFile({j|$(baseShaderPath)/gbuffer.vert|j}), 386 | }); 387 | let fragmentShaderModule = 388 | device 389 | |> Device.createShaderModule({ 390 | "code": 391 | WebGPUUtils.loadShaderFile({j|$(baseShaderPath)/gbuffer.frag|j}), 392 | }); 393 | 394 | let positionRoughnessRenderTargetFormat = "rgba16float"; 395 | let normalMetalnessRenderTargetFormat = "rgba16float"; 396 | let diffusePositionWRenderTargetFormat = "rgba8unorm"; 397 | // let specularRenderTargetFormat = "rgba8unorm"; 398 | let motionVectorDepthSpecularRenderTargetFormat = "rgba16float"; 399 | // let depthRenderTargetFormat = "r16float"; 400 | 401 | let depthTextureFormat = "depth24plus"; 402 | // let depthTextureFormat = "depth24plus-stencil8"; 403 | 404 | let pipeline = 405 | device 406 | |> Device.createRenderPipeline( 407 | Pipeline.Render.descriptor( 408 | ~layout= 409 | device 410 | |> Device.createPipelineLayout({ 411 | "bindGroupLayouts": [| 412 | modelBindGroupLayout, 413 | pbrMaterialBindGroupLayout, 414 | cameraBindGroupLayout, 415 | |], 416 | }), 417 | ~vertexStage={ 418 | Pipeline.Render.vertexStage( 419 | ~module_=vertexShaderModule, 420 | ~entryPoint="main", 421 | ); 422 | }, 423 | ~fragmentStage={ 424 | Pipeline.Render.fragmentStage( 425 | ~module_=fragmentShaderModule, 426 | ~entryPoint="main", 427 | ); 428 | }, 429 | ~primitiveTopology="triangle-list", 430 | ~vertexState= 431 | Pipeline.Render.vertexState( 432 | ~indexFormat="uint32", 433 | ~vertexBuffers=[| 434 | Pipeline.Render.vertexBuffer( 435 | ~arrayStride=6 * Float32Array._BYTES_PER_ELEMENT, 436 | ~attributes=[| 437 | Pipeline.Render.vertexAttribute( 438 | ~shaderLocation=0, 439 | ~offset=0, 440 | ~format="float3", 441 | ), 442 | Pipeline.Render.vertexAttribute( 443 | ~shaderLocation=1, 444 | ~offset=3 * Float32Array._BYTES_PER_ELEMENT, 445 | ~format="float3", 446 | ), 447 | |], 448 | (), 449 | ), 450 | |], 451 | (), 452 | ), 453 | ~rasterizationState=Pipeline.Render.rasterizationState(), 454 | ~colorStates=[| 455 | Pipeline.Render.colorState( 456 | ~format=positionRoughnessRenderTargetFormat, 457 | ~alphaBlend=Pipeline.Render.blendDescriptor(), 458 | ~colorBlend=Pipeline.Render.blendDescriptor(), 459 | ), 460 | Pipeline.Render.colorState( 461 | ~format=normalMetalnessRenderTargetFormat, 462 | ~alphaBlend=Pipeline.Render.blendDescriptor(), 463 | ~colorBlend=Pipeline.Render.blendDescriptor(), 464 | ), 465 | Pipeline.Render.colorState( 466 | ~format=diffusePositionWRenderTargetFormat, 467 | ~alphaBlend=Pipeline.Render.blendDescriptor(), 468 | ~colorBlend=Pipeline.Render.blendDescriptor(), 469 | ), 470 | // Pipeline.Render.colorState( 471 | // ~format=specularRenderTargetFormat, 472 | // ~alphaBlend=Pipeline.Render.blendDescriptor(), 473 | // ~colorBlend=Pipeline.Render.blendDescriptor(), 474 | // ), 475 | Pipeline.Render.colorState( 476 | ~format=motionVectorDepthSpecularRenderTargetFormat, 477 | ~alphaBlend=Pipeline.Render.blendDescriptor(), 478 | ~colorBlend=Pipeline.Render.blendDescriptor(), 479 | ), 480 | // Pipeline.Render.colorState( 481 | // ~format=depthRenderTargetFormat, 482 | // ~alphaBlend=Pipeline.Render.blendDescriptor(), 483 | // ~colorBlend=Pipeline.Render.blendDescriptor(), 484 | // ), 485 | |], 486 | ~depthStencilState= 487 | Pipeline.Render.depthStencilState( 488 | ~depthWriteEnabled=true, 489 | ~depthCompare="less", 490 | ~format=depthTextureFormat, 491 | ~stencilFront=Pipeline.Render.stencilStateFaceDescriptor(), 492 | ~stencilBack=Pipeline.Render.stencilStateFaceDescriptor(), 493 | ), 494 | (), 495 | ), 496 | ); 497 | 498 | let state = state |> Pass.GBufferPass.setPipeline(pipeline); 499 | 500 | let (positionRoughnessRenderTarget, positionRoughnessRenderTargetView) = 501 | _createRenderTargetData( 502 | device, 503 | window, 504 | positionRoughnessRenderTargetFormat, 505 | ); 506 | let (normalMetalnessRenderTarget, normalMetalnessRenderTargetView) = 507 | _createRenderTargetData( 508 | device, 509 | window, 510 | normalMetalnessRenderTargetFormat, 511 | ); 512 | let (diffusePositionWRenderTarget, diffusePositionWRenderTargetView) = 513 | _createRenderTargetData( 514 | device, 515 | window, 516 | diffusePositionWRenderTargetFormat, 517 | ); 518 | let (_, motionVectorDepthSpecularRenderTargetView) = 519 | _createRenderTargetData( 520 | device, 521 | window, 522 | motionVectorDepthSpecularRenderTargetFormat, 523 | ); 524 | // let (depthRenderTarget, depthRenderTargetView) = 525 | // _createRenderTargetData(device, window, depthRenderTargetFormat); 526 | 527 | let state = 528 | state 529 | |> Pass.setTextureView( 530 | "positionRoughnessRenderTargetView", 531 | positionRoughnessRenderTargetView, 532 | ) 533 | |> Pass.setTextureView( 534 | "normalMetalnessRenderTargetView", 535 | normalMetalnessRenderTargetView, 536 | ) 537 | |> Pass.setTextureView( 538 | "diffusePositionWRenderTargetView", 539 | diffusePositionWRenderTargetView, 540 | ) 541 | |> Pass.setTextureView( 542 | "motionVectorDepthSpecularRenderTargetView", 543 | motionVectorDepthSpecularRenderTargetView, 544 | ); 545 | // |> Pass.setTextureView("depthRenderTargetView", depthRenderTargetView); 546 | 547 | let (_, depthTextureView) = 548 | _createTextureData( 549 | device, 550 | window, 551 | depthTextureFormat, 552 | TextureUsage.output_attachment, 553 | ); 554 | 555 | let depthTexture = 556 | device 557 | |> Device.createTexture( 558 | Texture.descriptor( 559 | ~size={ 560 | "width": Window.getWidth(window), 561 | "height": Window.getHeight(window), 562 | "depth": 1, 563 | }, 564 | ~arrayLayerCount=1, 565 | ~mipLevelCount=1, 566 | ~sampleCount=1, 567 | ~dimension="2d", 568 | ~format=depthTextureFormat, 569 | ~usage=TextureUsage.output_attachment, 570 | ), 571 | ); 572 | 573 | let state = state |> Pass.GBufferPass.setDepthTextureView(depthTextureView); 574 | 575 | state; 576 | }; 577 | 578 | let _buildColorAttachment = (textureViewName, state) => { 579 | { 580 | "clearColor": { 581 | "r": 0.0, 582 | "g": 0.0, 583 | "b": 0.0, 584 | "a": 1.0, 585 | }, 586 | "loadOp": "clear", 587 | "storeOp": "store", 588 | "attachment": Pass.unsafeGetTextureView(textureViewName, state), 589 | }; 590 | }; 591 | 592 | let execute = (device, queue, state) => { 593 | let commandEncoder = 594 | device |> Device.createCommandEncoder(CommandEncoder.descriptor()); 595 | let renderPass = 596 | commandEncoder 597 | |> CommandEncoder.beginRenderPass( 598 | { 599 | PassEncoder.Render.descriptor( 600 | ~colorAttachments=[| 601 | _buildColorAttachment( 602 | "positionRoughnessRenderTargetView", 603 | state, 604 | ), 605 | _buildColorAttachment( 606 | "normalMetalnessRenderTargetView", 607 | state, 608 | ), 609 | _buildColorAttachment( 610 | "diffusePositionWRenderTargetView", 611 | state, 612 | ), 613 | // _buildColorAttachment("specularRenderTargetView", state), 614 | _buildColorAttachment( 615 | "motionVectorDepthSpecularRenderTargetView", 616 | state, 617 | ), 618 | // _buildColorAttachment("depthRenderTargetView", state), 619 | |], 620 | ~depthStencilAttachment={ 621 | "attachment": 622 | Pass.GBufferPass.unsafeGetDepthTextureView(state), 623 | "clearDepth": 1.0, 624 | "depthLoadOp": "clear", 625 | "depthStoreOp": "store", 626 | "clearStencil": 0, 627 | "stencilLoadOp": "clear", 628 | "stencilStoreOp": "store", 629 | }, 630 | (), 631 | ); 632 | }, 633 | ); 634 | renderPass 635 | |> PassEncoder.Render.setPipeline( 636 | Pass.GBufferPass.unsafeGetPipeline(state), 637 | ); 638 | Pass.GBufferPass.getStaticBindGroupDataArr(state) 639 | |> Js.Array.forEach(({setSlot, bindGroup}: staticBindGroupData) => { 640 | renderPass |> PassEncoder.Render.setBindGroup(setSlot, bindGroup) 641 | }); 642 | 643 | Pass.GBufferPass.getRenderGameObjectArr(state) 644 | |> Js.Array.forEach(renderGameObject => { 645 | // let transform = GameObject.unsafeGetTransform(renderGameObject, state); 646 | let geometry = GameObject.unsafeGetGeometry(renderGameObject, state); 647 | // Log.printComplete( 648 | // "draw geometry:", 649 | // ( 650 | // renderGameObject, 651 | // geometry, 652 | // Pass.GBufferPass.unsafeGetIndexCount(geometry, state), 653 | // ), 654 | // ); 655 | let (vertexBuffer, indexBuffer) = 656 | Pass.GBufferPass.unsafeGetVertexAndIndexBuffer(geometry, state); 657 | 658 | // TODO perf: judge last geometry 659 | renderPass |> PassEncoder.Render.setVertexBuffer(0, vertexBuffer); 660 | renderPass |> PassEncoder.Render.setIndexBuffer(indexBuffer); 661 | 662 | Pass.GBufferPass.getDynamicBindGroupDataArr(state) 663 | |> Js.Array.forEach( 664 | ({setSlot, bindGroup, offsetArrMap}: dynamicBindGroupData) => { 665 | renderPass 666 | |> PassEncoder.Render.setDynamicBindGroup( 667 | setSlot, 668 | bindGroup, 669 | offsetArrMap 670 | |> ImmutableSparseMap.unsafeGet(renderGameObject), 671 | ) 672 | }); 673 | 674 | renderPass 675 | |> PassEncoder.Render.drawIndexed( 676 | Pass.GBufferPass.unsafeGetIndexCount(geometry, state), 677 | 1, 678 | 0, 679 | 0, 680 | 0, 681 | ); 682 | }); 683 | 684 | renderPass |> PassEncoder.Render.endPass; 685 | 686 | queue |> Queue.submit([|commandEncoder |> CommandEncoder.finish|]); 687 | 688 | state; 689 | }; 690 | -------------------------------------------------------------------------------- /src/RTXScene.re: -------------------------------------------------------------------------------- 1 | open RaytracingFramework; 2 | 3 | open WebGPU; 4 | 5 | let _createSphere = 6 | ( 7 | (translation, rotation), 8 | (diffuse, specular, metalness, roughness), 9 | state, 10 | ) => { 11 | let (sphere, state) = GameObject.create(state); 12 | 13 | let (tran3, state) = Transform.create(state); 14 | let state = 15 | state 16 | |> Transform.setTranslation(tran3, translation) 17 | |> Transform.setRotation(tran3, rotation) 18 | |> Transform.setScale(tran3, (1., 1., 1.)); 19 | 20 | let radius = 2.; 21 | let bands = 20; 22 | 23 | let (geo3, state) = Geometry.create(state); 24 | let state = 25 | state 26 | |> Geometry.setVertexData( 27 | geo3, 28 | Geometry.buildSphereVertexData(radius, bands), 29 | ) 30 | |> Geometry.setIndexData(geo3, Geometry.buildSphereIndexData(bands)); 31 | 32 | let (mat3, state) = PBRMaterial.create(state); 33 | let state = 34 | state 35 | |> PBRMaterial.setDiffuse(mat3, diffuse) 36 | |> PBRMaterial.setSpecular(mat3, specular) 37 | |> PBRMaterial.setMetalness(mat3, Js.Math.min_float(metalness, 0.99)) 38 | |> PBRMaterial.setRoughness(mat3, Js.Math.max_float(0.01, roughness)); 39 | 40 | let (shader3, state) = Shader.create(state); 41 | let state = state |> Shader.setHitGroupIndex(shader3, 0); 42 | 43 | let state = 44 | state 45 | |> GameObject.addTransform(sphere, tran3) 46 | |> GameObject.addGeometry(sphere, geo3) 47 | |> GameObject.addPBRMaterial(sphere, mat3) 48 | |> GameObject.addShader(sphere, shader3); 49 | 50 | state; 51 | }; 52 | 53 | let _createPlane = 54 | ( 55 | (translation, rotation), 56 | (diffuse, specular, metalness, roughness), 57 | state, 58 | ) => { 59 | let (plane3, state) = GameObject.create(state); 60 | 61 | let (tran3, state) = Transform.create(state); 62 | let state = 63 | state 64 | |> Transform.setTranslation(tran3, translation) 65 | |> Transform.setRotation(tran3, rotation) 66 | |> Transform.setScale(tran3, (50., 50., 50.)); 67 | 68 | let (geo3, state) = Geometry.create(state); 69 | let state = 70 | state 71 | |> Geometry.setVertexData(geo3, Geometry.buildPlaneVertexData()) 72 | |> Geometry.setIndexData(geo3, Geometry.buildPlaneIndexData()); 73 | 74 | let (mat3, state) = PBRMaterial.create(state); 75 | let state = 76 | state 77 | |> PBRMaterial.setDiffuse(mat3, diffuse) 78 | |> PBRMaterial.setSpecular(mat3, specular) 79 | |> PBRMaterial.setMetalness(mat3, metalness) 80 | |> PBRMaterial.setRoughness(mat3, roughness); 81 | 82 | let (shader3, state) = Shader.create(state); 83 | let state = state |> Shader.setHitGroupIndex(shader3, 0); 84 | 85 | let state = 86 | state 87 | |> GameObject.addTransform(plane3, tran3) 88 | |> GameObject.addGeometry(plane3, geo3) 89 | |> GameObject.addPBRMaterial(plane3, mat3) 90 | |> GameObject.addShader(plane3, shader3); 91 | 92 | state; 93 | }; 94 | 95 | let _buildScene1 = state => { 96 | let (light1, state) = GameObject.create(state); 97 | 98 | let (directionLight1, state) = DirectionLight.create(state); 99 | let state = 100 | state 101 | |> DirectionLight.setIntensity(directionLight1, 1.) 102 | |> DirectionLight.setPosition(directionLight1, (0., 1., 1.)); 103 | 104 | let state = state |> GameObject.addDirectionLight(light1, directionLight1); 105 | 106 | let (light2, state) = GameObject.create(state); 107 | 108 | let (directionLight2, state) = DirectionLight.create(state); 109 | let state = 110 | state 111 | |> DirectionLight.setIntensity(directionLight2, 0.5) 112 | |> DirectionLight.setPosition(directionLight2, (1., 2., 1.)); 113 | 114 | let state = state |> GameObject.addDirectionLight(light2, directionLight2); 115 | 116 | let (camera1, state) = GameObject.create(state); 117 | 118 | let (cameraView1, state) = CameraView.create(state); 119 | let state = state |> CameraView.setCurrentCameraView(cameraView1); 120 | 121 | let (arcballCameraController1, state) = 122 | ArcballCameraController.create(state); 123 | let state = 124 | state 125 | |> ArcballCameraController.setCurrentArcballCameraController( 126 | arcballCameraController1, 127 | ) 128 | |> ArcballCameraController.setPhi( 129 | arcballCameraController1, 130 | Js.Math._PI /. 2., 131 | ) 132 | |> ArcballCameraController.setTheta( 133 | arcballCameraController1, 134 | Js.Math._PI /. 2., 135 | ) 136 | |> ArcballCameraController.setTarget( 137 | arcballCameraController1, 138 | (0., 0., 0.), 139 | ) 140 | |> ArcballCameraController.setRotateSpeed(arcballCameraController1, 1.) 141 | |> ArcballCameraController.setWheelSpeed(arcballCameraController1, 1.) 142 | |> ArcballCameraController.setDistance(arcballCameraController1, 20.); 143 | 144 | let state = 145 | state 146 | |> GameObject.addCameraView(camera1, cameraView1) 147 | |> GameObject.addArcballCameraController( 148 | camera1, 149 | arcballCameraController1, 150 | ); 151 | 152 | let (triangle1, state) = GameObject.create(state); 153 | 154 | let (tran1, state) = Transform.create(state); 155 | let state = 156 | state 157 | // |> Transform.setTranslation(tran1, (0., (-5.), 0.)) 158 | |> Transform.setTranslation(tran1, (0., 0., 0.)) 159 | // |> Transform.setRotation(tran1, (30., 45., 0.)) 160 | |> Transform.setRotation(tran1, (0., 20., 0.)) 161 | |> Transform.setScale(tran1, (1., 1., 1.)); 162 | 163 | let (geo1, state) = Geometry.create(state); 164 | let state = 165 | state 166 | |> Geometry.setVertexData(geo1, Geometry.buildTriangleVertexData()) 167 | |> Geometry.setIndexData(geo1, Geometry.buildTriangleIndexData()); 168 | 169 | let (mat1, state) = PBRMaterial.create(state); 170 | let state = 171 | state 172 | |> PBRMaterial.setDiffuse(mat1, (1.0, 0., 0.)) 173 | |> PBRMaterial.setSpecular(mat1, 0.95) 174 | |> PBRMaterial.setMetalness(mat1, 0.5) 175 | |> PBRMaterial.setRoughness(mat1, 0.5); 176 | // |> PBRMaterial.setIllum(mat1, 2) 177 | // |> PBRMaterial.setDissolve(mat1, 1.); 178 | 179 | let (shader1, state) = Shader.create(state); 180 | let state = state |> Shader.setHitGroupIndex(shader1, 0); 181 | 182 | let (transformAnim1, state) = TransformAnimation.create(state); 183 | let state = 184 | state |> TransformAnimation.setDynamicTransform(transformAnim1, 0); 185 | 186 | let state = 187 | state 188 | |> GameObject.addTransform(triangle1, tran1) 189 | |> GameObject.addGeometry(triangle1, geo1) 190 | |> GameObject.addPBRMaterial(triangle1, mat1) 191 | |> GameObject.addShader(triangle1, shader1) 192 | |> GameObject.addTransformAnimation(triangle1, transformAnim1); 193 | 194 | let (triangle2, state) = GameObject.create(state); 195 | 196 | let (tran2, state) = Transform.create(state); 197 | let state = 198 | state 199 | |> Transform.setTranslation(tran2, (3., 0., 5.)) 200 | |> Transform.setRotation(tran2, (0., 70., 0.)) 201 | |> Transform.setScale(tran2, (5., 5., 5.)); 202 | 203 | let (geo2, state) = Geometry.create(state); 204 | let state = 205 | state 206 | |> Geometry.setVertexData(geo2, Geometry.buildTriangleVertexData()) 207 | |> Geometry.setIndexData(geo2, Geometry.buildTriangleIndexData()); 208 | 209 | let (mat2, state) = PBRMaterial.create(state); 210 | let state = 211 | state 212 | |> PBRMaterial.setDiffuse(mat2, (0.0, 0.5, 0.5)) 213 | |> PBRMaterial.setSpecular(mat2, 0.95) 214 | |> PBRMaterial.setMetalness(mat2, 0.5) 215 | |> PBRMaterial.setRoughness(mat2, 0.5); 216 | 217 | let (shader2, state) = Shader.create(state); 218 | let state = state |> Shader.setHitGroupIndex(shader2, 0); 219 | 220 | // let (transformAnim2, state) = TransformAnimation.create(state); 221 | // let state = 222 | // state |> TransformAnimation.setDynamicTransform(transformAnim2, 0); 223 | 224 | let state = 225 | state 226 | |> GameObject.addTransform(triangle2, tran2) 227 | |> GameObject.addGeometry(triangle2, geo2) 228 | |> GameObject.addPBRMaterial(triangle2, mat2) 229 | |> GameObject.addShader(triangle2, shader2); 230 | // |> GameObject.addTransformAnimation(triangle2, transformAnim2); 231 | 232 | let state = 233 | _createSphere( 234 | ((10.0, 0.0, 10.0), (0., 0., 0.)), 235 | ( 236 | (Js.Math.random(), 0.0, Js.Math.random()), 237 | 0.95, 238 | Js.Math.random(), 239 | Js.Math.random(), 240 | ), 241 | state, 242 | ); 243 | 244 | // let state = _createPlane (((0., (-10.), (-5.)), (0., 0., 0.)), ((0., 1., 0.), 0.95, 0.9, 0.1), state); 245 | let state = 246 | _createPlane( 247 | ((0., (-10.), (-5.)), (0., 0., 0.)), 248 | ((0., 1., 0.), 0.95, 0.9, 0.3), 249 | state, 250 | ); 251 | 252 | state; 253 | }; 254 | 255 | let _buildScene2 = state => { 256 | let (light1, state) = GameObject.create(state); 257 | 258 | let (directionLight1, state) = DirectionLight.create(state); 259 | let state = 260 | state 261 | |> DirectionLight.setIntensity(directionLight1, 1.) 262 | |> DirectionLight.setPosition(directionLight1, (0., 1., 1.)); 263 | 264 | let state = state |> GameObject.addDirectionLight(light1, directionLight1); 265 | 266 | let (light2, state) = GameObject.create(state); 267 | 268 | let (directionLight2, state) = DirectionLight.create(state); 269 | let state = 270 | state 271 | |> DirectionLight.setIntensity(directionLight2, 0.5) 272 | |> DirectionLight.setPosition(directionLight2, (1., 2., 1.)); 273 | 274 | let state = state |> GameObject.addDirectionLight(light2, directionLight2); 275 | 276 | let (camera1, state) = GameObject.create(state); 277 | 278 | let (cameraView1, state) = CameraView.create(state); 279 | let state = state |> CameraView.setCurrentCameraView(cameraView1); 280 | 281 | let (arcballCameraController1, state) = 282 | ArcballCameraController.create(state); 283 | let state = 284 | state 285 | |> ArcballCameraController.setCurrentArcballCameraController( 286 | arcballCameraController1, 287 | ) 288 | |> ArcballCameraController.setPhi( 289 | arcballCameraController1, 290 | Js.Math._PI /. 2., 291 | ) 292 | |> ArcballCameraController.setTheta( 293 | arcballCameraController1, 294 | Js.Math._PI /. 2., 295 | ) 296 | |> ArcballCameraController.setTarget( 297 | arcballCameraController1, 298 | (0., 0., 0.), 299 | ) 300 | |> ArcballCameraController.setRotateSpeed(arcballCameraController1, 1.) 301 | |> ArcballCameraController.setWheelSpeed(arcballCameraController1, 1.) 302 | |> ArcballCameraController.setDistance(arcballCameraController1, 20.); 303 | 304 | let state = 305 | state 306 | |> GameObject.addCameraView(camera1, cameraView1) 307 | |> GameObject.addArcballCameraController( 308 | camera1, 309 | arcballCameraController1, 310 | ); 311 | 312 | let (triangle1, state) = GameObject.create(state); 313 | 314 | let (tran1, state) = Transform.create(state); 315 | let state = 316 | state 317 | // |> Transform.setTranslation(tran1, (0., (-5.), 0.)) 318 | |> Transform.setTranslation(tran1, (0., 0., 0.)) 319 | // |> Transform.setRotation(tran1, (30., 45., 0.)) 320 | |> Transform.setRotation(tran1, (0., 20., 0.)) 321 | |> Transform.setScale(tran1, (1., 1., 1.)); 322 | 323 | let (geo1, state) = Geometry.create(state); 324 | let state = 325 | state 326 | |> Geometry.setVertexData(geo1, Geometry.buildTriangleVertexData()) 327 | |> Geometry.setIndexData(geo1, Geometry.buildTriangleIndexData()); 328 | 329 | let (mat1, state) = PBRMaterial.create(state); 330 | let state = 331 | state 332 | |> PBRMaterial.setDiffuse(mat1, (1.0, 0., 0.)) 333 | |> PBRMaterial.setSpecular(mat1, 0.95) 334 | |> PBRMaterial.setMetalness(mat1, 0.5) 335 | |> PBRMaterial.setRoughness(mat1, 0.5); 336 | // |> PBRMaterial.setIllum(mat1, 2) 337 | // |> PBRMaterial.setDissolve(mat1, 1.); 338 | 339 | let (shader1, state) = Shader.create(state); 340 | let state = state |> Shader.setHitGroupIndex(shader1, 0); 341 | 342 | let (transformAnim1, state) = TransformAnimation.create(state); 343 | let state = 344 | state |> TransformAnimation.setDynamicTransform(transformAnim1, 0); 345 | 346 | let state = 347 | state 348 | |> GameObject.addTransform(triangle1, tran1) 349 | |> GameObject.addGeometry(triangle1, geo1) 350 | |> GameObject.addPBRMaterial(triangle1, mat1) 351 | |> GameObject.addShader(triangle1, shader1) 352 | |> GameObject.addTransformAnimation(triangle1, transformAnim1); 353 | 354 | let (triangle2, state) = GameObject.create(state); 355 | 356 | let (tran2, state) = Transform.create(state); 357 | let state = 358 | state 359 | |> Transform.setTranslation(tran2, (3., 0., 5.)) 360 | |> Transform.setRotation(tran2, (0., 70., 0.)) 361 | |> Transform.setScale(tran2, (5., 5., 5.)); 362 | 363 | let (geo2, state) = Geometry.create(state); 364 | let state = 365 | state 366 | |> Geometry.setVertexData(geo2, Geometry.buildTriangleVertexData()) 367 | |> Geometry.setIndexData(geo2, Geometry.buildTriangleIndexData()); 368 | 369 | let (mat2, state) = PBRMaterial.create(state); 370 | let state = 371 | state 372 | |> PBRMaterial.setDiffuse(mat2, (0.0, 0.5, 0.5)) 373 | |> PBRMaterial.setSpecular(mat2, 0.95) 374 | |> PBRMaterial.setMetalness(mat2, 0.5) 375 | |> PBRMaterial.setRoughness(mat2, 0.5); 376 | 377 | let (shader2, state) = Shader.create(state); 378 | let state = state |> Shader.setHitGroupIndex(shader2, 0); 379 | 380 | // let (transformAnim2, state) = TransformAnimation.create(state); 381 | // let state = 382 | // state |> TransformAnimation.setDynamicTransform(transformAnim2, 0); 383 | 384 | let state = 385 | state 386 | |> GameObject.addTransform(triangle2, tran2) 387 | |> GameObject.addGeometry(triangle2, geo2) 388 | |> GameObject.addPBRMaterial(triangle2, mat2) 389 | |> GameObject.addShader(triangle2, shader2); 390 | // |> GameObject.addTransformAnimation(triangle2, transformAnim2); 391 | 392 | let state = 393 | ArrayUtils.range(0, 300) 394 | |> ArrayUtils.reduceOneParam( 395 | (. state, index) => { 396 | // _createSphere (((( index * 2 - 500 ) |> float_of_int, Js.Math.random() *. 10., Js.Math.random() *. 100. -. 50.), (0.,0.,0.)), ((Js.Math.random(),0.0,Js.Math.random()), 0.95, Js.Math.random(), Js.Math.random()), state); 397 | _createSphere( 398 | ( 399 | ( 400 | Js.Math.random() *. 200. -. 100., 401 | Js.Math.random() *. 10., 402 | Js.Math.random() *. 100. -. 50., 403 | ), 404 | (0., 0., 0.), 405 | ), 406 | ( 407 | (Js.Math.random(), 0.0, Js.Math.random()), 408 | 0.95, 409 | Js.Math.random(), 410 | Js.Math.random(), 411 | ), 412 | state, 413 | ) 414 | }, 415 | state, 416 | ); 417 | 418 | let state = 419 | _createPlane( 420 | ((0., (-10.), (-5.)), (0., 0., 0.)), 421 | ((0., 1., 0.), 0.95, 0.9, 0.3), 422 | state, 423 | ); 424 | let state = 425 | _createPlane( 426 | ((0., (-10.), (-5.) -. 50.), (90., 0., 0.)), 427 | ((0., 0., 1.), 0.95, 0.5, 0.5), 428 | state, 429 | ); 430 | let state = 431 | _createPlane( 432 | ((0., (-10.), (-5.) +. 50.), ((-90.), 0., 0.)), 433 | ((0., 1., 0.), 0.95, 0.6, 0.3), 434 | state, 435 | ); 436 | 437 | state; 438 | }; 439 | 440 | let buildScene = state => { 441 | // _buildScene1(state); 442 | _buildScene2 (state); 443 | }; 444 | 445 | let getAllRenderGameObjects = state => { 446 | GameObject.getAllGeometryGameObjects(state); 447 | }; 448 | 449 | let _getAccumulatedFrameCount = () => 16; 450 | 451 | let init = (device, window, state) => { 452 | let (resolutionBufferSize, resolutionBuffer) = 453 | RTXBuffer.ResolutionBuffer.buildData(device, window); 454 | let (cameraBufferData, cameraBufferSize, cameraBuffer) = 455 | RTXBuffer.CameraBuffer.buildData(device, state); 456 | 457 | let ( 458 | rayTracingCommonDataBufferData, 459 | rayTracingCommonDataBufferSize, 460 | rayTracingCommonDataBuffer, 461 | ) = 462 | RTXBuffer.RayTracingCommonDataBuffer.buildData(device, state); 463 | 464 | let (pixelBufferSize, pixelBuffer) = 465 | RTXBuffer.PixelBuffer.buildData(device, window); 466 | 467 | let (prevNoisyPixelBufferSize, prevNoisyPixelBuffer) = 468 | RTXBuffer.PrevNoisyPixelBuffer.buildData(device, window); 469 | let (prevPositionBufferSize, prevPositionBuffer) = 470 | RTXBuffer.PrevPositionBuffer.buildData(device, window); 471 | let (prevNormalBufferSize, prevNormalBuffer) = 472 | RTXBuffer.PrevNormalBuffer.buildData(device, window); 473 | // let (acceptBoolBufferSize, acceptBoolBuffer) = 474 | // RTXBuffer.AcceptBoolBuffer.buildData(device, window); 475 | // let (prevFramePixelIndicesBufferSize, prevFramePixelIndicesBuffer) = 476 | // RTXBuffer.PrevFramePixelIndicesBuffer.buildData(device, window); 477 | 478 | let (tmpDataBufferSize, tmpDataBuffer) = 479 | RTXBuffer.Regression.TmpDataBuffer.buildData(device, window); 480 | let (outDataBufferSize, outDataBuffer) = 481 | RTXBuffer.Regression.OutDataBuffer.buildData(device, window); 482 | let ( 483 | regressionCommonDataBufferData, 484 | regressionCommonDataBufferSize, 485 | regressionCommonDataBuffer, 486 | ) = 487 | RTXBuffer.Regression.CommonDataBuffer.buildData(device, window); 488 | 489 | // let (accumulatedPrevFramePixelBufferSize, accumulatedPrevFramePixelBuffer) = 490 | // RTXBuffer.AccumulatedPrevFramePixelBuffer.buildData(device, window); 491 | 492 | let (historyPixelBufferSize, historyPixelBuffer) = 493 | RTXBuffer.HistoryPixelBuffer.buildData(device, window); 494 | let (taaBufferData, taaBufferSize, taaBuffer) = 495 | RTXBuffer.TAABuffer.buildData(device, state); 496 | let (commonDataBufferData, commonDataBufferSize, commonDataBuffer) = 497 | RTXBuffer.CommonDataBuffer.buildData(device, state); 498 | 499 | let (sceneDescBufferData, sceneDescBufferSize, sceneDescBuffer) = 500 | RTXBuffer.GetHitShadingData.SceneDescBuffer.buildData(device, state); 501 | let ( 502 | geometryOffsetDataBufferData, 503 | geometryOffsetDataBufferSize, 504 | geometryOffsetDataBuffer, 505 | ) = 506 | RTXBuffer.GetHitShadingData.GeometryOffsetDataBuffer.buildData( 507 | device, 508 | state, 509 | ); 510 | let (vertexBufferData, vertexBufferSize, vertexBuffer) = 511 | RTXBuffer.GetHitShadingData.VertexBuffer.buildData(device, state); 512 | let (indexBufferData, indexBufferSize, indexBuffer) = 513 | RTXBuffer.GetHitShadingData.IndexBuffer.buildData(device, state); 514 | let (pbrMaterialBufferData, pbrMaterialBufferSize, pbrMaterialBuffer) = 515 | RTXBuffer.GetHitShadingData.PBRMaterialBuffer.buildData(device, state); 516 | 517 | let (accumulationPixelBufferSize, accumulationPixelBuffer) = 518 | RTXBuffer.AccumulationPixelBuffer.buildData(device, window); 519 | let ( 520 | accumulationCommonDataBufferData, 521 | accumulationCommonDataBufferSize, 522 | accumulationCommonDataBuffer, 523 | ) = 524 | RTXBuffer.AccumulationCommonDataBuffer.buildData(device, state); 525 | 526 | state 527 | |> Pass.setAccumulatedFrameIndex(0) 528 | |> Pass.setJitterArr( 529 | TAAJitter.generateHaltonJiters( 530 | _getAccumulatedFrameCount(), 531 | // |> Log.printComplete("_getAccumulatedFrameCount") 532 | Window.getWidth(window), 533 | Window.getHeight(window), 534 | ), 535 | // |> Log.printComplete("HaltonJiters") 536 | ) 537 | |> RTXBuffer.ResolutionBuffer.setBufferData(( 538 | resolutionBufferSize, 539 | resolutionBuffer, 540 | )) 541 | |> RTXBuffer.CameraBuffer.setBufferData((cameraBufferData, cameraBuffer)) 542 | |> RTXBuffer.RayTracingCommonDataBuffer.setBufferData(( 543 | rayTracingCommonDataBufferData, 544 | rayTracingCommonDataBuffer, 545 | )) 546 | |> RTXBuffer.TAABuffer.setBufferData((taaBufferData, taaBuffer)) 547 | |> RTXBuffer.CommonDataBuffer.setBufferData(( 548 | commonDataBufferData, 549 | commonDataBuffer, 550 | )) 551 | |> RTXBuffer.PixelBuffer.setBufferData((pixelBufferSize, pixelBuffer)) 552 | |> RTXBuffer.PrevNoisyPixelBuffer.setBufferData(( 553 | prevNoisyPixelBufferSize, 554 | prevNoisyPixelBuffer, 555 | )) 556 | |> RTXBuffer.PrevPositionBuffer.setBufferData(( 557 | prevPositionBufferSize, 558 | prevPositionBuffer, 559 | )) 560 | |> RTXBuffer.PrevNormalBuffer.setBufferData(( 561 | prevNormalBufferSize, 562 | prevNormalBuffer, 563 | )) 564 | // |> RTXBuffer.AcceptBoolBuffer.setBufferData(( 565 | // acceptBoolBufferSize, 566 | // acceptBoolBuffer, 567 | // )) 568 | // |> RTXBuffer.PrevFramePixelIndicesBuffer.setBufferData(( 569 | // prevFramePixelIndicesBufferSize, 570 | // prevFramePixelIndicesBuffer, 571 | // )) 572 | |> RTXBuffer.Regression.TmpDataBuffer.setBufferData(( 573 | tmpDataBufferSize, 574 | tmpDataBuffer, 575 | )) 576 | |> RTXBuffer.Regression.OutDataBuffer.setBufferData(( 577 | outDataBufferSize, 578 | outDataBuffer, 579 | )) 580 | |> RTXBuffer.Regression.CommonDataBuffer.setBufferData(( 581 | regressionCommonDataBufferData, 582 | regressionCommonDataBuffer, 583 | )) 584 | // |> RTXBuffer.AccumulatedPrevFramePixelBuffer.setBufferData(( 585 | // accumulatedPrevFramePixelBufferSize, 586 | // accumulatedPrevFramePixelBuffer, 587 | // )) 588 | |> RTXBuffer.HistoryPixelBuffer.setBufferData(( 589 | historyPixelBufferSize, 590 | historyPixelBuffer, 591 | )) 592 | |> RTXBuffer.GetHitShadingData.SceneDescBuffer.setBufferData(( 593 | sceneDescBufferSize, 594 | sceneDescBufferData, 595 | sceneDescBuffer, 596 | )) 597 | |> RTXBuffer.GetHitShadingData.GeometryOffsetDataBuffer.setBufferData(( 598 | geometryOffsetDataBufferSize, 599 | geometryOffsetDataBuffer, 600 | )) 601 | |> RTXBuffer.GetHitShadingData.VertexBuffer.setBufferData(( 602 | vertexBufferSize, 603 | vertexBuffer, 604 | )) 605 | |> RTXBuffer.GetHitShadingData.IndexBuffer.setBufferData(( 606 | indexBufferSize, 607 | indexBuffer, 608 | )) 609 | |> RTXBuffer.GetHitShadingData.PBRMaterialBuffer.setBufferData(( 610 | pbrMaterialBufferSize, 611 | pbrMaterialBuffer, 612 | )) 613 | |> RTXBuffer.AccumulationPixelBuffer.setBufferData(( 614 | accumulationPixelBufferSize, 615 | accumulationPixelBuffer, 616 | )) 617 | |> RTXBuffer.AccumulationCommonDataBuffer.setBufferData(( 618 | accumulationCommonDataBufferData, 619 | accumulationCommonDataBuffer, 620 | )); 621 | }; 622 | 623 | let _updateRayTracingData = state => { 624 | state 625 | |> RTXBuffer.CommonDataBuffer.update( 626 | Director.getFrameIndex(state), 627 | DirectionLight.getLightCount(state), 628 | ); 629 | }; 630 | 631 | let _updateRegressionData = state => { 632 | state 633 | |> RTXBuffer.Regression.CommonDataBuffer.update( 634 | Director.getFrameIndex(state), 635 | ); 636 | }; 637 | 638 | let _updateCameraData = (window, state) => { 639 | let currentCameraView = state |> CameraView.unsafeGetCurrentCameraView; 640 | 641 | let lastViewProjectionMatrixOpt = 642 | Pass.GBufferPass.getLastViewProjectionMatrix(state); 643 | 644 | let currentArcballCameraController = 645 | state |> ArcballCameraController.unsafeGetCurrentArcballCameraController; 646 | let state = 647 | state 648 | |> CameraView.update( 649 | ( 650 | (Window.getWidth(window) |> float_of_int) 651 | /. (Window.getHeight(window) |> float_of_int), 652 | 180.0 *. 2. /. 5., 653 | 0.1, 654 | 4096.0, 655 | ), 656 | ( 657 | ArcballCameraController.getLookFrom( 658 | currentArcballCameraController, 659 | state, 660 | ), 661 | ArcballCameraController.unsafeGetTarget( 662 | currentArcballCameraController, 663 | state, 664 | ), 665 | (0., 1., 0.), 666 | ), 667 | ); 668 | 669 | let viewMatrix = CameraView.unsafeGetViewMatrix(currentCameraView, state); 670 | let projectionMatrix = 671 | CameraView.unsafeGetProjectionMatrix(currentCameraView, state); 672 | let state = 673 | state 674 | |> Pass.GBufferPass.setLastViewProjectionMatrix( 675 | Matrix4.createIdentityMatrix4() 676 | |> Matrix4.multiply(projectionMatrix, viewMatrix), 677 | ); 678 | 679 | let state = 680 | state 681 | |> RTXBuffer.CameraBuffer.update( 682 | CameraView.unsafeGetCameraPosition(currentCameraView, state), 683 | viewMatrix, 684 | projectionMatrix, 685 | lastViewProjectionMatrixOpt, 686 | ); 687 | 688 | state; 689 | }; 690 | 691 | let _updateJitterData = state => { 692 | let state = 693 | state 694 | |> RTXBuffer.TAABuffer.update( 695 | Pass.getJitter( 696 | Pass.getAccumulatedFrameIndex(state), 697 | // |> Log.printComplete("getAccumulatedFrameCount") 698 | state, 699 | ), 700 | ); 701 | 702 | state 703 | |> Pass.setAccumulatedFrameIndex( 704 | (Pass.getAccumulatedFrameIndex(state) |> succ) 705 | mod _getAccumulatedFrameCount(), 706 | ); 707 | }; 708 | 709 | let _updateAccumulationData = state => { 710 | let currentCameraView = state |> CameraView.unsafeGetCurrentCameraView; 711 | 712 | let viewMatrix = CameraView.unsafeGetViewMatrix(currentCameraView, state); 713 | 714 | let (accumFrameCount, state) = 715 | Pass.AccumulationPass.isCameraMove(viewMatrix, state) 716 | ? { 717 | let (accumFrameCount, state) = 718 | state |> Pass.AccumulationPass.resetAccumFrameCount; 719 | 720 | let state = state |> RTXBuffer.AccumulationPixelBuffer.clear; 721 | 722 | (accumFrameCount, state); 723 | } 724 | : { 725 | Pass.AccumulationPass.increaseAccumFrameCount(state); 726 | }; 727 | Log.print(("accum:", accumFrameCount)) |> ignore; 728 | 729 | state 730 | |> RTXBuffer.AccumulationCommonDataBuffer.update( 731 | accumFrameCount, 732 | Pass.AccumulationPass.convertCanDenoiseToFloat(state), 733 | ) 734 | |> Pass.AccumulationPass.setLastViewMatrix(viewMatrix); 735 | }; 736 | 737 | let _updateTransformAnim = (time, state) => { 738 | TransformAnimation.getAllDynamicTransforms(state) 739 | |> ArrayUtils.reduceOneParam( 740 | (. state, transform) => { 741 | let (tx, ty, tz) = Transform.getTranslation(transform, state); 742 | let (rx, ry, rz) = Transform.getRotation(transform, state); 743 | 744 | let newTx = tx +. 0.3 *. time /. 20.0; 745 | let newTx = newTx > 10.0 ? 0.0 : newTx; 746 | 747 | state 748 | |> Transform.setTranslation(transform, (newTx, ty, tz)) 749 | |> Transform.setRotation(transform, (rx, ry +. time /. 20.0, rz)); 750 | }, 751 | state, 752 | ); 753 | }; 754 | 755 | let _updateTransformData = (time, device, queue, state) => { 756 | let allRenderGameObjects = getAllRenderGameObjects(state); 757 | 758 | let state = 759 | allRenderGameObjects 760 | |> ArrayUtils.reduceOneParam( 761 | (. state, renderGameObject) => { 762 | state 763 | |> Pass.GBufferPass.setLastModelMatrix( 764 | GameObject.unsafeGetTransform(renderGameObject, state), 765 | Transform.buildModelMatrix( 766 | GameObject.unsafeGetTransform(renderGameObject, state), 767 | state, 768 | ), 769 | ) 770 | }, 771 | state, 772 | ); 773 | 774 | let state = state |> _updateTransformAnim(time); 775 | 776 | // let state = 777 | // state 778 | // |> ManageAccelerationContainer.updateInstanceContainer(device, queue); 779 | 780 | let state = 781 | state 782 | |> RTXBuffer.ModelBuffer.update(allRenderGameObjects) 783 | |> RTXBuffer.GetHitShadingData.SceneDescBuffer.update( 784 | allRenderGameObjects, 785 | ); 786 | 787 | state; 788 | }; 789 | 790 | let update = (device, queue, window, state) => { 791 | state 792 | |> _updateRayTracingData 793 | |> _updateRegressionData 794 | |> _updateCameraData(window) 795 | |> _updateTransformData(Director.getTime(state), device, queue) 796 | |> _updateJitterData 797 | |> _updateAccumulationData; 798 | }; 799 | --------------------------------------------------------------------------------