@zephyr3d/scene 0.9.21 → 0.9.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation/joint_dynamics/collision.js +1 -7
- package/dist/animation/joint_dynamics/collision.js.map +1 -1
- package/dist/animation/joint_dynamics/constraints.js +2 -17
- package/dist/animation/joint_dynamics/constraints.js.map +1 -1
- package/dist/animation/joint_dynamics/controller.js +2 -20
- package/dist/animation/joint_dynamics/controller.js.map +1 -1
- package/dist/animation/joint_dynamics/joint_dynamics_system.js +1 -3
- package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
- package/dist/animation/joint_dynamics/solver.js +14 -60
- package/dist/animation/joint_dynamics/solver.js.map +1 -1
- package/dist/animation/joint_dynamics/types.js +3 -3
- package/dist/animation/joint_dynamics/types.js.map +1 -1
- package/dist/app/app.js +23 -0
- package/dist/app/app.js.map +1 -1
- package/dist/app/scriptregistry.js +16 -53
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/assetmanager.js +2 -0
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/model.js +22 -0
- package/dist/asset/model.js.map +1 -1
- package/dist/blitter/bilateralblur.js +3 -1
- package/dist/blitter/bilateralblur.js.map +1 -1
- package/dist/blitter/blitter.js +3 -3
- package/dist/blitter/blitter.js.map +1 -1
- package/dist/camera/camera.js +398 -45
- package/dist/camera/camera.js.map +1 -1
- package/dist/camera/perspectivecamera.js +69 -2
- package/dist/camera/perspectivecamera.js.map +1 -1
- package/dist/index.d.ts +9100 -8712
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/material/blinn.js +1 -1
- package/dist/material/blinn.js.map +1 -1
- package/dist/material/lambert.js +3 -3
- package/dist/material/lambert.js.map +1 -1
- package/dist/material/material.js +8 -5
- package/dist/material/material.js.map +1 -1
- package/dist/material/meshmaterial.js +17 -10
- package/dist/material/meshmaterial.js.map +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
- package/dist/material/mixins/lightmodel/lambert.js +1 -1
- package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +21 -6
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/lit.js +33 -11
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/mixins/pbr/brdf.js +44 -12
- package/dist/material/mixins/pbr/brdf.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +149 -14
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/mtoon.js +7 -4
- package/dist/material/mtoon.js.map +1 -1
- package/dist/material/pbrblueprint.js +5 -1
- package/dist/material/pbrblueprint.js.map +1 -1
- package/dist/material/pbrmr.js +1 -1
- package/dist/material/pbrmr.js.map +1 -1
- package/dist/material/pbrsg.js +1 -1
- package/dist/material/pbrsg.js.map +1 -1
- package/dist/material/shader/helper.js +186 -11
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/skin.js +2 -2
- package/dist/material/skin.js.map +1 -1
- package/dist/material/terrain-cm.js +5 -5
- package/dist/material/terrain-cm.js.map +1 -1
- package/dist/material/water.js +6 -4
- package/dist/material/water.js.map +1 -1
- package/dist/posteffect/bloom.js +54 -4
- package/dist/posteffect/bloom.js.map +1 -1
- package/dist/posteffect/compositor.js +41 -0
- package/dist/posteffect/compositor.js.map +1 -1
- package/dist/posteffect/posteffect.js +51 -0
- package/dist/posteffect/posteffect.js.map +1 -1
- package/dist/posteffect/sao.js +7 -6
- package/dist/posteffect/sao.js.map +1 -1
- package/dist/posteffect/skinsss.js +3 -3
- package/dist/posteffect/skinsss.js.map +1 -1
- package/dist/posteffect/ssgi.js +1196 -0
- package/dist/posteffect/ssgi.js.map +1 -0
- package/dist/posteffect/ssr.js +83 -45
- package/dist/posteffect/ssr.js.map +1 -1
- package/dist/posteffect/sss.js +137 -49
- package/dist/posteffect/sss.js.map +1 -1
- package/dist/posteffect/taa.js +5 -4
- package/dist/posteffect/taa.js.map +1 -1
- package/dist/posteffect/tonemap.js +15 -3
- package/dist/posteffect/tonemap.js.map +1 -1
- package/dist/render/abuffer_oit.js +2 -2
- package/dist/render/abuffer_oit.js.map +1 -1
- package/dist/render/cluster_light.js +12 -6
- package/dist/render/cluster_light.js.map +1 -1
- package/dist/render/drawable_mixin.js +8 -5
- package/dist/render/drawable_mixin.js.map +1 -1
- package/dist/render/dualdepthpeeling_oit.js +10 -5
- package/dist/render/dualdepthpeeling_oit.js.map +1 -1
- package/dist/render/envlight.js +298 -5
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/gpu_picking.js +7 -5
- package/dist/render/gpu_picking.js.map +1 -1
- package/dist/render/hzb.js +28 -19
- package/dist/render/hzb.js.map +1 -1
- package/dist/render/lightpass.js +18 -4
- package/dist/render/lightpass.js.map +1 -1
- package/dist/render/render_queue.js +37 -4
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/renderer.js +8 -3
- package/dist/render/renderer.js.map +1 -1
- package/dist/render/rendergraph/blackboard.js +20 -48
- package/dist/render/rendergraph/blackboard.js.map +1 -1
- package/dist/render/rendergraph/device_pool_allocator.js +18 -58
- package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
- package/dist/render/rendergraph/executor.js +89 -115
- package/dist/render/rendergraph/executor.js.map +1 -1
- package/dist/render/rendergraph/forward_plus_builder.js +1003 -715
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/frame_graph_context.js +41 -0
- package/dist/render/rendergraph/frame_graph_context.js.map +1 -0
- package/dist/render/rendergraph/frame_resource_requirements.js +14 -0
- package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -0
- package/dist/render/rendergraph/history_resource_manager.js +74 -140
- package/dist/render/rendergraph/history_resource_manager.js.map +1 -1
- package/dist/render/rendergraph/history_resources.js +7 -5
- package/dist/render/rendergraph/history_resources.js.map +1 -1
- package/dist/render/rendergraph/render_context.js +19 -0
- package/dist/render/rendergraph/render_context.js.map +1 -0
- package/dist/render/rendergraph/render_pipeline.js +315 -0
- package/dist/render/rendergraph/render_pipeline.js.map +1 -0
- package/dist/render/rendergraph/rendergraph.js +158 -141
- package/dist/render/rendergraph/rendergraph.js.map +1 -1
- package/dist/render/rendergraph/scene_render_context.js +267 -0
- package/dist/render/rendergraph/scene_render_context.js.map +1 -0
- package/dist/render/rendergraph/texture_affinity_cache.js +19 -0
- package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -0
- package/dist/render/rendergraph/types.js +19 -31
- package/dist/render/rendergraph/types.js.map +1 -1
- package/dist/render/renderpass.js +3 -3
- package/dist/render/renderpass.js.map +1 -1
- package/dist/render/shadow_mask_pass.js +10 -6
- package/dist/render/shadow_mask_pass.js.map +1 -1
- package/dist/render/sky.js +197 -35
- package/dist/render/sky.js.map +1 -1
- package/dist/render/weightedblended_oit.js +4 -3
- package/dist/render/weightedblended_oit.js.map +1 -1
- package/dist/scene/basesprite.js +2 -0
- package/dist/scene/basesprite.js.map +1 -1
- package/dist/scene/batchgroup.js +10 -0
- package/dist/scene/batchgroup.js.map +1 -1
- package/dist/scene/environment.js +61 -2
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/light.js +178 -10
- package/dist/scene/light.js.map +1 -1
- package/dist/scene/meshdrawable.js +89 -2
- package/dist/scene/meshdrawable.js.map +1 -1
- package/dist/scene/msdftext.js +2 -0
- package/dist/scene/msdftext.js.map +1 -1
- package/dist/scene/msdftextsprite.js +2 -0
- package/dist/scene/msdftextsprite.js.map +1 -1
- package/dist/scene/particlesys.js +2 -0
- package/dist/scene/particlesys.js.map +1 -1
- package/dist/scene/scene.js +34 -1
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/terrain-cm/grass.js +2 -1
- package/dist/scene/terrain-cm/grass.js.map +1 -1
- package/dist/scene/terrain-cm/terrain-cm.js +2 -0
- package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
- package/dist/scene/water.js +2 -0
- package/dist/scene/water.js.map +1 -1
- package/dist/shaders/atmosphere.js +5 -4
- package/dist/shaders/atmosphere.js.map +1 -1
- package/dist/shaders/fog.js +10 -3
- package/dist/shaders/fog.js.map +1 -1
- package/dist/shaders/shadow.js +96 -29
- package/dist/shaders/shadow.js.map +1 -1
- package/dist/shaders/ssgi.js +63 -0
- package/dist/shaders/ssgi.js.map +1 -0
- package/dist/shaders/ssgi_reprojection.js +118 -0
- package/dist/shaders/ssgi_reprojection.js.map +1 -0
- package/dist/shaders/ssr.js +322 -154
- package/dist/shaders/ssr.js.map +1 -1
- package/dist/shadow/esm.js +13 -8
- package/dist/shadow/esm.js.map +1 -1
- package/dist/shadow/pcf_opt.js +15 -12
- package/dist/shadow/pcf_opt.js.map +1 -1
- package/dist/shadow/pcf_pd.js +15 -12
- package/dist/shadow/pcf_pd.js.map +1 -1
- package/dist/shadow/pcss.js +17 -11
- package/dist/shadow/pcss.js.map +1 -1
- package/dist/shadow/shadow_impl.js +20 -2
- package/dist/shadow/shadow_impl.js.map +1 -1
- package/dist/shadow/shadowmapper.js +10 -3
- package/dist/shadow/shadowmapper.js.map +1 -1
- package/dist/shadow/ssm.js +16 -13
- package/dist/shadow/ssm.js.map +1 -1
- package/dist/shadow/vsm.js +10 -8
- package/dist/shadow/vsm.js.map +1 -1
- package/dist/utility/physical.js +74 -0
- package/dist/utility/physical.js.map +1 -0
- package/dist/utility/rendermipmap.js +2 -2
- package/dist/utility/rendermipmap.js.map +1 -1
- package/dist/utility/serialization/manager.js +3 -1
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +3 -1
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/batch.js +3 -1
- package/dist/utility/serialization/scene/batch.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +598 -2
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/light.js +180 -9
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +43 -3
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +3 -1
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +3 -1
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/scene/particle.js +3 -1
- package/dist/utility/serialization/scene/particle.js.map +1 -1
- package/dist/utility/serialization/scene/primitive.js +2 -0
- package/dist/utility/serialization/scene/primitive.js.map +1 -1
- package/dist/utility/serialization/scene/scene.js +70 -0
- package/dist/utility/serialization/scene/scene.js.map +1 -1
- package/dist/utility/serialization/scene/sprite.js +3 -1
- package/dist/utility/serialization/scene/sprite.js.map +1 -1
- package/dist/utility/serialization/scene/terrain.js +3 -1
- package/dist/utility/serialization/scene/terrain.js.map +1 -1
- package/dist/utility/serialization/scene/text.js +3 -0
- package/dist/utility/serialization/scene/text.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +3 -1
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/values.js +2 -3
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
- package/dist/animation/joint_dynamics/convex_collider.js +0 -320
- package/dist/animation/joint_dynamics/convex_collider.js.map +0 -1
package/dist/shaders/ssr.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ShaderHelper } from '../material/shader/helper.js';
|
|
2
|
+
import { REVERSE_Z } from '@zephyr3d/base';
|
|
2
3
|
|
|
3
|
-
const MAX_FLOAT_VALUE = 3.402823466e38;
|
|
4
4
|
/** @internal */ function SSR_calcJitter(scope, viewPos, roughness) {
|
|
5
5
|
const pb = scope.$builder;
|
|
6
6
|
pb.func('SSR_calcJitter', [
|
|
@@ -21,14 +21,14 @@ const MAX_FLOAT_VALUE = 3.402823466e38;
|
|
|
21
21
|
pb.vec3('p'),
|
|
22
22
|
pb.mat4('mat')
|
|
23
23
|
], function() {
|
|
24
|
-
this.$l.c = pb.sub(pb.mul(this.p, 2), pb.
|
|
24
|
+
this.$l.c = pb.vec3(pb.sub(pb.mul(this.p.xy, 2), pb.vec2(1)), ShaderHelper.deviceDepthToClipZ(this, this.p.z));
|
|
25
25
|
this.$l.u = pb.mul(this.mat, pb.vec4(this.c, 1));
|
|
26
26
|
this.u = pb.div(this.u, this.u.w);
|
|
27
27
|
this.$return(this.u.xyz);
|
|
28
28
|
});
|
|
29
29
|
return scope.invProjectPosition(pos, mat);
|
|
30
30
|
}
|
|
31
|
-
/** @internal */ function validateHit(scope, hit2D, hit3D, surfaceZ, thickness, uv, traceRay, viewMatrix, invProjMatrix, textureSize, normalTexture) {
|
|
31
|
+
/** @internal */ function validateHit(scope, hit2D, hit3D, surfaceZ, thickness, uv, traceRay, viewMatrix, invProjMatrix, textureSize, normalTexture, debugValidationOut) {
|
|
32
32
|
const pb = scope.$builder;
|
|
33
33
|
const funcName = hit3D ? 'SSR_validateHit_HiZ' : 'SSR_validateHit';
|
|
34
34
|
pb.func(funcName, [
|
|
@@ -44,19 +44,34 @@ const MAX_FLOAT_VALUE = 3.402823466e38;
|
|
|
44
44
|
pb.vec3('viewSpaceRayDirection'),
|
|
45
45
|
pb.mat4('viewMatrix'),
|
|
46
46
|
pb.mat4('invProjMatrix'),
|
|
47
|
-
pb.vec4('textureSize')
|
|
47
|
+
pb.vec4('textureSize'),
|
|
48
|
+
...debugValidationOut ? [
|
|
49
|
+
pb.vec3('debugValidation').out()
|
|
50
|
+
] : []
|
|
48
51
|
], function() {
|
|
52
|
+
if (debugValidationOut) {
|
|
53
|
+
this.debugValidation = pb.vec3(1, 1, 0);
|
|
54
|
+
}
|
|
49
55
|
this.$if(pb.or(pb.any(pb.lessThan(this.hit2d, pb.vec2(0))), pb.any(pb.greaterThan(this.hit2d, pb.vec2(1)))), function() {
|
|
56
|
+
if (debugValidationOut) {
|
|
57
|
+
this.debugValidation = pb.vec3(0);
|
|
58
|
+
}
|
|
50
59
|
this.$return(pb.float(0));
|
|
51
60
|
});
|
|
52
61
|
this.$l.manhattanDist = pb.abs(pb.sub(this.hit2d, this.uv));
|
|
53
62
|
this.$if(pb.all(pb.lessThan(this.manhattanDist, pb.vec2(pb.div(pb.vec2(2), this.textureSize.xy)))), function() {
|
|
63
|
+
if (debugValidationOut) {
|
|
64
|
+
this.debugValidation.x = 0;
|
|
65
|
+
}
|
|
54
66
|
this.$return(pb.float(0));
|
|
55
67
|
});
|
|
56
68
|
if (normalTexture) {
|
|
57
69
|
this.$l.hitNormalWS = pb.sub(pb.mul(pb.textureSampleLevel(normalTexture, this.hit2d, 0).rgb, 2), pb.vec3(1));
|
|
58
70
|
this.$l.hitNormalVS = pb.mul(this.viewMatrix, pb.vec4(this.hitNormalWS, 0)).xyz;
|
|
59
71
|
this.$if(pb.greaterThan(pb.dot(this.hitNormalVS, this.viewSpaceRayDirection), 0), function() {
|
|
72
|
+
if (debugValidationOut) {
|
|
73
|
+
this.debugValidation.y = 0;
|
|
74
|
+
}
|
|
60
75
|
this.$return(pb.float(0));
|
|
61
76
|
});
|
|
62
77
|
}
|
|
@@ -67,14 +82,38 @@ const MAX_FLOAT_VALUE = 3.402823466e38;
|
|
|
67
82
|
if (this.hit3d) {
|
|
68
83
|
this.$l.distance = pb.distance(this.viewSpaceSurface, this.hit3d);
|
|
69
84
|
this.$l.confidence = pb.sub(1, pb.smoothStep(0, this.thickness, this.distance));
|
|
85
|
+
if (debugValidationOut) {
|
|
86
|
+
this.debugValidation.z = this.confidence;
|
|
87
|
+
}
|
|
70
88
|
this.$return(pb.mul(this.vignette, this.confidence, this.confidence));
|
|
71
89
|
} else {
|
|
72
90
|
this.$return(this.vignette);
|
|
73
91
|
}
|
|
74
92
|
});
|
|
75
|
-
return hit3D ? scope[funcName](hit2D, hit3D, thickness, surfaceZ, uv, traceRay, viewMatrix, invProjMatrix, textureSize) : scope[funcName](hit2D, surfaceZ, uv, traceRay, viewMatrix, invProjMatrix, textureSize);
|
|
93
|
+
return hit3D ? debugValidationOut ? scope[funcName](hit2D, hit3D, thickness, surfaceZ, uv, traceRay, viewMatrix, invProjMatrix, textureSize, debugValidationOut) : scope[funcName](hit2D, hit3D, thickness, surfaceZ, uv, traceRay, viewMatrix, invProjMatrix, textureSize) : scope[funcName](hit2D, surfaceZ, uv, traceRay, viewMatrix, invProjMatrix, textureSize);
|
|
76
94
|
}
|
|
77
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Optional `giTraceOut` (both tracers): `vec3(occluded, escaped, rawConfidence)`.
|
|
97
|
+
*
|
|
98
|
+
* Reflections only care whether a hit is usable, so the returned confidence folds
|
|
99
|
+
* together "was the ray blocked" and "can its radiance be trusted". Diffuse GI
|
|
100
|
+
* needs those apart: a hit whose colour is unusable still occludes the sky.
|
|
101
|
+
* - `occluded`: the march intersected geometry (not a sky texel).
|
|
102
|
+
* - `escaped`: the march missed and the ray was provably unoccluded where it
|
|
103
|
+
* stopped. Neither flag set means the outcome is indeterminate (ran out of
|
|
104
|
+
* screen or iterations behind geometry) and callers should exclude the sample
|
|
105
|
+
* rather than treat it as unoccluded.
|
|
106
|
+
* - `certainty`: how certain the intersection is *geometrically* — the hit's
|
|
107
|
+
* distance from the sampled surface relative to the thickness, so a thin-object
|
|
108
|
+
* false positive does not occlude. Deliberately excludes the screen-border,
|
|
109
|
+
* near-self and backface vetoes {@link validateHit} applies: those bound
|
|
110
|
+
* reflection artifacts, whereas for diffuse GI a border, adjacent or
|
|
111
|
+
* back-facing hit is real geometry whose screen colour is still the best
|
|
112
|
+
* available estimate of its outgoing radiance. The march-length attenuation is
|
|
113
|
+
* excluded too, as it would make occlusion depend on camera distance.
|
|
114
|
+
*
|
|
115
|
+
* Callers that omit the parameter generate exactly the same shader as before.
|
|
116
|
+
*/ function screenSpaceRayTracing_Linear2D(scope, viewPos, traceRay, viewMatrix, projMatrix, invProjMatrix, cameraNearFar, maxDistance, maxIterations, thickness, stride, textureSize, linearDepthTex, normalTexture, useBackfaceDepth, giTraceOut) {
|
|
78
117
|
const pb = scope.$builder;
|
|
79
118
|
pb.func('distanceSquared', [
|
|
80
119
|
pb.vec2('a'),
|
|
@@ -211,7 +250,7 @@ function screenSpaceRayTracing_Linear2D(scope, viewPos, traceRay, viewMatrix, pr
|
|
|
211
250
|
this.hit3D = pb.div(this.Q0, this.pqk.w);
|
|
212
251
|
this.$return(this.intersected);
|
|
213
252
|
});
|
|
214
|
-
pb.func('SSR_Linear2D', [
|
|
253
|
+
pb.func(giTraceOut ? 'SSR_Linear2D_GI' : 'SSR_Linear2D', [
|
|
215
254
|
pb.vec3('rayOrigin'),
|
|
216
255
|
pb.vec3('rayDirection'),
|
|
217
256
|
pb.mat4('viewMatrix'),
|
|
@@ -222,22 +261,50 @@ function screenSpaceRayTracing_Linear2D(scope, viewPos, traceRay, viewMatrix, pr
|
|
|
222
261
|
pb.float('maxIterations'),
|
|
223
262
|
pb.float('thickness'),
|
|
224
263
|
pb.vec2('cameraNearFar'),
|
|
225
|
-
pb.vec4('textureSize')
|
|
264
|
+
pb.vec4('textureSize'),
|
|
265
|
+
...giTraceOut ? [
|
|
266
|
+
pb.vec3('giTrace').out()
|
|
267
|
+
] : []
|
|
226
268
|
], function() {
|
|
269
|
+
if (giTraceOut) {
|
|
270
|
+
this.giTrace = pb.vec3(0);
|
|
271
|
+
}
|
|
227
272
|
this.$l.hit2D = pb.vec3();
|
|
228
273
|
this.$l.hit3D = pb.vec3();
|
|
229
274
|
this.$l.origin = pb.vec2();
|
|
230
275
|
this.$l.numIterations = pb.float();
|
|
231
276
|
this.$l.intersected = this.traceRayLinear2D(this.rayOrigin, this.rayDirection, this.stride, this.maxDistance, this.maxIterations, this.thickness, this.cameraNearFar, this.projMatrix, this.textureSize, this.hit2D, this.hit3D, this.origin, this.numIterations);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
277
|
+
if (giTraceOut) {
|
|
278
|
+
// Depth where the march stopped. A miss only counts as a free escape
|
|
279
|
+
// when the ray was still in front of the depth buffer there; a ray that
|
|
280
|
+
// left the screen from behind geometry is indeterminate, not unoccluded.
|
|
281
|
+
this.$l.exitSurfaceZ01 = ShaderHelper.sampleLinearDepth(this, linearDepthTex, this.hit2D.xy, 0);
|
|
282
|
+
this.$if(pb.not(this.intersected), function() {
|
|
283
|
+
this.$l.exitSceneZ = pb.neg(pb.mul(this.exitSurfaceZ01, this.cameraNearFar.y));
|
|
284
|
+
this.giTrace = pb.vec3(0, pb.float(pb.or(pb.greaterThanEqual(this.exitSurfaceZ01, 1), pb.greaterThan(this.hit2D.z, this.exitSceneZ))), 0);
|
|
285
|
+
this.$return(pb.vec4(0));
|
|
286
|
+
});
|
|
287
|
+
} else {
|
|
288
|
+
this.$if(pb.not(this.intersected), function() {
|
|
289
|
+
this.$return(pb.vec4(0));
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
this.$l.surfaceZ01 = giTraceOut ? this.exitSurfaceZ01 : ShaderHelper.sampleLinearDepth(this, linearDepthTex, this.hit2D.xy, 0);
|
|
236
293
|
this.$if(pb.equal(this.surfaceZ01, 1), function() {
|
|
294
|
+
if (giTraceOut) {
|
|
295
|
+
// The intersection resolved onto a sky texel, so the ray escaped.
|
|
296
|
+
this.giTrace = pb.vec3(0, 1, 0);
|
|
297
|
+
}
|
|
237
298
|
this.$return(pb.vec4(0));
|
|
238
299
|
});
|
|
239
300
|
this.$l.surfaceZ = ShaderHelper.linearDepthToNonLinear(this, pb.mul(this.surfaceZ01, this.cameraNearFar.y), this.cameraNearFar);
|
|
240
301
|
this.$l.confidence = validateHit(this, this.hit2D.xy, null, this.surfaceZ, null, this.origin, this.rayDirection, this.viewMatrix, this.invProjMatrix, this.textureSize, normalTexture);
|
|
302
|
+
if (giTraceOut) {
|
|
303
|
+
// rayIntersectDepth already enforced the thickness window, so an
|
|
304
|
+
// intersection here is geometrically certain regardless of the vetoes
|
|
305
|
+
// validateHit applies for reflections.
|
|
306
|
+
this.giTrace = pb.vec3(1, 0, 1);
|
|
307
|
+
}
|
|
241
308
|
this.$l.iterationAttenuation = pb.sub(1, pb.smoothStep(0, this.maxIterations, this.numIterations));
|
|
242
309
|
//this.$l.iterationAttenuation = pb.smoothStep(this.maxIterations, 1, this.numIterations);
|
|
243
310
|
this.confidence = pb.mul(this.confidence, this.iterationAttenuation);
|
|
@@ -246,15 +313,50 @@ function screenSpaceRayTracing_Linear2D(scope, viewPos, traceRay, viewMatrix, pr
|
|
|
246
313
|
this.$l.hitDistance = pb.length(pb.sub(this.hitPixel, this.startPixel));
|
|
247
314
|
this.$return(pb.vec4(this.hit2D.xy, this.hitDistance, this.confidence));
|
|
248
315
|
});
|
|
249
|
-
return scope.SSR_Linear2D(viewPos, traceRay, viewMatrix, projMatrix, invProjMatrix, stride, maxDistance, maxIterations, thickness, cameraNearFar, textureSize);
|
|
316
|
+
return giTraceOut ? scope.SSR_Linear2D_GI(viewPos, traceRay, viewMatrix, projMatrix, invProjMatrix, stride, maxDistance, maxIterations, thickness, cameraNearFar, textureSize, giTraceOut) : scope.SSR_Linear2D(viewPos, traceRay, viewMatrix, projMatrix, invProjMatrix, stride, maxDistance, maxIterations, thickness, cameraNearFar, textureSize);
|
|
250
317
|
}
|
|
251
|
-
|
|
318
|
+
/**
|
|
319
|
+
* UE5 Random.ush InterleavedGradientNoise. Used as the temporal jitter
|
|
320
|
+
* (StepOffset) for the fixed-step HZB march below.
|
|
321
|
+
*/ function SSR_interleavedGradientNoise(scope, uv, frameId) {
|
|
252
322
|
const pb = scope.$builder;
|
|
253
|
-
pb.func('
|
|
254
|
-
pb.
|
|
323
|
+
pb.func('SSR_IGN', [
|
|
324
|
+
pb.vec2('uv'),
|
|
325
|
+
pb.float('frameId')
|
|
255
326
|
], function() {
|
|
256
|
-
this.$
|
|
327
|
+
this.$l.p = pb.add(this.uv, pb.mul(pb.vec2(47, 17), 0.695, this.frameId));
|
|
328
|
+
this.$return(pb.fract(pb.mul(52.9829189, pb.fract(pb.dot(this.p, pb.vec2(0.06711056, 0.00583715))))));
|
|
257
329
|
});
|
|
330
|
+
return scope.SSR_IGN(uv, frameId);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Screen space ray intersection against the HZB, ported from UE5's
|
|
334
|
+
* SSRTRayCast.ush (InitScreenSpaceRayFromWorldSpace + CastScreenSpaceRay):
|
|
335
|
+
* a fixed-step linear march over the ray clipped/extended to the screen
|
|
336
|
+
* border, sampling the furthest-depth pyramid at a mip level that grows with
|
|
337
|
+
* roughness, with a slope-based CompareTolerance hit window and line-segment
|
|
338
|
+
* hit refinement.
|
|
339
|
+
*
|
|
340
|
+
* Convention differences vs UE5:
|
|
341
|
+
* - UE is reversed-Z (larger = closer); we use standard Z, so every depth
|
|
342
|
+
* difference is mirrored (`Diff = SampleDepth - SampleZ`).
|
|
343
|
+
* - UE view space has +z forward; ours has -z forward.
|
|
344
|
+
* - UE's HZB is a half-res pow2 pyramid and starts marching at its mip 1;
|
|
345
|
+
* ours is full-res at mip0. Under standard-Z the march starts at
|
|
346
|
+
* START_MIP = 0, because the coarse furthest-depth blocks quantize into a
|
|
347
|
+
* staircase that grazing rays periodically self-intersect, showing up as
|
|
348
|
+
* regular stripes TAA cannot converge. Under reverse-Z depth precision is
|
|
349
|
+
* nearly uniform, so the march starts at mip 1 like UE; rough reflections
|
|
350
|
+
* still climb the pyramid via the roughness mip ramp in both cases.
|
|
351
|
+
*
|
|
352
|
+
* `maxIterations` is the number of linear samples along the ray (UE NumSteps,
|
|
353
|
+
* typically 8..64), no longer the traversal iteration cap of the previous
|
|
354
|
+
* FidelityFX-style implementation.
|
|
355
|
+
*/ function screenSpaceRayTracing_HiZ(scope, viewPos, traceRay, viewMatrix, projMatrix, invProjMatrix, cameraNearFar, maxMipLevel, maxIterations, maxDistance, thickness, textureSize, HiZTexture, normalTexture, giTraceOut, roughness, stepOffset) {
|
|
356
|
+
const pb = scope.$builder;
|
|
357
|
+
// The r32f pyramid stores the furthest depth (max reduction; mip0 is the
|
|
358
|
+
// raw depth). Matches UE5 marching against the FurthestHZBTexture (UE is
|
|
359
|
+
// reversed-Z, so its furthest pyramid is the min reduction instead).
|
|
258
360
|
pb.func('SSR_loadDepth', [
|
|
259
361
|
pb.vec2('uv'),
|
|
260
362
|
pb.float('level')
|
|
@@ -265,130 +367,172 @@ function screenSpaceRayTracing_HiZ(scope, viewPos, traceRay, viewMatrix, projMat
|
|
|
265
367
|
pb.vec3('p'),
|
|
266
368
|
pb.mat4('mat')
|
|
267
369
|
], function() {
|
|
268
|
-
this.$l.c = pb.sub(pb.mul(this.p, 2), pb.
|
|
370
|
+
this.$l.c = pb.vec3(pb.sub(pb.mul(this.p.xy, 2), pb.vec2(1)), ShaderHelper.deviceDepthToClipZ(this, this.p.z));
|
|
269
371
|
this.$l.u = pb.mul(this.mat, pb.vec4(this.c, 1));
|
|
270
372
|
this.u = pb.div(this.u, this.u.w);
|
|
271
373
|
this.$return(this.u.xyz);
|
|
272
374
|
});
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
375
|
+
// Port of UE5 GetStepScreenFactorToClipAtScreenEdge. Returns the multiplier
|
|
376
|
+
// for rayStepNDC so the ray ends exactly at the screen border. A factor
|
|
377
|
+
// above 1 extends short rays to the border (UE bExtendRayToScreenBorder).
|
|
378
|
+
pb.func('SSR_clipRayToScreenEdge', [
|
|
379
|
+
pb.vec2('rayStartNDC'),
|
|
380
|
+
pb.vec2('rayStepNDC')
|
|
276
381
|
], function() {
|
|
277
|
-
this.$l.
|
|
278
|
-
this.
|
|
279
|
-
this.
|
|
280
|
-
this.$return(this.
|
|
382
|
+
this.$l.rayStepInvFactor = pb.mul(0.5, pb.length(this.rayStepNDC));
|
|
383
|
+
this.$l.absStep = pb.max(pb.abs(this.rayStepNDC), pb.vec2(1e-8));
|
|
384
|
+
this.$l.s = pb.sub(pb.vec2(1), pb.div(pb.max(pb.sub(pb.abs(pb.add(this.rayStepNDC, pb.mul(this.rayStartNDC, this.rayStepInvFactor))), pb.vec2(this.rayStepInvFactor)), pb.vec2(0)), this.absStep));
|
|
385
|
+
this.$return(pb.div(pb.min(this.s.x, this.s.y), pb.max(this.rayStepInvFactor, 1e-8)));
|
|
281
386
|
});
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
pb.
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
pb.vec3('
|
|
292
|
-
pb.vec3('
|
|
293
|
-
pb.
|
|
294
|
-
pb.vec2('currentMipResolution'),
|
|
295
|
-
pb.vec2('invCurrentMipResolution'),
|
|
296
|
-
pb.vec2('floorOffset'),
|
|
297
|
-
pb.vec2('uvOffset'),
|
|
298
|
-
pb.vec3('position').out(),
|
|
299
|
-
pb.float('currentT').out()
|
|
387
|
+
// Port of UE5 InitScreenSpaceRayFromWorldSpace, in view space (-z forward).
|
|
388
|
+
// Outputs the ray in "texture space": uv in [0,1], z = device depth in
|
|
389
|
+
// [0,1], the same mapping the HZB stores.
|
|
390
|
+
pb.func('SSR_initScreenSpaceRay', [
|
|
391
|
+
pb.vec3('viewPos'),
|
|
392
|
+
pb.vec3('rayDirection'),
|
|
393
|
+
pb.float('maxDistance'),
|
|
394
|
+
pb.float('slopeCompareToleranceScale'),
|
|
395
|
+
pb.mat4('projMatrix'),
|
|
396
|
+
pb.vec3('rayStartTS').out(),
|
|
397
|
+
pb.vec3('rayStepTS').out(),
|
|
398
|
+
pb.float('compareTolerance').out()
|
|
300
399
|
], function() {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
this.
|
|
304
|
-
this.$l.
|
|
305
|
-
this.
|
|
306
|
-
this.
|
|
400
|
+
// Rays heading towards the camera stop before reaching 5% of the
|
|
401
|
+
// surface view depth (UE: min(-0.95 * SceneDepth / ViewDirZ, TMax)).
|
|
402
|
+
this.$l.rayLength = this.$choice(pb.greaterThan(this.rayDirection.z, 0), pb.min(this.maxDistance, pb.div(pb.mul(-0.95, this.viewPos.z), pb.max(this.rayDirection.z, 1e-6))), this.maxDistance);
|
|
403
|
+
this.$l.rayEnd = pb.add(this.viewPos, pb.mul(this.rayDirection, this.rayLength));
|
|
404
|
+
this.$l.startH = pb.mul(this.projMatrix, pb.vec4(this.viewPos, 1));
|
|
405
|
+
this.$l.endH = pb.mul(this.projMatrix, pb.vec4(this.rayEnd, 1));
|
|
406
|
+
this.$l.startNDC = pb.div(this.startH.xyz, this.startH.w);
|
|
407
|
+
this.$l.endNDC = pb.div(this.endH.xyz, this.endH.w);
|
|
408
|
+
this.$l.stepNDC = pb.sub(this.endNDC, this.startNDC);
|
|
409
|
+
// Always extend/clip the ray to the screen border so NumSteps samples
|
|
410
|
+
// cover the whole visible segment.
|
|
411
|
+
this.stepNDC = pb.mul(this.stepNDC, this.SSR_clipRayToScreenEdge(this.startNDC.xy, this.stepNDC.xy));
|
|
412
|
+
if (REVERSE_Z) {
|
|
413
|
+
// Reverse ZO canonical clip space: NDC z is already the device depth.
|
|
414
|
+
this.rayStartTS = pb.vec3(pb.add(pb.mul(this.startNDC.xy, 0.5), pb.vec2(0.5)), this.startNDC.z);
|
|
415
|
+
this.rayStepTS = pb.vec3(pb.mul(this.stepNDC.xy, 0.5), this.stepNDC.z);
|
|
416
|
+
} else {
|
|
417
|
+
this.rayStartTS = pb.add(pb.mul(this.startNDC, 0.5), pb.vec3(0.5));
|
|
418
|
+
this.rayStepTS = pb.mul(this.stepNDC, 0.5);
|
|
419
|
+
}
|
|
420
|
+
// Depth-only step (UE RayDepthScreen): project the point at rayLength
|
|
421
|
+
// straight along the view forward axis for the slope tolerance.
|
|
422
|
+
this.$l.depthH = pb.mul(this.projMatrix, pb.vec4(this.viewPos.xy, pb.sub(this.viewPos.z, this.rayLength), 1));
|
|
423
|
+
this.$l.depthTSz = REVERSE_Z ? pb.div(this.depthH.z, this.depthH.w) : pb.add(pb.mul(pb.div(this.depthH.z, this.depthH.w), 0.5), 0.5);
|
|
424
|
+
// Under standard Z depth grows away from the camera, mirroring UE's
|
|
425
|
+
// reversed-Z expression (RayStartScreen.z - RayDepthScreen.z); under
|
|
426
|
+
// reverse-Z the UE orientation applies directly.
|
|
427
|
+
this.compareTolerance = pb.max(pb.abs(this.rayStepTS.z), pb.mul(REVERSE_Z ? pb.sub(this.rayStartTS.z, this.depthTSz) : pb.sub(this.depthTSz, this.rayStartTS.z), this.slopeCompareToleranceScale));
|
|
307
428
|
});
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
pb.
|
|
319
|
-
pb.vec3('
|
|
320
|
-
pb.float('
|
|
429
|
+
// Port of UE5 CastScreenSpaceRay: NumSteps uniform samples in batches of 4,
|
|
430
|
+
// mip level ramped by roughness, tolerance-window hit test, uncertainty
|
|
431
|
+
// tracking and line-segment hit refinement.
|
|
432
|
+
// Standard-Z keeps 0 instead of UE's StartMipLevel=1: coarse-mip depth
|
|
433
|
+
// staircases combined with the poor far-depth resolution near 1.0 cause
|
|
434
|
+
// grazing-angle stripe artifacts. Under reverse-Z depth precision is nearly
|
|
435
|
+
// uniform along the ray, so the march starts at mip 1 like UE for better
|
|
436
|
+
// texture cache behavior.
|
|
437
|
+
const START_MIP = REVERSE_Z ? 1 : 0;
|
|
438
|
+
pb.func('SSR_castScreenSpaceRay', [
|
|
439
|
+
pb.vec3('rayStartTS'),
|
|
440
|
+
pb.vec3('rayStepTS'),
|
|
441
|
+
pb.float('compareToleranceIn'),
|
|
442
|
+
pb.float('numSteps'),
|
|
443
|
+
pb.float('stepOffset'),
|
|
444
|
+
pb.float('roughness'),
|
|
445
|
+
pb.float('maxMipLevel'),
|
|
446
|
+
pb.vec3('hitUVz').out(),
|
|
447
|
+
pb.bool('foundHit').out(),
|
|
448
|
+
pb.bool('uncertain').out(),
|
|
449
|
+
pb.float('numIterations').out()
|
|
321
450
|
], function() {
|
|
322
|
-
this.$l.
|
|
323
|
-
this.
|
|
324
|
-
this.$l.
|
|
325
|
-
this.$
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
this.currentT = pb.div(pb.sub(this.surfaceZMax, this.origin.z), this.direction.z);
|
|
348
|
-
this.position = pb.add(this.origin, pb.mul(this.direction, this.currentT));
|
|
451
|
+
this.$l.step = pb.div(1, this.numSteps);
|
|
452
|
+
this.$l.compareTolerance = pb.mul(this.compareToleranceIn, this.step);
|
|
453
|
+
this.$l.rayStepUVz = pb.mul(this.rayStepTS, this.step);
|
|
454
|
+
this.$l.rayUVz = pb.add(this.rayStartTS, pb.mul(this.rayStepUVz, this.stepOffset));
|
|
455
|
+
this.$l.level = pb.float(START_MIP);
|
|
456
|
+
this.$l.mipInc = pb.mul(pb.div(8, this.numSteps), this.roughness);
|
|
457
|
+
this.$l.lastDiff = pb.float(0);
|
|
458
|
+
this.foundHit = false;
|
|
459
|
+
this.uncertain = false;
|
|
460
|
+
this.$l.marchBase = pb.float(0);
|
|
461
|
+
// Depth diffs / hit flags of the current 4-sample batch, kept for the
|
|
462
|
+
// post-loop hit refinement.
|
|
463
|
+
this.$l.diff0 = pb.float(0);
|
|
464
|
+
this.$l.diff1 = pb.float(0);
|
|
465
|
+
this.$l.diff2 = pb.float(0);
|
|
466
|
+
this.$l.diff3 = pb.float(0);
|
|
467
|
+
this.$l.hit0 = pb.bool(false);
|
|
468
|
+
this.$l.hit1 = pb.bool(false);
|
|
469
|
+
this.$l.hit2 = pb.bool(false);
|
|
470
|
+
this.$l.hit3 = pb.bool(false);
|
|
471
|
+
this.$l.numBatches = pb.ceil(pb.mul(this.numSteps, 0.25));
|
|
472
|
+
this.$for(pb.float('i'), 0, pb.getDevice().type === 'webgl' ? 64 : this.numBatches, function() {
|
|
473
|
+
if (pb.getDevice().type === 'webgl') {
|
|
474
|
+
this.$if(pb.greaterThanEqual(this.i, this.numBatches), function() {
|
|
475
|
+
this.$break();
|
|
349
476
|
});
|
|
477
|
+
}
|
|
478
|
+
this.marchBase = pb.mul(this.i, 4);
|
|
479
|
+
// Two samples per mip step (UE: SamplesMip.xy = Level; Level += inc).
|
|
480
|
+
this.$l.mip01 = pb.min(this.level, this.maxMipLevel);
|
|
481
|
+
this.$l.mip23 = pb.min(pb.add(this.level, this.mipInc), this.maxMipLevel);
|
|
482
|
+
this.level = pb.add(this.level, pb.mul(this.mipInc, 2));
|
|
483
|
+
for(let j = 0; j < 4; j++){
|
|
484
|
+
this.$l[`sampleT${j}`] = pb.add(this.marchBase, j + 1);
|
|
485
|
+
this.$l[`sampleUV${j}`] = pb.add(this.rayUVz.xy, pb.mul(this.rayStepUVz.xy, this[`sampleT${j}`]));
|
|
486
|
+
this.$l[`sampleZ${j}`] = pb.add(this.rayUVz.z, pb.mul(this.rayStepUVz.z, this[`sampleT${j}`]));
|
|
487
|
+
// Negative when the ray is behind the surface, hit window (-2T, 0).
|
|
488
|
+
// Under reverse-Z this is UE's original `SamplesZ - SampleDepth`;
|
|
489
|
+
// under standard Z the difference is mirrored.
|
|
490
|
+
this[`diff${j}`] = REVERSE_Z ? pb.sub(this[`sampleZ${j}`], this.SSR_loadDepth(this[`sampleUV${j}`], j < 2 ? this.mip01 : this.mip23)) : pb.sub(this.SSR_loadDepth(this[`sampleUV${j}`], j < 2 ? this.mip01 : this.mip23), this[`sampleZ${j}`]);
|
|
491
|
+
this[`hit${j}`] = pb.lessThan(pb.abs(pb.add(this[`diff${j}`], this.compareTolerance)), this.compareTolerance);
|
|
492
|
+
this.foundHit = pb.or(this.foundHit, this[`hit${j}`]);
|
|
493
|
+
// The ray went far behind geometry before any hit: its outcome
|
|
494
|
+
// cannot be resolved from the depth buffer (UE bUncertain).
|
|
495
|
+
this.uncertain = pb.or(this.uncertain, pb.and(pb.lessThan(pb.add(this[`diff${j}`], this.compareTolerance), pb.neg(this.compareTolerance)), pb.not(this.foundHit)));
|
|
496
|
+
}
|
|
497
|
+
this.$if(this.foundHit, function() {
|
|
498
|
+
this.$break();
|
|
350
499
|
});
|
|
500
|
+
this.lastDiff = this.diff3;
|
|
351
501
|
});
|
|
352
|
-
this.$
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
pb.float('maxT'),
|
|
363
|
-
pb.float('numIterations').out()
|
|
364
|
-
], function() {
|
|
365
|
-
this.$l.invDirection = pb.vec3(this.$choice(pb.greaterThan(pb.abs(this.screenSpaceDirection.x), 1e-8), pb.div(1, this.screenSpaceDirection.x), MAX_FLOAT_VALUE), this.$choice(pb.greaterThan(pb.abs(this.screenSpaceDirection.y), 1e-8), pb.div(1, this.screenSpaceDirection.y), MAX_FLOAT_VALUE), this.$choice(pb.greaterThan(pb.abs(this.screenSpaceDirection.z), 1e-8), pb.div(1, this.screenSpaceDirection.z), MAX_FLOAT_VALUE));
|
|
366
|
-
this.$l.currentMip = this.mostDetailMip;
|
|
367
|
-
this.$l.currentMipResolution = this.getMipResolution(this.currentMip);
|
|
368
|
-
this.$l.invCurrentMipResolution = pb.div(pb.vec2(1), this.currentMipResolution);
|
|
369
|
-
this.$l.uvOffset = pb.div(pb.mul(0.005, pb.exp2(pb.float(this.mostDetailMip))), this.screenSize);
|
|
370
|
-
this.uvOffset = pb.vec2(this.$choice(pb.lessThan(this.screenSpaceDirection.x, 0), pb.neg(this.uvOffset.x), this.uvOffset.x), this.$choice(pb.lessThan(this.screenSpaceDirection.y, 0), pb.neg(this.uvOffset.y), this.uvOffset.y));
|
|
371
|
-
this.$l.floorOffset = pb.vec2(this.$choice(pb.lessThan(this.screenSpaceDirection.x, 0), pb.float(0), pb.float(1)), this.$choice(pb.lessThan(this.screenSpaceDirection.y, 0), pb.float(0), pb.float(1)));
|
|
372
|
-
this.$l.currentT = pb.float();
|
|
373
|
-
this.$l.position = pb.vec3();
|
|
374
|
-
this.SSR_initialAdvanceRay(this.screenSpacePos, this.screenSpaceDirection, this.invDirection, this.currentMipResolution, this.invCurrentMipResolution, this.floorOffset, this.uvOffset, this.position, this.currentT);
|
|
375
|
-
this.numIterations = pb.float(0);
|
|
376
|
-
this.$while(pb.and(pb.and(pb.lessThan(this.numIterations, this.maxIterations), pb.greaterThanEqual(this.currentMip, this.mostDetailMip)), pb.and(pb.lessThanEqual(this.currentT, this.maxT), pb.all(pb.greaterThanEqual(this.position.xy, pb.vec2(0))), pb.all(pb.lessThanEqual(this.position.xy, pb.vec2(1))))), function() {
|
|
377
|
-
this.$l.currentMipPosition = pb.mul(this.currentMipResolution, this.position.xy);
|
|
378
|
-
this.$l.depthRange = pb.textureLoad(HiZTexture, pb.ivec2(this.currentMipPosition), this.currentMip).rg;
|
|
379
|
-
this.$l.skippedTile = this.SSR_advanceRay(this.screenSpacePos, this.screenSpaceDirection, this.invDirection, this.currentMipPosition, this.invCurrentMipResolution, this.floorOffset, this.uvOffset, this.depthRange.x, this.depthRange.y, this.currentMip, this.position, this.currentT);
|
|
380
|
-
this.$l.nextMipIsOutOfRange = pb.and(this.skippedTile, pb.greaterThanEqual(this.currentMip, this.maxMipLevel));
|
|
381
|
-
this.$if(pb.not(this.nextMipIsOutOfRange), function() {
|
|
382
|
-
this.currentMip = pb.add(this.currentMip, this.$choice(this.skippedTile, pb.int(1), pb.int(-1)));
|
|
383
|
-
this.currentMipResolution = pb.mul(this.currentMipResolution, this.$choice(this.skippedTile, 0.5, 2));
|
|
384
|
-
this.invCurrentMipResolution = pb.mul(this.invCurrentMipResolution, this.$choice(this.skippedTile, 2, 0.5));
|
|
502
|
+
this.$if(this.foundHit, function() {
|
|
503
|
+
// Locate the first hit sample of the batch, then refine with a line
|
|
504
|
+
// segment intersection (UE: TimeLerp = saturate(D0 / (D0 - D1))).
|
|
505
|
+
this.$l.depthDiff0 = this.diff2;
|
|
506
|
+
this.$l.depthDiff1 = this.diff3;
|
|
507
|
+
this.$l.time0 = pb.float(3);
|
|
508
|
+
this.$if(this.hit2, function() {
|
|
509
|
+
this.depthDiff0 = this.diff1;
|
|
510
|
+
this.depthDiff1 = this.diff2;
|
|
511
|
+
this.time0 = 2;
|
|
385
512
|
});
|
|
386
|
-
this
|
|
513
|
+
this.$if(this.hit1, function() {
|
|
514
|
+
this.depthDiff0 = this.diff0;
|
|
515
|
+
this.depthDiff1 = this.diff1;
|
|
516
|
+
this.time0 = 1;
|
|
517
|
+
});
|
|
518
|
+
this.$if(this.hit0, function() {
|
|
519
|
+
this.depthDiff0 = this.lastDiff;
|
|
520
|
+
this.depthDiff1 = this.diff0;
|
|
521
|
+
this.time0 = 0;
|
|
522
|
+
});
|
|
523
|
+
this.time0 = pb.add(this.time0, this.marchBase);
|
|
524
|
+
this.$l.denom = pb.sub(this.depthDiff0, this.depthDiff1);
|
|
525
|
+
this.$l.timeLerp = this.$choice(pb.greaterThan(pb.abs(this.denom), 1e-20), pb.clamp(pb.div(this.depthDiff0, this.denom), 0, 1), pb.float(0.5));
|
|
526
|
+
this.$l.intersectTime = pb.add(this.time0, this.timeLerp);
|
|
527
|
+
this.hitUVz = pb.add(this.rayUVz, pb.mul(this.rayStepUVz, this.intersectTime));
|
|
528
|
+
this.numIterations = this.intersectTime;
|
|
529
|
+
}).$else(function() {
|
|
530
|
+
// No certain intersection - the march covered the whole clipped ray.
|
|
531
|
+
this.hitUVz = pb.add(this.rayUVz, pb.mul(this.rayStepUVz, this.numSteps));
|
|
532
|
+
this.numIterations = this.numSteps;
|
|
387
533
|
});
|
|
388
|
-
this.$l.validHit = this.$choice(pb.and(pb.lessThan(this.currentMip, this.mostDetailMip), pb.and(pb.greaterThanEqual(this.currentT, 0), pb.lessThanEqual(this.currentT, this.maxT))), pb.float(1), pb.float(0));
|
|
389
|
-
this.$return(pb.vec4(this.position, this.validHit));
|
|
390
534
|
});
|
|
391
|
-
pb.func('SSR_HiZ', [
|
|
535
|
+
pb.func(giTraceOut ? 'SSR_HiZ_GI' : 'SSR_HiZ', [
|
|
392
536
|
pb.vec3('viewPos'),
|
|
393
537
|
pb.vec3('traceRay'),
|
|
394
538
|
pb.mat4('viewMatrix'),
|
|
@@ -399,44 +543,68 @@ function screenSpaceRayTracing_HiZ(scope, viewPos, traceRay, viewMatrix, projMat
|
|
|
399
543
|
pb.float('thickness'),
|
|
400
544
|
pb.vec4('textureSize'),
|
|
401
545
|
pb.int('maxMipLevel'),
|
|
402
|
-
pb.float('maxIterations')
|
|
546
|
+
pb.float('maxIterations'),
|
|
547
|
+
pb.float('roughness'),
|
|
548
|
+
pb.float('stepOffset'),
|
|
549
|
+
...giTraceOut ? [
|
|
550
|
+
pb.vec3('giTrace').out()
|
|
551
|
+
] : []
|
|
403
552
|
], function() {
|
|
553
|
+
if (giTraceOut) {
|
|
554
|
+
this.giTrace = pb.vec3(0);
|
|
555
|
+
}
|
|
404
556
|
this.$l.rayDirection = pb.normalize(this.traceRay);
|
|
405
|
-
this.$l.
|
|
406
|
-
this.$l.
|
|
407
|
-
this.$
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
this.$
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
this.$l.originH = pb.mul(this.projMatrix, pb.vec4(this.viewPos, 1));
|
|
414
|
-
this.$l.originCS = pb.div(this.originH.xyz, this.originH.w);
|
|
415
|
-
this.$l.originTS = pb.add(pb.mul(this.originCS, 0.5), pb.vec3(0.5));
|
|
416
|
-
this.$l.endTS = this.projectPosition(pb.add(this.viewPos, pb.mul(this.rayDirection, this.rayLength)), this.projMatrix);
|
|
417
|
-
this.$l.directionTS = this.$choice(this.reverseRay, pb.sub(this.endTS, this.originTS), this.projectDirection(this.viewPos, this.rayDirection, this.originTS, this.projMatrix));
|
|
418
|
-
this.$l.maxT = this.$choice(this.reverseRay, pb.float(1), pb.float(MAX_FLOAT_VALUE));
|
|
419
|
-
this.$l.mostDetailMip = pb.int(0);
|
|
557
|
+
this.$l.rayStartTS = pb.vec3();
|
|
558
|
+
this.$l.rayStepTS = pb.vec3();
|
|
559
|
+
this.$l.compareTolerance = pb.float();
|
|
560
|
+
// UE uses SlopeCompareToleranceScale 4 for SSR and 2 for SSGI.
|
|
561
|
+
this.SSR_initScreenSpaceRay(this.viewPos, this.rayDirection, this.maxDistance, pb.float(giTraceOut ? 2 : 4), this.projMatrix, this.rayStartTS, this.rayStepTS, this.compareTolerance);
|
|
562
|
+
this.$l.hitUVz = pb.vec3();
|
|
563
|
+
this.$l.foundHit = pb.bool();
|
|
564
|
+
this.$l.uncertain = pb.bool();
|
|
420
565
|
this.$l.numIterations = pb.float();
|
|
421
|
-
this
|
|
566
|
+
this.SSR_castScreenSpaceRay(this.rayStartTS, this.rayStepTS, this.compareTolerance, pb.max(this.maxIterations, 4), this.stepOffset, this.roughness, pb.float(this.maxMipLevel), this.hitUVz, this.foundHit, this.uncertain, this.numIterations);
|
|
422
567
|
this.$l.confidence = pb.float(0);
|
|
423
|
-
this.$if(
|
|
424
|
-
this.$l.surfaceZ =
|
|
425
|
-
this.$if(
|
|
568
|
+
const hitBranch = this.$if(this.foundHit, function() {
|
|
569
|
+
this.$l.surfaceZ = this.SSR_loadDepth(this.hitUVz.xy, 0);
|
|
570
|
+
this.$if(ShaderHelper.isFarthestDepth(this, this.surfaceZ), function() {
|
|
571
|
+
if (giTraceOut) {
|
|
572
|
+
// The intersection resolved onto a sky texel, so the ray escaped.
|
|
573
|
+
this.giTrace = pb.vec3(0, 1, 0);
|
|
574
|
+
}
|
|
426
575
|
this.$return(pb.vec4(0));
|
|
427
576
|
});
|
|
428
|
-
this.$l.hit3D = invProjectPosition(this, this.
|
|
429
|
-
this.confidence = validateHit(this, this.
|
|
577
|
+
this.$l.hit3D = invProjectPosition(this, this.hitUVz, this.invProjMatrix);
|
|
578
|
+
this.confidence = validateHit(this, this.hitUVz.xy, this.hit3D, this.surfaceZ, this.thickness, this.rayStartTS.xy, this.rayDirection, this.viewMatrix, this.invProjMatrix, this.textureSize, normalTexture);
|
|
579
|
+
if (giTraceOut) {
|
|
580
|
+
// Keep only the thickness term of validateHit: a hit far from the
|
|
581
|
+
// sampled surface may be a thin-object false positive, which is a
|
|
582
|
+
// genuine geometric doubt. The border, near-self and backface vetoes
|
|
583
|
+
// bound reflection artifacts and must not gate diffuse occlusion.
|
|
584
|
+
this.$l.giSurfaceVS = invProjectPosition(this, pb.vec3(this.hitUVz.xy, this.surfaceZ), this.invProjMatrix);
|
|
585
|
+
this.$l.giThicknessFade = pb.sub(1, pb.smoothStep(0, this.thickness, pb.distance(this.giSurfaceVS, this.hit3D)));
|
|
586
|
+
this.giTrace = pb.vec3(1, 0, pb.mul(this.giThicknessFade, this.giThicknessFade));
|
|
587
|
+
}
|
|
430
588
|
});
|
|
589
|
+
if (giTraceOut) {
|
|
590
|
+
hitBranch.$else(function() {
|
|
591
|
+
// The ray is always extended to the screen border, so a march that
|
|
592
|
+
// finished without ever going behind geometry is a proven escape.
|
|
593
|
+
// An uncertain march (went far behind geometry before any hit) is
|
|
594
|
+
// indeterminate, not unoccluded (UE bUncertain semantics).
|
|
595
|
+
this.giTrace = pb.vec3(0, pb.float(pb.not(this.uncertain)), 0);
|
|
596
|
+
});
|
|
597
|
+
}
|
|
431
598
|
this.$l.iterationAttenuation = pb.sub(1, pb.smoothStep(0, this.maxIterations, this.numIterations));
|
|
432
|
-
//this.$l.iterationAttenuation = pb.smoothStep(this.maxIterations, 1, this.numIterations);
|
|
433
599
|
this.confidence = pb.mul(this.confidence, this.iterationAttenuation);
|
|
434
|
-
this.$l.hitPixel = pb.mul(this.
|
|
435
|
-
this.$l.startPixel = pb.mul(this.
|
|
600
|
+
this.$l.hitPixel = pb.mul(this.hitUVz.xy, this.textureSize.zw);
|
|
601
|
+
this.$l.startPixel = pb.mul(this.rayStartTS.xy, this.textureSize.zw);
|
|
436
602
|
this.$l.hitDistance = pb.length(pb.sub(this.hitPixel, this.startPixel));
|
|
437
|
-
this.$return(pb.vec4(this.
|
|
603
|
+
this.$return(pb.vec4(this.hitUVz.xy, this.hitDistance, this.confidence));
|
|
438
604
|
});
|
|
439
|
-
|
|
605
|
+
const roughnessArg = roughness ?? 0;
|
|
606
|
+
const stepOffsetArg = stepOffset ?? 0.5;
|
|
607
|
+
return giTraceOut ? scope.SSR_HiZ_GI(viewPos, traceRay, viewMatrix, projMatrix, invProjMatrix, cameraNearFar, maxDistance, thickness, textureSize, pb.sub(maxMipLevel, 1), maxIterations, roughnessArg, stepOffsetArg, giTraceOut) : scope.SSR_HiZ(viewPos, traceRay, viewMatrix, projMatrix, invProjMatrix, cameraNearFar, maxDistance, thickness, textureSize, pb.sub(maxMipLevel, 1), maxIterations, roughnessArg, stepOffsetArg);
|
|
440
608
|
} /*
|
|
441
609
|
float2 cell(float2 ray, float2 cell_count, uint camera) {
|
|
442
610
|
return floor(ray.xy * cell_count);
|
|
@@ -517,5 +685,5 @@ float3 hi_z_trace(float3 p, float3 v, in uint camera, out uint iterations) {
|
|
|
517
685
|
}
|
|
518
686
|
*/
|
|
519
687
|
|
|
520
|
-
export { SSR_calcJitter, screenSpaceRayTracing_HiZ, screenSpaceRayTracing_Linear2D };
|
|
688
|
+
export { SSR_calcJitter, SSR_interleavedGradientNoise, screenSpaceRayTracing_HiZ, screenSpaceRayTracing_Linear2D };
|
|
521
689
|
//# sourceMappingURL=ssr.js.map
|