@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vector4 } from '@zephyr3d/base';
|
|
1
|
+
import { REVERSE_Z, Vector4, DEPTH_CLEAR_VALUE, DEPTH_COMPARE_DEFAULT } from '@zephyr3d/base';
|
|
2
2
|
import { RenderQueue } from '../render_queue.js';
|
|
3
3
|
import { LightPass } from '../lightpass.js';
|
|
4
4
|
import { ShadowMapPass } from '../shadowmap_pass.js';
|
|
@@ -11,13 +11,18 @@ import '@zephyr3d/device';
|
|
|
11
11
|
import { CopyBlitter } from '../../blitter/copy.js';
|
|
12
12
|
import { fetchSampler } from '../../utility/misc.js';
|
|
13
13
|
import { MaterialVaryingFlags } from '../../values.js';
|
|
14
|
+
import { ShaderHelper } from '../../material/shader/helper.js';
|
|
14
15
|
import { PostEffectLayer, AbstractPostEffect } from '../../posteffect/posteffect.js';
|
|
15
16
|
import { RenderGraph } from './rendergraph.js';
|
|
16
17
|
import { RenderGraphExecutor } from './executor.js';
|
|
18
|
+
import { RGTextureAffinityCache } from './texture_affinity_cache.js';
|
|
17
19
|
import { DevicePoolAllocator } from './device_pool_allocator.js';
|
|
18
20
|
import { HistoryResourceManager } from './history_resource_manager.js';
|
|
19
21
|
import { RGHistoryResources } from './history_resources.js';
|
|
20
22
|
import { FrameResources, RGBlackboard } from './blackboard.js';
|
|
23
|
+
import { OrderingScope } from './render_context.js';
|
|
24
|
+
import { RenderPipeline } from './render_pipeline.js';
|
|
25
|
+
import { mergeFrameResourceRequirements } from './frame_resource_requirements.js';
|
|
21
26
|
import { renderObjectColors } from '../gpu_picking.js';
|
|
22
27
|
import { BoxShape } from '../../shapes/box.js';
|
|
23
28
|
import '../../shapes/capsule.js';
|
|
@@ -27,16 +32,28 @@ import '../../shapes/plane.js';
|
|
|
27
32
|
import '../../shapes/sphere.js';
|
|
28
33
|
import '../../shapes/tetrahedron.js';
|
|
29
34
|
|
|
30
|
-
// ─── Shared Pass Instances ──────────────────────────────────────────
|
|
31
35
|
const _scenePass = new LightPass();
|
|
32
36
|
const _depthPass = new DepthPass();
|
|
33
37
|
const _shadowMapPass = new ShadowMapPass();
|
|
34
38
|
const _clusters = [];
|
|
35
39
|
const _shadowMaskRenderer = new ShadowMaskRenderer();
|
|
36
40
|
const _devicePoolAllocator = new DevicePoolAllocator();
|
|
41
|
+
const _textureAffinityCaches = new WeakMap();
|
|
42
|
+
function getTextureAffinityCache(camera, device) {
|
|
43
|
+
const current = _textureAffinityCaches.get(camera);
|
|
44
|
+
if (current?.device === device) {
|
|
45
|
+
return current.cache;
|
|
46
|
+
}
|
|
47
|
+
const cache = new RGTextureAffinityCache();
|
|
48
|
+
_textureAffinityCaches.set(camera, {
|
|
49
|
+
device,
|
|
50
|
+
cache
|
|
51
|
+
});
|
|
52
|
+
return cache;
|
|
53
|
+
}
|
|
37
54
|
let _backDepthColorState = null;
|
|
38
55
|
let _frontDepthColorState = null;
|
|
39
|
-
const SURFACE_MRT_FLAGS = MaterialVaryingFlags.
|
|
56
|
+
const SURFACE_MRT_FLAGS = MaterialVaryingFlags.SCENE_STORE_ROUGHNESS | MaterialVaryingFlags.SSS_STORE_PROFILE | MaterialVaryingFlags.SSS_STORE_DIFFUSE | MaterialVaryingFlags.SCENE_STORE_NORMAL | MaterialVaryingFlags.SSS_STORE_TRANSMISSION | MaterialVaryingFlags.SKIN_SSS_STORE;
|
|
40
57
|
function getClusteredLight() {
|
|
41
58
|
return _clusters.length > 0 ? _clusters.pop() : new ClusteredLight();
|
|
42
59
|
}
|
|
@@ -164,23 +181,26 @@ function getSurfaceTextureFormat(ctx) {
|
|
|
164
181
|
function getTextureFormatBytes(ctx, format) {
|
|
165
182
|
return ctx.device.getDeviceCaps().textureCaps.getTextureFormatInfo(format).size;
|
|
166
183
|
}
|
|
184
|
+
function supportsSSGIRenderTargets(ctx) {
|
|
185
|
+
const caps = ctx.device.getDeviceCaps();
|
|
186
|
+
const rgba16fBytes = caps.textureCaps.getTextureFormatInfo('rgba16f').size;
|
|
187
|
+
return !!(caps.textureCaps.supportHalfFloatColorBuffer && caps.framebufferCaps.maxDrawBuffers >= 2 && caps.framebufferCaps.maxColorAttachmentBytesPerSample >= rgba16fBytes * 2);
|
|
188
|
+
}
|
|
167
189
|
function shouldStoreSSSDiffuse(ctx) {
|
|
168
190
|
return ctx.camera.sssStrength > 0 && ctx.camera.sssBlurScale > 0;
|
|
169
191
|
}
|
|
170
192
|
function shouldStoreSSSTransmission(ctx) {
|
|
171
193
|
return ctx.camera.sssStrength > 0 && ctx.camera.sssTransmissionStrength > 0;
|
|
172
194
|
}
|
|
173
|
-
function getSSSLightingTextureFormat(ctx, attachmentCount,
|
|
195
|
+
function getSSSLightingTextureFormat(ctx, attachmentCount, surfaceAttachmentCount) {
|
|
174
196
|
const colorFormat = ctx.colorFormat;
|
|
175
|
-
if (
|
|
197
|
+
if (surfaceAttachmentCount === 0 || attachmentCount === 0) {
|
|
176
198
|
return colorFormat;
|
|
177
199
|
}
|
|
178
200
|
const caps = ctx.device.getDeviceCaps();
|
|
179
|
-
//
|
|
180
|
-
// are graph textures now, so derive the format directly instead of reading
|
|
181
|
-
// the (not yet resolved) DrawContext fields.
|
|
201
|
+
// MRT graph textures are not resolved on DrawContext yet.
|
|
182
202
|
const surfaceFormat = getSurfaceTextureFormat(ctx);
|
|
183
|
-
const colorBytes = getTextureFormatBytes(ctx, colorFormat) + getTextureFormatBytes(ctx, surfaceFormat)
|
|
203
|
+
const colorBytes = getTextureFormatBytes(ctx, colorFormat) + getTextureFormatBytes(ctx, surfaceFormat) * surfaceAttachmentCount;
|
|
184
204
|
const fullPrecisionBytes = colorBytes + getTextureFormatBytes(ctx, colorFormat) * attachmentCount;
|
|
185
205
|
if (fullPrecisionBytes <= caps.framebufferCaps.maxColorAttachmentBytesPerSample) {
|
|
186
206
|
return colorFormat;
|
|
@@ -197,10 +217,11 @@ function getLightPassColorAttachments(ctx, colorAttachment) {
|
|
|
197
217
|
const attachments = [
|
|
198
218
|
colorAttachment
|
|
199
219
|
];
|
|
200
|
-
if (ctx.materialFlags & MaterialVaryingFlags.
|
|
201
|
-
attachments.push(ctx.
|
|
202
|
-
}
|
|
203
|
-
|
|
220
|
+
if (ctx.materialFlags & MaterialVaryingFlags.SCENE_STORE_ROUGHNESS) {
|
|
221
|
+
attachments.push(ctx.SceneRoughnessTexture);
|
|
222
|
+
}
|
|
223
|
+
if (ctx.materialFlags & MaterialVaryingFlags.SCENE_STORE_NORMAL) {
|
|
224
|
+
attachments.push(ctx.SceneNormalTexture);
|
|
204
225
|
}
|
|
205
226
|
if (ctx.materialFlags & MaterialVaryingFlags.SSS_STORE_PROFILE) {
|
|
206
227
|
attachments.push(ctx.SSSProfileTexture, ctx.SSSParamTexture);
|
|
@@ -216,89 +237,143 @@ function getLightPassColorAttachments(ctx, colorAttachment) {
|
|
|
216
237
|
}
|
|
217
238
|
return attachments.length === 1 ? attachments[0] : attachments;
|
|
218
239
|
}
|
|
219
|
-
/**
|
|
220
|
-
* Derive pipeline options from the current scene/camera state.
|
|
221
|
-
* @internal
|
|
222
|
-
*/ function deriveForwardPlusOptions(scene, camera, deviceType, renderQueue) {
|
|
240
|
+
/** Derive Forward+ options from scene and camera state. @internal */ function deriveForwardPlusOptions(scene, camera, deviceType, renderQueue) {
|
|
223
241
|
const ssr = camera.SSR && scene.env.light.envLight && scene.env.light.envLight.hasRadiance();
|
|
242
|
+
const ssgi = camera.SSGI && camera.HDR && camera.ssgiIntensity > 0 && scene.env.light.type === 'ibl' && !!scene.env.light.envLight?.hasRadiance() && !!scene.env.light.envLight?.hasIrradiance();
|
|
224
243
|
const sss = camera.SSS && renderQueueHasActiveSSS(renderQueue);
|
|
225
244
|
const skinSSS = camera.skinSSS && renderQueueHasActiveSkinSSS(renderQueue);
|
|
226
245
|
const needSceneColor = renderQueue.needSceneColor();
|
|
227
246
|
const needSceneColorWithDepth = renderQueue.needSceneColorWithDepth();
|
|
228
247
|
return {
|
|
229
248
|
depthPrepass: true,
|
|
230
|
-
motionVectors:
|
|
231
|
-
hiZ:
|
|
249
|
+
motionVectors: false,
|
|
250
|
+
hiZ: false,
|
|
251
|
+
sceneNormal: false,
|
|
252
|
+
sceneRoughness: false,
|
|
253
|
+
shadowMask: false,
|
|
232
254
|
ssr: !!ssr,
|
|
255
|
+
ssgi: !!ssgi,
|
|
233
256
|
ssrCalcThickness: !!ssr && camera.ssrCalcThickness,
|
|
234
257
|
gpuPicking: !!camera.getPickResultResolveFunc(),
|
|
235
258
|
needSceneColor,
|
|
236
259
|
needSceneColorWithDepth,
|
|
237
260
|
needsTransmissionDepthForSSR: !!ssr && needSceneColor && !needSceneColorWithDepth,
|
|
238
261
|
sss: !!sss,
|
|
239
|
-
skinSSS: !!skinSSS
|
|
262
|
+
skinSSS: !!skinSSS,
|
|
263
|
+
fogPresents: !!scene.env.sky?.fogPresents
|
|
240
264
|
};
|
|
241
265
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
266
|
+
function resolveFrameResourceRequirements(ctx, options, requirements) {
|
|
267
|
+
const deviceType = ctx.device.type;
|
|
268
|
+
options.motionVectors ||= !!requirements.motionVector;
|
|
269
|
+
options.hiZ ||= !!requirements.hiZ;
|
|
270
|
+
options.sceneNormal ||= !!requirements.sceneNormal;
|
|
271
|
+
options.sceneRoughness ||= !!requirements.sceneRoughness;
|
|
272
|
+
options.shadowMask ||= !!requirements.shadowMask;
|
|
273
|
+
if (options.motionVectors && deviceType === 'webgl') {
|
|
274
|
+
throw new Error('Forward+: MotionVector was requested but is not supported by the WebGL backend.');
|
|
275
|
+
}
|
|
276
|
+
if (options.hiZ && deviceType === 'webgl') {
|
|
277
|
+
throw new Error('Forward+: HiZ was requested but is not supported by the WebGL backend.');
|
|
278
|
+
}
|
|
279
|
+
if (options.shadowMask && deviceType === 'webgl') {
|
|
280
|
+
throw new Error('Forward+: ShadowMask was requested but is not supported by the WebGL backend.');
|
|
281
|
+
}
|
|
282
|
+
const surfaceAttachmentCount = Number(options.sceneNormal) + Number(options.sceneRoughness);
|
|
283
|
+
if (surfaceAttachmentCount > 0) {
|
|
284
|
+
const caps = ctx.device.getDeviceCaps();
|
|
285
|
+
const maxDrawBuffers = caps.framebufferCaps.maxDrawBuffers ?? Number.MAX_SAFE_INTEGER;
|
|
286
|
+
if (1 + surfaceAttachmentCount > maxDrawBuffers) {
|
|
287
|
+
throw new Error(`Forward+: ${surfaceAttachmentCount} scene surface attachment(s) were requested, ` + `but the device supports only ${maxDrawBuffers} color attachments.`);
|
|
288
|
+
}
|
|
289
|
+
const bytesPerSample = getTextureFormatBytes(ctx, ctx.colorFormat) + getTextureFormatBytes(ctx, getSurfaceTextureFormat(ctx)) * surfaceAttachmentCount;
|
|
290
|
+
if (bytesPerSample > caps.framebufferCaps.maxColorAttachmentBytesPerSample) {
|
|
291
|
+
throw new Error(`Forward+: requested scene surface attachments require ${bytesPerSample} bytes per sample, ` + `but the device limit is ${caps.framebufferCaps.maxColorAttachmentBytesPerSample}.`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
ctx.motionVectors = options.motionVectors;
|
|
295
|
+
ctx.HiZ = options.hiZ;
|
|
296
|
+
ctx.SSGI = options.ssgi;
|
|
297
|
+
ctx.screenSpaceShadowMask = options.shadowMask;
|
|
298
|
+
ctx.SSS = options.sss;
|
|
259
299
|
}
|
|
260
|
-
function
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
300
|
+
function validateProducedFrameResources(blackboard, options, renderQueue) {
|
|
301
|
+
const required = [
|
|
302
|
+
[
|
|
303
|
+
options.motionVectors,
|
|
304
|
+
FrameResources.MotionVector
|
|
305
|
+
],
|
|
306
|
+
[
|
|
307
|
+
options.hiZ,
|
|
308
|
+
FrameResources.HiZ
|
|
309
|
+
],
|
|
310
|
+
[
|
|
311
|
+
options.sceneNormal,
|
|
312
|
+
FrameResources.SceneNormal
|
|
313
|
+
],
|
|
314
|
+
[
|
|
315
|
+
options.sceneRoughness,
|
|
316
|
+
FrameResources.SceneRoughness
|
|
317
|
+
],
|
|
318
|
+
[
|
|
319
|
+
options.shadowMask && renderQueue.shadowedLights.length > 0,
|
|
320
|
+
FrameResources.ShadowMask
|
|
321
|
+
]
|
|
322
|
+
];
|
|
323
|
+
for (const [needed, resource] of required){
|
|
324
|
+
if (needed && !blackboard.has(resource)) {
|
|
325
|
+
throw new Error(`Forward+: frame resource "${resource}" was requested but no enabled RenderModule produced it.`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/** Require state produced by an earlier module. @internal */ function requireBuildState(fg, key, producerType, consumerType) {
|
|
330
|
+
const value = fg.state[key];
|
|
331
|
+
if (!value) {
|
|
332
|
+
throw new Error(`Forward+ module "${consumerType}" requires module "${producerType}" ` + `(build state "${String(key)}" was not produced). Did you remove it from the pipeline?`);
|
|
333
|
+
}
|
|
334
|
+
return value;
|
|
335
|
+
}
|
|
336
|
+
/** @internal */ const SkyUpdateModule = {
|
|
337
|
+
type: 'SkyUpdate',
|
|
338
|
+
prepare: ()=>({
|
|
339
|
+
enabled: true
|
|
340
|
+
}),
|
|
341
|
+
setup ({ graph, ctx, frame, ordering }) {
|
|
342
|
+
graph.addPass('SkyUpdate', (builder)=>{
|
|
343
|
+
ordering.emit(builder, 'SkyUpdateDone');
|
|
344
|
+
builder.sideEffect();
|
|
345
|
+
builder.setExecute(()=>{
|
|
346
|
+
frame.sunLightColor = ctx.scene.env.sky.update(ctx);
|
|
347
|
+
});
|
|
283
348
|
});
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
/** @internal */ const ClusterLightsModule = {
|
|
352
|
+
type: 'ClusterLights',
|
|
353
|
+
prepare: ()=>({
|
|
354
|
+
enabled: true
|
|
355
|
+
}),
|
|
356
|
+
setup ({ graph, ctx, renderQueue, ordering }) {
|
|
357
|
+
graph.addPass('ClusterLights', (builder)=>{
|
|
358
|
+
ordering.chainInto(builder);
|
|
359
|
+
ordering.emit(builder, 'ClusterLightsDone');
|
|
360
|
+
builder.sideEffect();
|
|
361
|
+
builder.setExecute(()=>{
|
|
362
|
+
ctx.clusteredLight = getClusteredLight();
|
|
363
|
+
ctx.clusteredLight.calculateLightIndex(ctx.camera, renderQueue, ctx.screenSpaceShadowMask, ShaderHelper.getPreExposure(ctx));
|
|
364
|
+
});
|
|
294
365
|
});
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
/** @internal */ const GPUPickingModule = {
|
|
369
|
+
type: 'GPUPicking',
|
|
370
|
+
prepare: ({ options })=>({
|
|
371
|
+
enabled: options.gpuPicking
|
|
372
|
+
}),
|
|
373
|
+
setup ({ graph, ctx, renderQueue, ordering }) {
|
|
374
|
+
graph.addPass('GPUPicking', (builder)=>{
|
|
375
|
+
ordering.chainInto(builder);
|
|
376
|
+
ordering.emit(builder, 'GPUPickingDone');
|
|
302
377
|
builder.sideEffect();
|
|
303
378
|
builder.setExecute(()=>{
|
|
304
379
|
const pickResolveFunc = ctx.camera.getPickResultResolveFunc();
|
|
@@ -306,125 +381,140 @@ function buildForwardPlusGraphInternal(graph, ctx, renderQueue, options) {
|
|
|
306
381
|
renderObjectColors(ctx, pickResolveFunc, renderQueue);
|
|
307
382
|
}
|
|
308
383
|
});
|
|
309
|
-
return done;
|
|
310
384
|
});
|
|
311
385
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
386
|
+
};
|
|
387
|
+
/** @internal */ const ShadowMapsModule = {
|
|
388
|
+
type: 'ShadowMaps',
|
|
389
|
+
// Light-owned shadow maps are observable side effects.
|
|
390
|
+
prepare: ({ renderQueue })=>({
|
|
391
|
+
enabled: renderQueue.shadowedLights.length > 0
|
|
392
|
+
}),
|
|
393
|
+
setup ({ graph, ctx, renderQueue, ordering }) {
|
|
394
|
+
graph.addPass('ShadowMaps', (builder)=>{
|
|
395
|
+
ordering.chainInto(builder);
|
|
396
|
+
ordering.emit(builder, 'ShadowMapsDone');
|
|
318
397
|
builder.sideEffect();
|
|
319
398
|
builder.setExecute(()=>{
|
|
320
399
|
renderShadowMaps(ctx, renderQueue.shadowedLights);
|
|
321
400
|
});
|
|
322
|
-
return done;
|
|
323
401
|
});
|
|
324
402
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
403
|
+
};
|
|
404
|
+
/** @internal */ const DepthPrepassModule = {
|
|
405
|
+
type: 'DepthPrepass',
|
|
406
|
+
writes: [
|
|
407
|
+
FrameResources.LinearDepth,
|
|
408
|
+
FrameResources.MotionVector,
|
|
409
|
+
FrameResources.SceneDepthAttachment
|
|
410
|
+
],
|
|
411
|
+
prepare: ()=>({
|
|
412
|
+
enabled: true
|
|
413
|
+
}),
|
|
414
|
+
setup (fg) {
|
|
415
|
+
const { graph, ctx, frame, ordering, blackboard, options } = fg;
|
|
416
|
+
const result = graph.addPass('DepthPrepass', (builder)=>{
|
|
417
|
+
ordering.chainInto(builder);
|
|
418
|
+
const format = ctx.device.type === 'webgl' ? ctx.SSRCalcThickness ? 'rgba16f' : 'rgba8unorm' : ctx.SSRCalcThickness ? 'rg32f' : 'r32f';
|
|
419
|
+
const mvFormat = 'rgba16f';
|
|
420
|
+
const depthHandle = builder.createTexture({
|
|
421
|
+
format,
|
|
422
|
+
label: 'linearDepth',
|
|
423
|
+
allocationKey: 'ForwardPlus.LinearDepth'
|
|
424
|
+
});
|
|
425
|
+
const motionVectorHandle = options.motionVectors ? builder.createTexture({
|
|
426
|
+
format: mvFormat,
|
|
427
|
+
label: 'motionVector',
|
|
428
|
+
allocationKey: 'ForwardPlus.MotionVector'
|
|
429
|
+
}) : undefined;
|
|
430
|
+
const finalDepthAttachment = ctx.finalFramebuffer?.getDepthAttachment();
|
|
431
|
+
const externalDepthAttachment = finalDepthAttachment?.isTexture2D() ? finalDepthAttachment : null;
|
|
432
|
+
const externalDepthAttachmentHandle = externalDepthAttachment ? graph.importTexture('externalSceneDepth') : undefined;
|
|
433
|
+
const graphDepthAttachmentHandle = externalDepthAttachment ? undefined : builder.createTexture({
|
|
434
|
+
format: ctx.depthFormat,
|
|
435
|
+
label: 'sceneDepth',
|
|
436
|
+
allocationKey: 'ForwardPlus.SceneDepth'
|
|
437
|
+
});
|
|
438
|
+
const depthAttachmentOrFormat = externalDepthAttachmentHandle ?? graphDepthAttachmentHandle ?? ctx.depthFormat;
|
|
439
|
+
const depthFramebufferHandle = builder.createFramebuffer({
|
|
440
|
+
label: 'DepthPrepassFramebuffer',
|
|
441
|
+
width: ctx.renderWidth,
|
|
442
|
+
height: ctx.renderHeight,
|
|
443
|
+
colorAttachments: motionVectorHandle ? [
|
|
444
|
+
depthHandle,
|
|
445
|
+
motionVectorHandle
|
|
446
|
+
] : depthHandle,
|
|
447
|
+
depthAttachment: depthAttachmentOrFormat,
|
|
448
|
+
ignoreDepthStencil: false
|
|
449
|
+
});
|
|
450
|
+
const skyMotionVectorFramebufferHandle = motionVectorHandle ? builder.createFramebuffer({
|
|
451
|
+
label: 'SkyMotionVectorFramebuffer',
|
|
452
|
+
width: ctx.renderWidth,
|
|
453
|
+
height: ctx.renderHeight,
|
|
454
|
+
colorAttachments: motionVectorHandle,
|
|
455
|
+
depthAttachment: depthAttachmentOrFormat
|
|
456
|
+
}) : undefined;
|
|
457
|
+
builder.addSubpass('SceneDepth', (rgCtx)=>{
|
|
458
|
+
const depthFramebuffer = rgCtx.getFramebuffer(depthFramebufferHandle);
|
|
459
|
+
frame.depthFramebuffer = renderSceneDepth(frame, depthFramebuffer, rgCtx, undefined, undefined, false);
|
|
460
|
+
});
|
|
461
|
+
if (skyMotionVectorFramebufferHandle) {
|
|
462
|
+
builder.addSubpass('SkyMotionVectors', (rgCtx)=>{
|
|
463
|
+
renderSkyMotionVectors(ctx, rgCtx, skyMotionVectorFramebufferHandle);
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
351
467
|
depthHandle,
|
|
352
|
-
motionVectorHandle
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
label: 'SkyMotionVectorFramebuffer',
|
|
359
|
-
width: ctx.renderWidth,
|
|
360
|
-
height: ctx.renderHeight,
|
|
361
|
-
colorAttachments: motionVectorHandle,
|
|
362
|
-
depthAttachment: depthAttachmentOrFormat
|
|
363
|
-
}) : undefined;
|
|
364
|
-
builder.addSubpass('SceneDepth', (rgCtx)=>{
|
|
365
|
-
const depthFramebuffer = rgCtx.getFramebuffer(depthFramebufferHandle);
|
|
366
|
-
frame.depthFramebuffer = renderSceneDepth(frame, depthFramebuffer, rgCtx, undefined, undefined, false);
|
|
468
|
+
motionVectorHandle,
|
|
469
|
+
graphDepthAttachmentHandle,
|
|
470
|
+
externalDepthAttachmentHandle,
|
|
471
|
+
externalDepthAttachment,
|
|
472
|
+
depthFramebufferHandle
|
|
473
|
+
};
|
|
367
474
|
});
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
475
|
+
fg.state.depth = result;
|
|
476
|
+
// Depth mutations re-register their versions through the blackboard.
|
|
477
|
+
blackboard.set(FrameResources.LinearDepth, result.depthHandle);
|
|
478
|
+
if (result.motionVectorHandle) {
|
|
479
|
+
blackboard.set(FrameResources.MotionVector, result.motionVectorHandle);
|
|
372
480
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
};
|
|
380
|
-
});
|
|
381
|
-
let depthHandle = depthPassResult.depthHandle;
|
|
382
|
-
const motionVectorHandle = depthPassResult.motionVectorHandle;
|
|
383
|
-
blackboard.set(FrameResources.LinearDepth, depthHandle);
|
|
384
|
-
if (motionVectorHandle) {
|
|
385
|
-
blackboard.set(FrameResources.MotionVector, motionVectorHandle);
|
|
386
|
-
}
|
|
387
|
-
if (depthPassResult.graphDepthAttachmentHandle) {
|
|
388
|
-
blackboard.set(FrameResources.SceneDepthAttachment, depthPassResult.graphDepthAttachmentHandle);
|
|
481
|
+
blackboard.set(FrameResources.SceneDepthAttachment, result.graphDepthAttachmentHandle ?? result.externalDepthAttachmentHandle);
|
|
482
|
+
// Later modules share this attachment without owning it.
|
|
483
|
+
fg.state.renderDepthAttachment = result.graphDepthAttachmentHandle ?? result.externalDepthAttachmentHandle ?? null;
|
|
484
|
+
// Opaque effects require a texture and may require surface MRT attachments.
|
|
485
|
+
const opaqueLayerHasEffects = !!ctx.compositor?.layerHasEnabledEffect(PostEffectLayer.opaque);
|
|
486
|
+
fg.state.useFinalFramebufferAsIntermediate = !!result.externalDepthAttachment && result.externalDepthAttachment === ctx.finalFramebuffer?.getDepthAttachment() && !opaqueLayerHasEffects;
|
|
389
487
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
//
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
488
|
+
};
|
|
489
|
+
/** @internal */ const ShadowMaskModule = {
|
|
490
|
+
type: 'ShadowMaskPass',
|
|
491
|
+
writes: [
|
|
492
|
+
FrameResources.ShadowMask
|
|
493
|
+
],
|
|
494
|
+
// shadowMapInfo is populated at execute time and cannot gate graph building.
|
|
495
|
+
prepare: ({ ctx, options, renderQueue })=>({
|
|
496
|
+
enabled: options.shadowMask && renderQueue.shadowedLights.length > 0,
|
|
497
|
+
requirements: {
|
|
498
|
+
shadowMask: ctx.device.type !== 'webgl' && ctx.camera.screenSpaceShadowMask && renderQueue.shadowedLights.length > 0
|
|
499
|
+
}
|
|
500
|
+
}),
|
|
501
|
+
setup (fg) {
|
|
502
|
+
// Four shadow lights share each RGBA8 layer in clustered-light order.
|
|
503
|
+
const { graph, ctx, renderQueue, blackboard } = fg;
|
|
504
|
+
const depthPassResult = requireBuildState(fg, 'depth', 'DepthPrepass', 'ShadowMaskPass');
|
|
407
505
|
const numShadowLights = renderQueue.shadowedLights.length;
|
|
408
506
|
const numLayers = ShadowMaskRenderer.getLayerCount(numShadowLights);
|
|
409
507
|
const maskPassResult = graph.addPass('ShadowMaskPass', (builder)=>{
|
|
410
|
-
//
|
|
411
|
-
|
|
412
|
-
// version ('linearDepth@TransmissionDepth'); if the execute closure below
|
|
413
|
-
// captured it by reference it would read a handle this pass never declared,
|
|
414
|
-
// tripping RenderGraphExecutor's access assertion. The shadow mask is built
|
|
415
|
-
// from the opaque prepass depth, so the pre-transmission version is correct.
|
|
416
|
-
const maskDepthHandle = depthHandle;
|
|
508
|
+
// Capture the depth version declared at this pipeline position.
|
|
509
|
+
const maskDepthHandle = blackboard.expect(FrameResources.LinearDepth);
|
|
417
510
|
builder.read(maskDepthHandle);
|
|
418
511
|
builder.read(depthPassResult.depthFramebufferHandle);
|
|
419
|
-
//
|
|
420
|
-
// downstream passes read this handle directly (same pattern as HiZ). The
|
|
421
|
-
// per-layer framebuffers are created inside execute (rgCtx.createFramebuffer),
|
|
422
|
-
// which the graph cannot see; the createTexture producer edge is what keeps
|
|
423
|
-
// the resource alive and ordered before the LightPass reader.
|
|
512
|
+
// Per-layer framebuffers are temporary views of this graph texture.
|
|
424
513
|
const maskHandle = builder.createTexture({
|
|
425
514
|
format: 'rgba8unorm',
|
|
426
515
|
label: 'shadowMask',
|
|
427
|
-
arrayLayers: numLayers
|
|
516
|
+
arrayLayers: numLayers,
|
|
517
|
+
allocationKey: 'ForwardPlus.ShadowMask'
|
|
428
518
|
});
|
|
429
519
|
builder.setExecute((rgCtx)=>{
|
|
430
520
|
const depthTex = rgCtx.getTexture(maskDepthHandle);
|
|
@@ -436,34 +526,31 @@ function buildForwardPlusGraphInternal(graph, ctx, renderQueue, options) {
|
|
|
436
526
|
depthAttachment: null,
|
|
437
527
|
attachmentLayer: layer
|
|
438
528
|
}));
|
|
439
|
-
ctx.shadowMaskTexture = maskTex;
|
|
440
529
|
});
|
|
441
530
|
return {
|
|
442
531
|
maskHandle
|
|
443
532
|
};
|
|
444
533
|
});
|
|
445
|
-
|
|
446
|
-
blackboard.set(FrameResources.ShadowMask, shadowMaskHandle);
|
|
534
|
+
blackboard.set(FrameResources.ShadowMask, maskPassResult.maskHandle);
|
|
447
535
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
536
|
+
};
|
|
537
|
+
/** @internal */ const TransmissionDepthForSSRModule = {
|
|
538
|
+
type: 'TransmissionDepthForSSR',
|
|
539
|
+
writes: [
|
|
540
|
+
FrameResources.LinearDepth
|
|
541
|
+
],
|
|
542
|
+
prepare: ({ options })=>({
|
|
543
|
+
enabled: options.needsTransmissionDepthForSSR
|
|
544
|
+
}),
|
|
545
|
+
setup (fg) {
|
|
546
|
+
const { graph, frame, blackboard } = fg;
|
|
547
|
+
const depthPassResult = requireBuildState(fg, 'depth', 'DepthPrepass', 'TransmissionDepthForSSR');
|
|
460
548
|
const transmissionDepthResult = graph.addPass('TransmissionDepthForSSR', (builder)=>{
|
|
461
|
-
|
|
549
|
+
const currentDepth = blackboard.expect(FrameResources.LinearDepth);
|
|
550
|
+
builder.read(currentDepth);
|
|
462
551
|
builder.read(depthPassResult.depthFramebufferHandle);
|
|
463
|
-
//
|
|
464
|
-
|
|
465
|
-
// it through data flow instead of relying on the token alone.
|
|
466
|
-
const depthOut = builder.write(depthHandle);
|
|
552
|
+
// Version the in-place depth mutation for downstream dependencies.
|
|
553
|
+
const depthOut = builder.write(currentDepth);
|
|
467
554
|
const done = builder.createToken('TransmissionDepthForSSRDone');
|
|
468
555
|
builder.sideEffect();
|
|
469
556
|
builder.setExecute((rgCtx)=>{
|
|
@@ -474,24 +561,38 @@ function buildForwardPlusGraphInternal(graph, ctx, renderQueue, options) {
|
|
|
474
561
|
depthOut
|
|
475
562
|
};
|
|
476
563
|
});
|
|
477
|
-
preLightTransmissionDepthToken = transmissionDepthResult.done;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
blackboard.set(FrameResources.LinearDepth, depthHandle);
|
|
564
|
+
fg.state.preLightTransmissionDepthToken = transmissionDepthResult.done;
|
|
565
|
+
// Publish the post-transmission depth version.
|
|
566
|
+
blackboard.set(FrameResources.LinearDepth, transmissionDepthResult.depthOut);
|
|
481
567
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
568
|
+
};
|
|
569
|
+
/** @internal */ const HiZModule = {
|
|
570
|
+
type: 'HiZ',
|
|
571
|
+
writes: [
|
|
572
|
+
FrameResources.HiZ
|
|
573
|
+
],
|
|
574
|
+
prepare: ({ options })=>({
|
|
575
|
+
enabled: options.hiZ
|
|
576
|
+
}),
|
|
577
|
+
setup (fg) {
|
|
578
|
+
const { graph, ctx, frame, blackboard } = fg;
|
|
579
|
+
const depthPassResult = requireBuildState(fg, 'depth', 'DepthPrepass', 'HiZ');
|
|
580
|
+
const preLightTransmissionDepthToken = fg.state.preLightTransmissionDepthToken;
|
|
581
|
+
//const hiZWidth = nextPowerOf2(ctx.renderWidth);
|
|
582
|
+
//const hiZHeight = nextPowerOf2(ctx.renderHeight);
|
|
583
|
+
let hiZHandle;
|
|
485
584
|
graph.addPass('HiZ', (builder)=>{
|
|
486
|
-
builder.read(
|
|
585
|
+
builder.read(blackboard.expect(FrameResources.LinearDepth));
|
|
487
586
|
builder.read(depthPassResult.depthFramebufferHandle);
|
|
488
587
|
if (preLightTransmissionDepthToken) {
|
|
489
588
|
builder.read(preLightTransmissionDepthToken);
|
|
490
589
|
}
|
|
491
590
|
hiZHandle = builder.createTexture({
|
|
492
|
-
format: '
|
|
591
|
+
format: REVERSE_Z ? 'r16f' : 'r32f',
|
|
493
592
|
label: 'hiZ',
|
|
494
|
-
|
|
593
|
+
sizeMode: 'backbuffer-relative',
|
|
594
|
+
mipLevels: getFullMipLevelCount(ctx.renderWidth, ctx.renderHeight),
|
|
595
|
+
allocationKey: 'ForwardPlus.HiZ'
|
|
495
596
|
});
|
|
496
597
|
const hiZFramebufferHandle = builder.createFramebuffer({
|
|
497
598
|
label: 'HiZFramebuffer',
|
|
@@ -499,79 +600,55 @@ function buildForwardPlusGraphInternal(graph, ctx, renderQueue, options) {
|
|
|
499
600
|
depthAttachment: null
|
|
500
601
|
});
|
|
501
602
|
builder.setExecute((rgCtx)=>{
|
|
502
|
-
const
|
|
503
|
-
//
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
const HiZFrameBuffer = rgCtx.getFramebuffer(hiZFramebufferHandle);
|
|
509
|
-
buildHiZ(depthTex, HiZFrameBuffer);
|
|
510
|
-
ctx.HiZTexture = hiZTex;
|
|
603
|
+
const passCtx = frame.ctx;
|
|
604
|
+
// Resolve the declared handle, not mutable framebuffer state.
|
|
605
|
+
const depthFb = rgCtx.getFramebuffer(depthPassResult.depthFramebufferHandle);
|
|
606
|
+
const depthTex = depthFb.getDepthAttachment();
|
|
607
|
+
if (!depthTex) {
|
|
608
|
+
throw new Error('HiZ pass: depth prepass framebuffer has no depth attachment.');
|
|
511
609
|
}
|
|
610
|
+
const hiZTex = rgCtx.getTexture(hiZHandle);
|
|
611
|
+
const HiZFrameBuffer = rgCtx.getFramebuffer(hiZFramebufferHandle);
|
|
612
|
+
buildHiZ(depthTex, HiZFrameBuffer);
|
|
613
|
+
passCtx.HiZTexture = hiZTex;
|
|
512
614
|
});
|
|
513
615
|
});
|
|
514
616
|
if (hiZHandle) {
|
|
515
617
|
blackboard.set(FrameResources.HiZ, hiZHandle);
|
|
516
618
|
}
|
|
517
619
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
const motionVectorHistoryHandle = historyManager.importPreviousIfCompatible(graph, RGHistoryResources.SSR_MOTION_VECTOR, {
|
|
533
|
-
format: 'rgba16f',
|
|
534
|
-
sizeMode: 'absolute',
|
|
535
|
-
width: ctx.renderWidth,
|
|
536
|
-
height: ctx.renderHeight
|
|
537
|
-
}, historySize);
|
|
538
|
-
if (reflectHistoryHandle && motionVectorHistoryHandle) {
|
|
539
|
-
lightHistoryReadBindings.push({
|
|
540
|
-
name: RGHistoryResources.SSR_REFLECT,
|
|
541
|
-
handle: reflectHistoryHandle
|
|
542
|
-
}, {
|
|
543
|
-
name: RGHistoryResources.SSR_MOTION_VECTOR,
|
|
544
|
-
handle: motionVectorHistoryHandle
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
// Note: TAA history import/commit is handled by TAA.setup() (self-describing).
|
|
549
|
-
let sssProfileResult;
|
|
550
|
-
if (options.sss) {
|
|
551
|
-
sssProfileResult = graph.addPass('SSSProfile', (builder)=>{
|
|
552
|
-
builder.read(depthHandle);
|
|
620
|
+
};
|
|
621
|
+
/** @internal */ const SSSProfileModule = {
|
|
622
|
+
type: 'SSSProfile',
|
|
623
|
+
prepare: ({ options })=>({
|
|
624
|
+
enabled: options.sss
|
|
625
|
+
}),
|
|
626
|
+
setup (fg) {
|
|
627
|
+
const { graph, ctx, frame, blackboard } = fg;
|
|
628
|
+
const depthPassResult = requireBuildState(fg, 'depth', 'DepthPrepass', 'SSSProfile');
|
|
629
|
+
const preLightTransmissionDepthToken = fg.state.preLightTransmissionDepthToken;
|
|
630
|
+
const shadowMaskHandle = blackboard.get(FrameResources.ShadowMask);
|
|
631
|
+
const renderDepthAttachment = fg.state.renderDepthAttachment;
|
|
632
|
+
const sssProfileResult = graph.addPass('SSSProfile', (builder)=>{
|
|
633
|
+
builder.read(blackboard.expect(FrameResources.LinearDepth));
|
|
553
634
|
builder.read(depthPassResult.depthFramebufferHandle);
|
|
554
635
|
if (preLightTransmissionDepthToken) {
|
|
555
636
|
builder.read(preLightTransmissionDepthToken);
|
|
556
637
|
}
|
|
638
|
+
if (shadowMaskHandle) {
|
|
639
|
+
builder.read(shadowMaskHandle);
|
|
640
|
+
}
|
|
557
641
|
const profileHandle = builder.createTexture({
|
|
558
642
|
format: 'rgba16f',
|
|
559
|
-
label: 'sssProfile'
|
|
643
|
+
label: 'sssProfile',
|
|
644
|
+
allocationKey: 'ForwardPlus.SSSProfile'
|
|
560
645
|
});
|
|
561
646
|
const paramHandle = builder.createTexture({
|
|
562
647
|
format: 'rgba8unorm',
|
|
563
|
-
label: 'sssParam'
|
|
648
|
+
label: 'sssParam',
|
|
649
|
+
allocationKey: 'ForwardPlus.SSSParam'
|
|
564
650
|
});
|
|
565
|
-
const
|
|
566
|
-
format: getSurfaceTextureFormat(ctx),
|
|
567
|
-
label: 'sssNormal'
|
|
568
|
-
});
|
|
569
|
-
const colorAttachments = normalHandle ? [
|
|
570
|
-
ctx.colorFormat,
|
|
571
|
-
normalHandle,
|
|
572
|
-
profileHandle,
|
|
573
|
-
paramHandle
|
|
574
|
-
] : [
|
|
651
|
+
const colorAttachments = [
|
|
575
652
|
ctx.colorFormat,
|
|
576
653
|
profileHandle,
|
|
577
654
|
paramHandle
|
|
@@ -585,34 +662,46 @@ function buildForwardPlusGraphInternal(graph, ctx, renderQueue, options) {
|
|
|
585
662
|
ignoreDepthStencil: false
|
|
586
663
|
});
|
|
587
664
|
builder.setExecute((rgCtx)=>{
|
|
588
|
-
|
|
665
|
+
ctx.shadowMaskTexture = shadowMaskHandle ? rgCtx.getTexture(shadowMaskHandle) : null;
|
|
666
|
+
renderForwardSSSProfile(frame, rgCtx.getFramebuffer(framebufferHandle), rgCtx.getTexture(profileHandle), rgCtx.getTexture(paramHandle), null);
|
|
589
667
|
});
|
|
590
668
|
return {
|
|
591
669
|
profileHandle,
|
|
592
670
|
paramHandle,
|
|
593
|
-
normalHandle,
|
|
594
671
|
framebufferHandle
|
|
595
672
|
};
|
|
596
673
|
});
|
|
674
|
+
blackboard.set(FrameResources.SSSProfile, sssProfileResult.profileHandle);
|
|
675
|
+
blackboard.set(FrameResources.SSSParam, sssProfileResult.paramHandle);
|
|
597
676
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
677
|
+
};
|
|
678
|
+
/** @internal */ const SceneColorGrabModule = {
|
|
679
|
+
type: 'SceneColorGrab',
|
|
680
|
+
prepare: ({ options })=>({
|
|
681
|
+
enabled: options.needSceneColor
|
|
682
|
+
}),
|
|
683
|
+
setup (fg) {
|
|
684
|
+
// Refraction samples this non-transmission scene copy.
|
|
685
|
+
const { graph, ctx, frame, blackboard, options } = fg;
|
|
686
|
+
const depthPassResult = requireBuildState(fg, 'depth', 'DepthPrepass', 'SceneColorGrab');
|
|
687
|
+
const preLightTransmissionDepthToken = fg.state.preLightTransmissionDepthToken;
|
|
688
|
+
const shadowMaskHandle = blackboard.get(FrameResources.ShadowMask);
|
|
689
|
+
const renderDepthAttachment = fg.state.renderDepthAttachment;
|
|
690
|
+
const grabResult = graph.addPass('SceneColorGrab', (builder)=>{
|
|
691
|
+
builder.read(blackboard.expect(FrameResources.LinearDepth));
|
|
605
692
|
builder.read(depthPassResult.depthFramebufferHandle);
|
|
606
693
|
if (preLightTransmissionDepthToken) {
|
|
607
694
|
builder.read(preLightTransmissionDepthToken);
|
|
608
695
|
}
|
|
696
|
+
if (shadowMaskHandle) {
|
|
697
|
+
builder.read(shadowMaskHandle);
|
|
698
|
+
}
|
|
609
699
|
const copyHandle = builder.createTexture({
|
|
610
700
|
format: ctx.colorFormat,
|
|
611
|
-
label: 'sceneColorCopy'
|
|
701
|
+
label: 'sceneColorCopy',
|
|
702
|
+
allocationKey: 'ForwardPlus.SceneColorCopy'
|
|
612
703
|
});
|
|
613
|
-
// SSR
|
|
614
|
-
// case the refraction scene-color copy needs an isolated depth buffer so
|
|
615
|
-
// transmission surfaces do not occlude the background they sample.
|
|
704
|
+
// Isolate depth when SSR inserts transmission depth before LightPass.
|
|
616
705
|
const copyFramebufferHandle = !options.needsTransmissionDepthForSSR ? builder.createFramebuffer({
|
|
617
706
|
label: 'SceneColorCopyFramebuffer',
|
|
618
707
|
width: ctx.renderWidth,
|
|
@@ -622,6 +711,7 @@ function buildForwardPlusGraphInternal(graph, ctx, renderQueue, options) {
|
|
|
622
711
|
ignoreDepthStencil: false
|
|
623
712
|
}) : undefined;
|
|
624
713
|
builder.setExecute((rgCtx)=>{
|
|
714
|
+
ctx.shadowMaskTexture = shadowMaskHandle ? rgCtx.getTexture(shadowMaskHandle) : null;
|
|
625
715
|
renderSceneColorGrab(frame, rgCtx, copyHandle, copyFramebufferHandle);
|
|
626
716
|
});
|
|
627
717
|
return {
|
|
@@ -629,366 +719,569 @@ function buildForwardPlusGraphInternal(graph, ctx, renderQueue, options) {
|
|
|
629
719
|
copyFramebufferHandle
|
|
630
720
|
};
|
|
631
721
|
});
|
|
722
|
+
blackboard.set(FrameResources.SceneColorCopy, grabResult.copyHandle);
|
|
632
723
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
const
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
const
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
724
|
+
};
|
|
725
|
+
/** @internal */ const LightPassModule = {
|
|
726
|
+
type: 'LightPass',
|
|
727
|
+
writes: [
|
|
728
|
+
FrameResources.SceneColor,
|
|
729
|
+
FrameResources.SceneRoughness,
|
|
730
|
+
FrameResources.SceneNormal,
|
|
731
|
+
FrameResources.SSSDiffuse,
|
|
732
|
+
FrameResources.SSSTransmission,
|
|
733
|
+
FrameResources.SkinSSS
|
|
734
|
+
],
|
|
735
|
+
prepare: ()=>({
|
|
736
|
+
enabled: true
|
|
737
|
+
}),
|
|
738
|
+
setup (fg) {
|
|
739
|
+
const { graph, ctx, frame, blackboard, options, backbuffer } = fg;
|
|
740
|
+
const depthPassResult = requireBuildState(fg, 'depth', 'DepthPrepass', 'LightPass');
|
|
741
|
+
const shadowMaskHandle = blackboard.get(FrameResources.ShadowMask);
|
|
742
|
+
const preLightTransmissionDepthToken = fg.state.preLightTransmissionDepthToken;
|
|
743
|
+
const hiZHandle = blackboard.get(FrameResources.HiZ);
|
|
744
|
+
const sssProfileHandle = blackboard.get(FrameResources.SSSProfile);
|
|
745
|
+
const sssParamHandle = blackboard.get(FrameResources.SSSParam);
|
|
746
|
+
const sceneColorCopyHandle = blackboard.get(FrameResources.SceneColorCopy);
|
|
747
|
+
const useFinalFramebufferAsIntermediate = fg.state.useFinalFramebufferAsIntermediate;
|
|
748
|
+
const renderDepthAttachment = fg.state.renderDepthAttachment;
|
|
749
|
+
const historyManager = fg.history;
|
|
750
|
+
// Keep SSR history scoped while the light pass executes.
|
|
751
|
+
const lightHistoryReadBindings = fg.state.lightHistoryReadBindings;
|
|
752
|
+
const historySize = {
|
|
753
|
+
width: ctx.renderWidth,
|
|
754
|
+
height: ctx.renderHeight
|
|
755
|
+
};
|
|
756
|
+
if (historyManager && options.ssr && ctx.camera?.ssrTemporal && options.motionVectors) {
|
|
757
|
+
const reflectHistoryHandle = historyManager.importPreviousIfCompatible(graph, RGHistoryResources.SSR_REFLECT, {
|
|
758
|
+
format: 'rgba16f',
|
|
759
|
+
sizeMode: 'absolute',
|
|
760
|
+
width: ctx.renderWidth,
|
|
761
|
+
height: ctx.renderHeight
|
|
762
|
+
}, historySize);
|
|
763
|
+
const motionVectorHistoryHandle = historyManager.importPreviousIfCompatible(graph, RGHistoryResources.SSR_MOTION_VECTOR, {
|
|
764
|
+
format: 'rgba16f',
|
|
765
|
+
sizeMode: 'absolute',
|
|
766
|
+
width: ctx.renderWidth,
|
|
767
|
+
height: ctx.renderHeight
|
|
768
|
+
}, historySize);
|
|
769
|
+
if (reflectHistoryHandle && motionVectorHistoryHandle) {
|
|
770
|
+
lightHistoryReadBindings.push({
|
|
771
|
+
name: RGHistoryResources.SSR_REFLECT,
|
|
772
|
+
handle: reflectHistoryHandle
|
|
773
|
+
}, {
|
|
774
|
+
name: RGHistoryResources.SSR_MOTION_VECTOR,
|
|
775
|
+
handle: motionVectorHistoryHandle
|
|
776
|
+
});
|
|
666
777
|
}
|
|
667
778
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
779
|
+
if (historyManager && options.ssgi) {
|
|
780
|
+
const ssgiHistorySize = {
|
|
781
|
+
width: ctx.renderWidth,
|
|
782
|
+
height: ctx.renderHeight
|
|
783
|
+
};
|
|
784
|
+
const irradianceHistoryHandle = historyManager.importPreviousIfCompatible(graph, RGHistoryResources.SSGI_IRRADIANCE, {
|
|
785
|
+
format: 'rgba16f',
|
|
786
|
+
sizeMode: 'absolute',
|
|
787
|
+
width: ctx.renderWidth,
|
|
788
|
+
height: ctx.renderHeight
|
|
789
|
+
}, ssgiHistorySize);
|
|
790
|
+
const surfaceHistoryHandle = historyManager.importPreviousIfCompatible(graph, RGHistoryResources.SSGI_SURFACE, {
|
|
791
|
+
format: 'rgba16f',
|
|
792
|
+
sizeMode: 'absolute',
|
|
793
|
+
width: ctx.renderWidth,
|
|
794
|
+
height: ctx.renderHeight
|
|
795
|
+
}, ssgiHistorySize);
|
|
796
|
+
if (irradianceHistoryHandle && surfaceHistoryHandle) {
|
|
797
|
+
lightHistoryReadBindings.push({
|
|
798
|
+
name: RGHistoryResources.SSGI_IRRADIANCE,
|
|
799
|
+
handle: irradianceHistoryHandle
|
|
800
|
+
}, {
|
|
801
|
+
name: RGHistoryResources.SSGI_SURFACE,
|
|
802
|
+
handle: surfaceHistoryHandle
|
|
803
|
+
});
|
|
804
|
+
}
|
|
684
805
|
}
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
// rendering and apply()-based effects still read.
|
|
712
|
-
ctx.SSRRoughnessTexture = ssrRoughnessHandle ? rgCtx.getTexture(ssrRoughnessHandle) : null;
|
|
713
|
-
ctx.SSRNormalTexture = ssrNormalHandle ? rgCtx.getTexture(ssrNormalHandle) : null;
|
|
714
|
-
if (sssProfileResult) {
|
|
715
|
-
ctx.SSSProfileTexture = rgCtx.getTexture(sssProfileResult.profileHandle);
|
|
716
|
-
ctx.SSSParamTexture = rgCtx.getTexture(sssProfileResult.paramHandle);
|
|
717
|
-
if (sssProfileResult.normalHandle) {
|
|
718
|
-
ctx.SSRNormalTexture = rgCtx.getTexture(sssProfileResult.normalHandle);
|
|
719
|
-
}
|
|
806
|
+
const opaquePassResult = graph.addPass('LightPass', (builder)=>{
|
|
807
|
+
builder.read(blackboard.expect(FrameResources.LinearDepth));
|
|
808
|
+
builder.read(depthPassResult.depthFramebufferHandle);
|
|
809
|
+
if (shadowMaskHandle) {
|
|
810
|
+
builder.read(shadowMaskHandle);
|
|
811
|
+
}
|
|
812
|
+
if (preLightTransmissionDepthToken) {
|
|
813
|
+
builder.read(preLightTransmissionDepthToken);
|
|
814
|
+
}
|
|
815
|
+
if (hiZHandle) {
|
|
816
|
+
builder.read(hiZHandle);
|
|
817
|
+
}
|
|
818
|
+
for (const binding of lightHistoryReadBindings){
|
|
819
|
+
builder.read(binding.handle);
|
|
820
|
+
}
|
|
821
|
+
// Direct rendering writes the backbuffer; otherwise create a texture.
|
|
822
|
+
const sceneColorHandle = useFinalFramebufferAsIntermediate ? builder.write(backbuffer) : builder.createTexture({
|
|
823
|
+
format: ctx.colorFormat,
|
|
824
|
+
label: 'sceneColor',
|
|
825
|
+
allocationKey: 'ForwardPlus.SceneColor'
|
|
826
|
+
});
|
|
827
|
+
if (sceneColorCopyHandle) {
|
|
828
|
+
builder.read(sceneColorCopyHandle);
|
|
829
|
+
}
|
|
830
|
+
if (sssProfileHandle) {
|
|
831
|
+
builder.read(sssProfileHandle);
|
|
720
832
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
833
|
+
if (sssParamHandle) {
|
|
834
|
+
builder.read(sssParamHandle);
|
|
835
|
+
}
|
|
836
|
+
const surfaceAttachmentCount = Number(options.sceneRoughness) + Number(options.sceneNormal);
|
|
837
|
+
// Surface MRT products are exposed through blackboard handles.
|
|
838
|
+
const sceneRoughnessHandle = options.sceneRoughness ? builder.createTexture({
|
|
839
|
+
format: getSurfaceTextureFormat(ctx),
|
|
840
|
+
label: 'sceneRoughness',
|
|
841
|
+
allocationKey: 'ForwardPlus.SceneRoughness'
|
|
842
|
+
}) : undefined;
|
|
843
|
+
const sceneNormalHandle = options.sceneNormal ? builder.createTexture({
|
|
844
|
+
format: getSurfaceTextureFormat(ctx),
|
|
845
|
+
label: 'sceneNormal',
|
|
846
|
+
allocationKey: 'ForwardPlus.SceneNormal'
|
|
847
|
+
}) : undefined;
|
|
848
|
+
const writeSSSDiffuse = options.sss && shouldStoreSSSDiffuse(ctx);
|
|
849
|
+
let writeSSSTransmission = options.sss && shouldStoreSSSTransmission(ctx);
|
|
850
|
+
if (writeSSSDiffuse && writeSSSTransmission && surfaceAttachmentCount > 0 && getSSSLightingTextureFormat(ctx, 2, surfaceAttachmentCount) !== ctx.colorFormat) {
|
|
851
|
+
writeSSSTransmission = false;
|
|
852
|
+
}
|
|
853
|
+
const writeSkinSSS = options.skinSSS;
|
|
854
|
+
const sssLightingAttachmentCount = (writeSSSDiffuse ? 1 : 0) + (writeSSSTransmission ? 1 : 0) + (writeSkinSSS ? 1 : 0);
|
|
855
|
+
const sssLightingFormat = getSSSLightingTextureFormat(ctx, sssLightingAttachmentCount, surfaceAttachmentCount);
|
|
856
|
+
const sssDiffuseHandle = writeSSSDiffuse ? builder.createTexture({
|
|
857
|
+
format: sssLightingFormat,
|
|
858
|
+
label: 'sssDiffuse',
|
|
859
|
+
allocationKey: 'ForwardPlus.SSSDiffuse'
|
|
860
|
+
}) : undefined;
|
|
861
|
+
const sssTransmissionHandle = writeSSSTransmission ? builder.createTexture({
|
|
862
|
+
format: sssLightingFormat,
|
|
863
|
+
label: 'sssTransmission',
|
|
864
|
+
allocationKey: 'ForwardPlus.SSSTransmission'
|
|
865
|
+
}) : undefined;
|
|
866
|
+
const skinSSSHandle = writeSkinSSS ? builder.createTexture({
|
|
867
|
+
format: sssLightingFormat,
|
|
868
|
+
label: 'skinSSS',
|
|
869
|
+
allocationKey: 'ForwardPlus.SkinSSS'
|
|
870
|
+
}) : undefined;
|
|
871
|
+
const sceneColorFramebufferHandle = useFinalFramebufferAsIntermediate ? undefined : builder.createFramebuffer({
|
|
872
|
+
label: 'SceneColorFramebuffer',
|
|
873
|
+
width: ctx.renderWidth,
|
|
874
|
+
height: ctx.renderHeight,
|
|
875
|
+
colorAttachments: sceneColorHandle,
|
|
876
|
+
depthAttachment: renderDepthAttachment
|
|
877
|
+
});
|
|
878
|
+
builder.setExecute((rgCtx)=>{
|
|
879
|
+
const sceneColorTex = rgCtx.getTexture(sceneColorHandle);
|
|
880
|
+
const sceneColorCopyTex = sceneColorCopyHandle ? rgCtx.getTexture(sceneColorCopyHandle) : null;
|
|
881
|
+
// Legacy effects still read resolved MRT textures from DrawContext.
|
|
882
|
+
ctx.shadowMaskTexture = shadowMaskHandle ? rgCtx.getTexture(shadowMaskHandle) : null;
|
|
883
|
+
ctx.HiZTexture = hiZHandle ? rgCtx.getTexture(hiZHandle) : null;
|
|
884
|
+
ctx.SceneRoughnessTexture = sceneRoughnessHandle ? rgCtx.getTexture(sceneRoughnessHandle) : null;
|
|
885
|
+
ctx.SceneNormalTexture = sceneNormalHandle ? rgCtx.getTexture(sceneNormalHandle) : null;
|
|
886
|
+
ctx.SSSProfileTexture = sssProfileHandle ? rgCtx.getTexture(sssProfileHandle) : null;
|
|
887
|
+
ctx.SSSParamTexture = sssParamHandle ? rgCtx.getTexture(sssParamHandle) : null;
|
|
888
|
+
ctx.SSSDiffuseTexture = sssDiffuseHandle ? rgCtx.getTexture(sssDiffuseHandle) : null;
|
|
889
|
+
ctx.SSSTransmissionTexture = sssTransmissionHandle ? rgCtx.getTexture(sssTransmissionHandle) : null;
|
|
890
|
+
ctx.SkinSSSTexture = skinSSSHandle ? rgCtx.getTexture(skinSSSHandle) : null;
|
|
891
|
+
const renderLightPass = ()=>renderOpaqueScenePass(frame, sceneColorTex, sceneColorCopyTex, rgCtx, sceneColorFramebufferHandle);
|
|
892
|
+
if (historyManager && lightHistoryReadBindings.length > 0) {
|
|
893
|
+
const ssgiIrradianceBinding = lightHistoryReadBindings.find((binding)=>binding.name === RGHistoryResources.SSGI_IRRADIANCE);
|
|
894
|
+
const ssgiSurfaceBinding = lightHistoryReadBindings.find((binding)=>binding.name === RGHistoryResources.SSGI_SURFACE);
|
|
895
|
+
ctx.SSGIIrradianceHistoryTexture = ssgiIrradianceBinding ? rgCtx.getTexture(ssgiIrradianceBinding.handle) : null;
|
|
896
|
+
ctx.SSGISurfaceHistoryTexture = ssgiSurfaceBinding ? rgCtx.getTexture(ssgiSurfaceBinding.handle) : null;
|
|
897
|
+
historyManager.beginReadScope(lightHistoryReadBindings.map((binding)=>({
|
|
898
|
+
name: binding.name,
|
|
899
|
+
texture: rgCtx.getTexture(binding.handle)
|
|
900
|
+
})));
|
|
901
|
+
try {
|
|
902
|
+
renderLightPass();
|
|
903
|
+
} finally{
|
|
904
|
+
historyManager.endReadScope();
|
|
905
|
+
ctx.SSGIIrradianceHistoryTexture = null;
|
|
906
|
+
ctx.SSGISurfaceHistoryTexture = null;
|
|
907
|
+
}
|
|
908
|
+
} else {
|
|
731
909
|
renderLightPass();
|
|
732
|
-
} finally{
|
|
733
|
-
historyManager.endReadScope();
|
|
734
910
|
}
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
|
|
911
|
+
});
|
|
912
|
+
return {
|
|
913
|
+
sceneColorHandle,
|
|
914
|
+
sceneColorFramebufferHandle,
|
|
915
|
+
sceneRoughnessHandle,
|
|
916
|
+
sceneNormalHandle,
|
|
917
|
+
sssDiffuseHandle,
|
|
918
|
+
sssTransmissionHandle,
|
|
919
|
+
skinSSSHandle
|
|
920
|
+
};
|
|
738
921
|
});
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
ssrNormalHandle,
|
|
745
|
-
sssDiffuseHandle,
|
|
746
|
-
sssTransmissionHandle,
|
|
747
|
-
skinSSSHandle
|
|
748
|
-
};
|
|
749
|
-
});
|
|
750
|
-
// Register the LightPass MRT products so effects can look them up by name.
|
|
751
|
-
if (lightPassResult.ssrRoughnessHandle) {
|
|
752
|
-
blackboard.set(FrameResources.SSRRoughness, lightPassResult.ssrRoughnessHandle);
|
|
753
|
-
}
|
|
754
|
-
if (lightPassResult.ssrNormalHandle) {
|
|
755
|
-
blackboard.set(FrameResources.SSRNormal, lightPassResult.ssrNormalHandle);
|
|
756
|
-
} else if (sssProfileResult?.normalHandle) {
|
|
757
|
-
blackboard.set(FrameResources.SSRNormal, sssProfileResult.normalHandle);
|
|
758
|
-
}
|
|
759
|
-
if (lightPassResult.sssDiffuseHandle) {
|
|
760
|
-
blackboard.set(FrameResources.SSSDiffuse, lightPassResult.sssDiffuseHandle);
|
|
761
|
-
}
|
|
762
|
-
if (lightPassResult.sssTransmissionHandle) {
|
|
763
|
-
blackboard.set(FrameResources.SSSTransmission, lightPassResult.sssTransmissionHandle);
|
|
764
|
-
}
|
|
765
|
-
if (lightPassResult.skinSSSHandle) {
|
|
766
|
-
blackboard.set(FrameResources.SkinSSS, lightPassResult.skinSSSHandle);
|
|
767
|
-
}
|
|
768
|
-
// 7d. Opaque-layer post effects (SAO/SSR/SSS/SkinSSS). They read the opaque
|
|
769
|
-
// scene color and must complete before transparent geometry renders on top
|
|
770
|
-
// of their output. Never direct-write: the chain output becomes the
|
|
771
|
-
// transparent pass's render target. In final-framebuffer-as-intermediate
|
|
772
|
-
// mode the scene color handle is the LightPass's backbuffer write version,
|
|
773
|
-
// so the data flow is real either way — no keep-alive reads needed.
|
|
774
|
-
const opaqueChainInput = lightPassResult.sceneColorHandle;
|
|
775
|
-
// Data dependencies for every effect pass: frame textures the effects sample
|
|
776
|
-
// through DrawContext fields (linear depth, HiZ, scene color copy, SSS MRT
|
|
777
|
-
// outputs) rather than through declared require* hooks.
|
|
778
|
-
const opaqueChainDeps = [
|
|
779
|
-
depthHandle
|
|
780
|
-
];
|
|
781
|
-
if (hiZHandle) {
|
|
782
|
-
opaqueChainDeps.push(hiZHandle);
|
|
783
|
-
}
|
|
784
|
-
if (lightPassResult.sceneColorFramebufferHandle) {
|
|
785
|
-
opaqueChainDeps.push(lightPassResult.sceneColorFramebufferHandle);
|
|
786
|
-
}
|
|
787
|
-
if (grabResult) {
|
|
788
|
-
opaqueChainDeps.push(grabResult.copyHandle);
|
|
789
|
-
}
|
|
790
|
-
if (sssProfileResult) {
|
|
791
|
-
opaqueChainDeps.push(sssProfileResult.profileHandle, sssProfileResult.paramHandle);
|
|
792
|
-
if (sssProfileResult.normalHandle) {
|
|
793
|
-
opaqueChainDeps.push(sssProfileResult.normalHandle);
|
|
922
|
+
const lightPassResult = opaquePassResult;
|
|
923
|
+
fg.state.lightPass = lightPassResult;
|
|
924
|
+
blackboard.set(FrameResources.SceneColor, lightPassResult.sceneColorHandle);
|
|
925
|
+
if (lightPassResult.sceneRoughnessHandle) {
|
|
926
|
+
blackboard.set(FrameResources.SceneRoughness, lightPassResult.sceneRoughnessHandle);
|
|
794
927
|
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
lightPassResult.ssrRoughnessHandle,
|
|
798
|
-
lightPassResult.ssrNormalHandle,
|
|
799
|
-
lightPassResult.sssDiffuseHandle,
|
|
800
|
-
lightPassResult.sssTransmissionHandle,
|
|
801
|
-
lightPassResult.skinSSSHandle
|
|
802
|
-
]){
|
|
803
|
-
if (handle) {
|
|
804
|
-
opaqueChainDeps.push(handle);
|
|
928
|
+
if (lightPassResult.sceneNormalHandle) {
|
|
929
|
+
blackboard.set(FrameResources.SceneNormal, lightPassResult.sceneNormalHandle);
|
|
805
930
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
graph,
|
|
809
|
-
ctx,
|
|
810
|
-
layer: PostEffectLayer.opaque,
|
|
811
|
-
blackboard,
|
|
812
|
-
input: opaqueChainInput,
|
|
813
|
-
finalOutput: null,
|
|
814
|
-
sceneDepthAttachment: renderDepthAttachment,
|
|
815
|
-
dependencies: opaqueChainDeps,
|
|
816
|
-
historyReads: lightHistoryReadBindings,
|
|
817
|
-
history: historyManager
|
|
818
|
-
}) : {
|
|
819
|
-
color: opaqueChainInput,
|
|
820
|
-
wroteFinal: false
|
|
821
|
-
};
|
|
822
|
-
const opaqueChainRan = opaqueChainResult.color !== opaqueChainInput;
|
|
823
|
-
// 7e. Transparent scene geometry (transmission/transparent lists + OIT).
|
|
824
|
-
// Renders on top of the opaque-chain output; graph-wise an in-place write
|
|
825
|
-
// producing a new version of the current scene color.
|
|
826
|
-
const sceneColorHandle = graph.addPass('TransparentPass', (builder)=>{
|
|
827
|
-
builder.read(depthHandle);
|
|
828
|
-
builder.read(depthPassResult.depthFramebufferHandle);
|
|
829
|
-
if (hiZHandle) {
|
|
830
|
-
// Transparent-phase materials may ray-march HiZ (e.g. water SSR)
|
|
831
|
-
builder.read(hiZHandle);
|
|
931
|
+
if (lightPassResult.sssDiffuseHandle) {
|
|
932
|
+
blackboard.set(FrameResources.SSSDiffuse, lightPassResult.sssDiffuseHandle);
|
|
832
933
|
}
|
|
833
|
-
if (lightPassResult.
|
|
834
|
-
|
|
934
|
+
if (lightPassResult.sssTransmissionHandle) {
|
|
935
|
+
blackboard.set(FrameResources.SSSTransmission, lightPassResult.sssTransmissionHandle);
|
|
835
936
|
}
|
|
836
|
-
if (lightPassResult.
|
|
837
|
-
|
|
937
|
+
if (lightPassResult.skinSSSHandle) {
|
|
938
|
+
blackboard.set(FrameResources.SkinSSS, lightPassResult.skinSSSHandle);
|
|
838
939
|
}
|
|
839
|
-
builder.read(opaqueChainResult.color);
|
|
840
|
-
const out = builder.write(opaqueChainResult.color);
|
|
841
|
-
builder.setExecute((rgCtx)=>{
|
|
842
|
-
renderTransparentScenePass(frame, rgCtx, opaqueChainRan ? opaqueChainResult.color : null, lightPassResult.sceneColorFramebufferHandle);
|
|
843
|
-
});
|
|
844
|
-
return out;
|
|
845
|
-
});
|
|
846
|
-
blackboard.set(FrameResources.SceneColor, sceneColorHandle);
|
|
847
|
-
if (lightPassResult.sceneColorCopyHandle) {
|
|
848
|
-
blackboard.set(FrameResources.SceneColorCopy, lightPassResult.sceneColorCopyHandle);
|
|
849
940
|
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
graph,
|
|
880
|
-
ctx,
|
|
881
|
-
layer: PostEffectLayer.transparent,
|
|
882
|
-
blackboard,
|
|
883
|
-
input: chainInput,
|
|
884
|
-
finalOutput: endLayerHasEffects ? null : finalOutput,
|
|
885
|
-
inputResidesInFinalTarget: !!backbufferResidentHandle,
|
|
886
|
-
sceneDepthAttachment: renderDepthAttachment,
|
|
887
|
-
dependencies: chainDependencies,
|
|
888
|
-
history: historyManager
|
|
889
|
-
}) : {
|
|
890
|
-
color: chainInput,
|
|
891
|
-
wroteFinal: false
|
|
892
|
-
};
|
|
893
|
-
// 8b. Transmission depth pass (optional). Mutates the linear depth texture;
|
|
894
|
-
// the mutation is modeled as a graph write: the WAR hazard orders this pass
|
|
895
|
-
// after every pre-transmission depth reader (the transparent-layer chain),
|
|
896
|
-
// and re-registering the post-write version in the blackboard gives
|
|
897
|
-
// end-layer effects (TAA) a real data dependency on the transmission depth.
|
|
898
|
-
let transmissionDepthToken;
|
|
899
|
-
if (options.needSceneColor && !options.needsTransmissionDepthForSSR) {
|
|
900
|
-
const transmissionDepthResult = graph.addPass('TransmissionDepth', (builder)=>{
|
|
941
|
+
};
|
|
942
|
+
/** @internal */ const SkyPassModule = {
|
|
943
|
+
type: 'SkyPass',
|
|
944
|
+
reads: [
|
|
945
|
+
{
|
|
946
|
+
resource: FrameResources.SceneColor,
|
|
947
|
+
version: 'current'
|
|
948
|
+
}
|
|
949
|
+
],
|
|
950
|
+
writes: [
|
|
951
|
+
FrameResources.SceneColor,
|
|
952
|
+
FrameResources.SceneColorNoFog
|
|
953
|
+
],
|
|
954
|
+
prepare: ()=>({
|
|
955
|
+
enabled: true
|
|
956
|
+
}),
|
|
957
|
+
setup (fg) {
|
|
958
|
+
const { graph, ctx, frame, blackboard, options } = fg;
|
|
959
|
+
const depthPassResult = requireBuildState(fg, 'depth', 'DepthPrepass', 'SkyPass');
|
|
960
|
+
const lightPassResult = requireBuildState(fg, 'lightPass', 'LightPass', 'SkyPass');
|
|
961
|
+
const sceneColorCopyHandle = blackboard.get(FrameResources.SceneColorCopy);
|
|
962
|
+
const sceneColorHandle = blackboard.expect(FrameResources.SceneColor);
|
|
963
|
+
// Screen-space passes must not read fog as surface radiance. Snapshot the lit
|
|
964
|
+
// scene with sky but before fog, and only when fog is actually present and a
|
|
965
|
+
// consumer exists, so fog-free scenes allocate nothing extra. The refraction
|
|
966
|
+
// background path already baked sky and fog into the copy, so no fog-free
|
|
967
|
+
// version can be recovered there and consumers keep their existing input.
|
|
968
|
+
const captureNoFog = !sceneColorCopyHandle && (options.ssgi || options.ssr) && options.fogPresents;
|
|
969
|
+
const skyPassResult = graph.addPass('SkyPass', (builder)=>{
|
|
901
970
|
builder.read(sceneColorHandle);
|
|
902
|
-
if (transparentChainResult.color !== sceneColorHandle) {
|
|
903
|
-
builder.read(transparentChainResult.color);
|
|
904
|
-
}
|
|
905
|
-
builder.read(depthHandle);
|
|
906
971
|
builder.read(depthPassResult.depthFramebufferHandle);
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
972
|
+
if (lightPassResult.sceneColorFramebufferHandle) {
|
|
973
|
+
builder.read(lightPassResult.sceneColorFramebufferHandle);
|
|
974
|
+
}
|
|
975
|
+
const noFog = captureNoFog ? builder.createTexture({
|
|
976
|
+
format: ctx.colorFormat,
|
|
977
|
+
label: 'sceneColorNoFog',
|
|
978
|
+
allocationKey: 'ForwardPlus.SceneColorNoFog'
|
|
979
|
+
}) : null;
|
|
980
|
+
const out = builder.write(sceneColorHandle);
|
|
910
981
|
builder.setExecute((rgCtx)=>{
|
|
911
|
-
|
|
982
|
+
// The refraction background already contains sky and fog.
|
|
983
|
+
if (!sceneColorCopyHandle) {
|
|
984
|
+
renderSkyScenePass(frame, rgCtx, lightPassResult.sceneColorFramebufferHandle, noFog ? rgCtx.getTexture(noFog) : null);
|
|
985
|
+
}
|
|
912
986
|
});
|
|
913
987
|
return {
|
|
914
|
-
|
|
915
|
-
|
|
988
|
+
color: out,
|
|
989
|
+
noFog
|
|
916
990
|
};
|
|
917
991
|
});
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
992
|
+
lightPassResult.sceneColorHandle = skyPassResult.color;
|
|
993
|
+
blackboard.set(FrameResources.SceneColor, skyPassResult.color);
|
|
994
|
+
if (skyPassResult.noFog) {
|
|
995
|
+
blackboard.set(FrameResources.SceneColorNoFog, skyPassResult.noFog);
|
|
996
|
+
}
|
|
923
997
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
998
|
+
};
|
|
999
|
+
/** @internal */ const CompositeTailModule = {
|
|
1000
|
+
type: 'CompositeTail',
|
|
1001
|
+
writes: [
|
|
1002
|
+
FrameResources.SceneColor,
|
|
1003
|
+
FrameResources.LinearDepth,
|
|
1004
|
+
FrameResources.PresentedColor
|
|
1005
|
+
],
|
|
1006
|
+
prepare: ()=>({
|
|
1007
|
+
enabled: true
|
|
1008
|
+
}),
|
|
1009
|
+
setup (fg) {
|
|
1010
|
+
const { graph, ctx, frame, blackboard, options, backbuffer } = fg;
|
|
1011
|
+
const depthPassResult = requireBuildState(fg, 'depth', 'DepthPrepass', 'CompositeTail');
|
|
1012
|
+
const hiZHandle = blackboard.get(FrameResources.HiZ);
|
|
1013
|
+
const sceneColorCopyHandle = blackboard.get(FrameResources.SceneColorCopy);
|
|
1014
|
+
const lightPassResult = requireBuildState(fg, 'lightPass', 'LightPass', 'CompositeTail');
|
|
1015
|
+
const renderDepthAttachment = fg.state.renderDepthAttachment;
|
|
1016
|
+
const useFinalFramebufferAsIntermediate = fg.state.useFinalFramebufferAsIntermediate;
|
|
1017
|
+
const lightHistoryReadBindings = fg.state.lightHistoryReadBindings;
|
|
1018
|
+
const historyManager = fg.history;
|
|
1019
|
+
// Opaque effects finish before transparent geometry uses their output.
|
|
1020
|
+
const opaqueChainInput = blackboard.expect(FrameResources.SceneColor);
|
|
1021
|
+
// Include textures sampled indirectly through DrawContext.
|
|
1022
|
+
const opaqueChainDeps = [
|
|
1023
|
+
blackboard.expect(FrameResources.LinearDepth)
|
|
1024
|
+
];
|
|
1025
|
+
if (hiZHandle) {
|
|
1026
|
+
opaqueChainDeps.push(hiZHandle);
|
|
1027
|
+
}
|
|
1028
|
+
if (lightPassResult.sceneColorFramebufferHandle) {
|
|
1029
|
+
opaqueChainDeps.push(lightPassResult.sceneColorFramebufferHandle);
|
|
1030
|
+
}
|
|
1031
|
+
if (sceneColorCopyHandle) {
|
|
1032
|
+
opaqueChainDeps.push(sceneColorCopyHandle);
|
|
1033
|
+
}
|
|
1034
|
+
for (const handle of [
|
|
1035
|
+
blackboard.get(FrameResources.SSSProfile),
|
|
1036
|
+
blackboard.get(FrameResources.SSSParam),
|
|
1037
|
+
blackboard.get(FrameResources.SceneRoughness),
|
|
1038
|
+
blackboard.get(FrameResources.SceneNormal),
|
|
1039
|
+
blackboard.get(FrameResources.SSSDiffuse),
|
|
1040
|
+
blackboard.get(FrameResources.SSSTransmission),
|
|
1041
|
+
blackboard.get(FrameResources.SkinSSS)
|
|
1042
|
+
]){
|
|
1043
|
+
if (handle) {
|
|
1044
|
+
opaqueChainDeps.push(handle);
|
|
955
1045
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1046
|
+
}
|
|
1047
|
+
const opaqueChainResult = ctx.compositor ? ctx.compositor.buildLayer({
|
|
1048
|
+
graph,
|
|
1049
|
+
ctx,
|
|
1050
|
+
layer: PostEffectLayer.opaque,
|
|
1051
|
+
blackboard,
|
|
1052
|
+
input: opaqueChainInput,
|
|
1053
|
+
finalOutput: null,
|
|
1054
|
+
sceneDepthAttachment: renderDepthAttachment,
|
|
1055
|
+
dependencies: opaqueChainDeps,
|
|
1056
|
+
historyReads: lightHistoryReadBindings,
|
|
1057
|
+
history: historyManager
|
|
1058
|
+
}) : {
|
|
1059
|
+
color: opaqueChainInput,
|
|
1060
|
+
wroteFinal: false
|
|
1061
|
+
};
|
|
1062
|
+
const opaqueChainRan = opaqueChainResult.color !== opaqueChainInput;
|
|
1063
|
+
// Transparent geometry writes a new version of the opaque-chain output.
|
|
1064
|
+
const sceneColorHandle = graph.addPass('TransparentPass', (builder)=>{
|
|
1065
|
+
builder.read(blackboard.expect(FrameResources.LinearDepth));
|
|
1066
|
+
builder.read(depthPassResult.depthFramebufferHandle);
|
|
1067
|
+
if (hiZHandle) {
|
|
1068
|
+
// Transparent materials may ray-march HiZ.
|
|
1069
|
+
builder.read(hiZHandle);
|
|
1070
|
+
}
|
|
1071
|
+
if (lightPassResult.sceneColorFramebufferHandle) {
|
|
1072
|
+
builder.read(lightPassResult.sceneColorFramebufferHandle);
|
|
966
1073
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1074
|
+
if (sceneColorCopyHandle) {
|
|
1075
|
+
builder.read(sceneColorCopyHandle);
|
|
1076
|
+
}
|
|
1077
|
+
builder.read(opaqueChainResult.color);
|
|
1078
|
+
const out = builder.write(opaqueChainResult.color);
|
|
971
1079
|
builder.setExecute((rgCtx)=>{
|
|
972
|
-
|
|
973
|
-
if (sourceTex) {
|
|
974
|
-
const blitter = new CopyBlitter();
|
|
975
|
-
blitter.srgbOut = !ctx.finalFramebuffer;
|
|
976
|
-
blitter.blit(sourceTex, ctx.finalFramebuffer ?? null, fetchSampler('clamp_nearest_nomip'));
|
|
977
|
-
}
|
|
978
|
-
finishFrame(frame);
|
|
1080
|
+
renderTransparentScenePass(frame, rgCtx, opaqueChainRan ? opaqueChainResult.color : null, lightPassResult.sceneColorFramebufferHandle);
|
|
979
1081
|
});
|
|
980
|
-
return
|
|
1082
|
+
return out;
|
|
981
1083
|
});
|
|
1084
|
+
blackboard.set(FrameResources.SceneColor, sceneColorHandle);
|
|
1085
|
+
const chainInput = sceneColorHandle;
|
|
1086
|
+
// Track whether the chain input still resides in the final target.
|
|
1087
|
+
const backbufferResidentHandle = useFinalFramebufferAsIntermediate ? sceneColorHandle : null;
|
|
1088
|
+
const chainDependencies = [];
|
|
1089
|
+
const finalOutput = {
|
|
1090
|
+
handle: backbuffer,
|
|
1091
|
+
isScreen: !ctx.finalFramebuffer
|
|
1092
|
+
};
|
|
1093
|
+
const endLayerHasEffects = !!ctx.compositor?.layerHasEnabledEffect(PostEffectLayer.end);
|
|
1094
|
+
// Transparent-layer effects read depth before its transmission mutation.
|
|
1095
|
+
const transparentChainResult = ctx.compositor ? ctx.compositor.buildLayer({
|
|
1096
|
+
graph,
|
|
1097
|
+
ctx,
|
|
1098
|
+
layer: PostEffectLayer.transparent,
|
|
1099
|
+
blackboard,
|
|
1100
|
+
input: chainInput,
|
|
1101
|
+
finalOutput: endLayerHasEffects ? null : finalOutput,
|
|
1102
|
+
inputResidesInFinalTarget: !!backbufferResidentHandle,
|
|
1103
|
+
sceneDepthAttachment: renderDepthAttachment,
|
|
1104
|
+
dependencies: chainDependencies,
|
|
1105
|
+
history: historyManager
|
|
1106
|
+
}) : {
|
|
1107
|
+
color: chainInput,
|
|
1108
|
+
wroteFinal: false
|
|
1109
|
+
};
|
|
1110
|
+
// WAR orders this depth mutation after pre-transmission readers.
|
|
1111
|
+
let transmissionDepthToken;
|
|
1112
|
+
if (options.needSceneColor && !options.needsTransmissionDepthForSSR) {
|
|
1113
|
+
const transmissionDepthResult = graph.addPass('TransmissionDepth', (builder)=>{
|
|
1114
|
+
const currentDepth = blackboard.expect(FrameResources.LinearDepth);
|
|
1115
|
+
builder.read(sceneColorHandle);
|
|
1116
|
+
if (transparentChainResult.color !== sceneColorHandle) {
|
|
1117
|
+
builder.read(transparentChainResult.color);
|
|
1118
|
+
}
|
|
1119
|
+
builder.read(currentDepth);
|
|
1120
|
+
builder.read(depthPassResult.depthFramebufferHandle);
|
|
1121
|
+
const depthOut = builder.write(currentDepth);
|
|
1122
|
+
const done = builder.createToken('TransmissionDepthDone');
|
|
1123
|
+
builder.sideEffect();
|
|
1124
|
+
builder.setExecute((rgCtx)=>{
|
|
1125
|
+
renderTransmissionDepthPass(frame, rgCtx);
|
|
1126
|
+
});
|
|
1127
|
+
return {
|
|
1128
|
+
done,
|
|
1129
|
+
depthOut
|
|
1130
|
+
};
|
|
1131
|
+
});
|
|
1132
|
+
transmissionDepthToken = transmissionDepthResult.done;
|
|
1133
|
+
blackboard.set(FrameResources.LinearDepth, transmissionDepthResult.depthOut);
|
|
1134
|
+
}
|
|
1135
|
+
const endChainDependencies = transmissionDepthToken ? [
|
|
1136
|
+
...chainDependencies,
|
|
1137
|
+
transmissionDepthToken
|
|
1138
|
+
] : chainDependencies;
|
|
1139
|
+
const chainResult = ctx.compositor ? ctx.compositor.buildLayer({
|
|
1140
|
+
graph,
|
|
1141
|
+
ctx,
|
|
1142
|
+
layer: PostEffectLayer.end,
|
|
1143
|
+
blackboard,
|
|
1144
|
+
input: transparentChainResult.color,
|
|
1145
|
+
finalOutput,
|
|
1146
|
+
inputResidesInFinalTarget: !!backbufferResidentHandle && transparentChainResult.color === chainInput,
|
|
1147
|
+
sceneDepthAttachment: renderDepthAttachment,
|
|
1148
|
+
dependencies: endChainDependencies,
|
|
1149
|
+
history: historyManager
|
|
1150
|
+
}) : {
|
|
1151
|
+
color: transparentChainResult.color,
|
|
1152
|
+
wroteFinal: false
|
|
1153
|
+
};
|
|
1154
|
+
const finalWroteFinal = chainResult.wroteFinal || transparentChainResult.wroteFinal;
|
|
1155
|
+
let presentedBackbuffer;
|
|
1156
|
+
if (finalWroteFinal) {
|
|
1157
|
+
presentedBackbuffer = chainResult.color;
|
|
1158
|
+
} else {
|
|
1159
|
+
presentedBackbuffer = graph.addPass('Blit', (builder)=>{
|
|
1160
|
+
builder.read(chainResult.color);
|
|
1161
|
+
for (const dep of endChainDependencies){
|
|
1162
|
+
builder.read(dep);
|
|
1163
|
+
}
|
|
1164
|
+
const outputBackbuffer = builder.write(backbuffer);
|
|
1165
|
+
// Skip copies when the output already resides in the final target.
|
|
1166
|
+
const needsBlit = chainResult.color !== backbufferResidentHandle;
|
|
1167
|
+
builder.setExecute((rgCtx)=>{
|
|
1168
|
+
const sourceTex = needsBlit ? rgCtx.getTexture(chainResult.color) : null;
|
|
1169
|
+
if (sourceTex) {
|
|
1170
|
+
const blitter = new CopyBlitter();
|
|
1171
|
+
blitter.srgbOut = !ctx.finalFramebuffer;
|
|
1172
|
+
blitter.blit(sourceTex, ctx.finalFramebuffer ?? null, fetchSampler('clamp_nearest_nomip'));
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
return outputBackbuffer;
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
fg.state.presentedBackbuffer = presentedBackbuffer;
|
|
1179
|
+
// Downstream modules may replace this sink registration.
|
|
1180
|
+
blackboard.set(FrameResources.PresentedColor, presentedBackbuffer);
|
|
982
1181
|
}
|
|
1182
|
+
};
|
|
1183
|
+
/** Built-in Forward+ modules addressable by pipeline anchors. @public */ const ForwardPlusModules = {
|
|
1184
|
+
SkyUpdate: SkyUpdateModule,
|
|
1185
|
+
ClusterLights: ClusterLightsModule,
|
|
1186
|
+
GPUPicking: GPUPickingModule,
|
|
1187
|
+
ShadowMaps: ShadowMapsModule,
|
|
1188
|
+
DepthPrepass: DepthPrepassModule,
|
|
1189
|
+
ShadowMask: ShadowMaskModule,
|
|
1190
|
+
TransmissionDepthForSSR: TransmissionDepthForSSRModule,
|
|
1191
|
+
HiZ: HiZModule,
|
|
1192
|
+
SSSProfile: SSSProfileModule,
|
|
1193
|
+
SceneColorGrab: SceneColorGrabModule,
|
|
1194
|
+
LightPass: LightPassModule,
|
|
1195
|
+
SkyPass: SkyPassModule,
|
|
1196
|
+
CompositeTail: CompositeTailModule
|
|
1197
|
+
};
|
|
1198
|
+
/** The default module order assembled by {@link createForwardPlusPipeline}. */ const DEFAULT_FORWARD_PLUS_MODULES = [
|
|
1199
|
+
SkyUpdateModule,
|
|
1200
|
+
ClusterLightsModule,
|
|
1201
|
+
GPUPickingModule,
|
|
1202
|
+
ShadowMapsModule,
|
|
1203
|
+
DepthPrepassModule,
|
|
1204
|
+
ShadowMaskModule,
|
|
1205
|
+
TransmissionDepthForSSRModule,
|
|
1206
|
+
HiZModule,
|
|
1207
|
+
SSSProfileModule,
|
|
1208
|
+
SceneColorGrabModule,
|
|
1209
|
+
LightPassModule,
|
|
1210
|
+
SkyPassModule,
|
|
1211
|
+
CompositeTailModule
|
|
1212
|
+
];
|
|
1213
|
+
/** @internal */ let _defaultForwardPlusPipeline = null;
|
|
1214
|
+
/** Create an independent pipeline with the built-in Forward+ modules. @public */ function createForwardPlusPipeline() {
|
|
1215
|
+
return new RenderPipeline(DEFAULT_FORWARD_PLUS_MODULES);
|
|
1216
|
+
}
|
|
1217
|
+
/** Return the shared default pipeline. Mutations affect cameras using it. @public */ function getDefaultForwardPlusPipeline() {
|
|
1218
|
+
if (!_defaultForwardPlusPipeline) {
|
|
1219
|
+
_defaultForwardPlusPipeline = createForwardPlusPipeline();
|
|
1220
|
+
}
|
|
1221
|
+
return _defaultForwardPlusPipeline;
|
|
1222
|
+
}
|
|
1223
|
+
/** Build the Forward+ render graph and return its backbuffer output. @public */ function buildForwardPlusGraph(graph, ctx, renderQueue, options) {
|
|
1224
|
+
return buildForwardPlusGraphInternal(graph, ctx, renderQueue, options).backbuffer;
|
|
1225
|
+
}
|
|
1226
|
+
function buildForwardPlusGraphInternal(graph, ctx, renderQueue, options) {
|
|
1227
|
+
const backbuffer = graph.importTexture('backbuffer');
|
|
1228
|
+
// Irradiance, moments and surface history require renderable half-float
|
|
1229
|
+
// targets. Keep ordinary IBL active on devices that cannot provide them.
|
|
1230
|
+
options.ssgi &&= supportsSSGIRenderTargets(ctx);
|
|
1231
|
+
ctx.SSS = !!options.sss;
|
|
1232
|
+
ctx.SSGI = !!options.ssgi;
|
|
1233
|
+
ctx.SSGIIrradianceHistoryTexture = null;
|
|
1234
|
+
ctx.SSGISurfaceHistoryTexture = null;
|
|
1235
|
+
ctx.SkinSSSTexture = null;
|
|
1236
|
+
// ShadowMask sets this only when it produces a texture.
|
|
1237
|
+
ctx.shadowMaskTexture = null;
|
|
1238
|
+
const blackboard = new RGBlackboard();
|
|
1239
|
+
const frame = {
|
|
1240
|
+
ctx,
|
|
1241
|
+
renderQueue,
|
|
1242
|
+
depthFramebuffer: null,
|
|
1243
|
+
sunLightColor: null,
|
|
1244
|
+
options,
|
|
1245
|
+
renderQueueDisposed: false,
|
|
1246
|
+
clusteredLightReleased: false,
|
|
1247
|
+
sunLightRestored: false
|
|
1248
|
+
};
|
|
1249
|
+
const ordering = new OrderingScope();
|
|
1250
|
+
const fg = {
|
|
1251
|
+
graph,
|
|
1252
|
+
ctx,
|
|
1253
|
+
finalFramebuffer: ctx.finalFramebuffer,
|
|
1254
|
+
renderQueue,
|
|
1255
|
+
blackboard,
|
|
1256
|
+
frame,
|
|
1257
|
+
history: ctx.camera?.getHistoryResourceManager?.() ?? null,
|
|
1258
|
+
options,
|
|
1259
|
+
ordering,
|
|
1260
|
+
backbuffer,
|
|
1261
|
+
state: {
|
|
1262
|
+
renderDepthAttachment: null,
|
|
1263
|
+
useFinalFramebufferAsIntermediate: false,
|
|
1264
|
+
lightHistoryReadBindings: []
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
const pipeline = ctx.camera?.renderPipeline ?? getDefaultForwardPlusPipeline();
|
|
1268
|
+
const requirements = ctx.compositor?.collectRequirements(ctx) ?? {};
|
|
1269
|
+
mergeFrameResourceRequirements(requirements, pipeline.collectRequirements(fg));
|
|
1270
|
+
resolveFrameResourceRequirements(ctx, options, requirements);
|
|
1271
|
+
pipeline.build(fg);
|
|
1272
|
+
validateProducedFrameResources(blackboard, options, renderQueue);
|
|
1273
|
+
const presented = blackboard.get(FrameResources.PresentedColor) ?? fg.state.presentedBackbuffer;
|
|
1274
|
+
const depth = fg.state.depth;
|
|
1275
|
+
const externalDepthImport = depth?.externalDepthAttachmentHandle && depth.externalDepthAttachment ? {
|
|
1276
|
+
handle: depth.externalDepthAttachmentHandle,
|
|
1277
|
+
texture: depth.externalDepthAttachment
|
|
1278
|
+
} : undefined;
|
|
983
1279
|
return {
|
|
984
|
-
backbuffer:
|
|
985
|
-
frame
|
|
1280
|
+
backbuffer: presented,
|
|
1281
|
+
frame,
|
|
1282
|
+
externalDepthImport
|
|
986
1283
|
};
|
|
987
1284
|
}
|
|
988
|
-
// ─── Pass Implementation Helpers ────────────────────────────────────
|
|
989
|
-
// These wrap the existing SceneRenderer static methods, adapted to work
|
|
990
|
-
// with the FrameState pattern. They contain the same logic as the
|
|
991
|
-
// original methods but read/write through FrameState.
|
|
992
1285
|
/** @internal */ function renderShadowMaps(ctx, lights) {
|
|
993
1286
|
ctx.renderPass = _shadowMapPass;
|
|
994
1287
|
ctx.device.pushDeviceStates();
|
|
@@ -1021,20 +1314,17 @@ function renderForwardSSSProfile(frame, profileFramebuffer, profileTexture, para
|
|
|
1021
1314
|
const savedCommandBufferReuse = ctx.camera.commandBufferReuse;
|
|
1022
1315
|
const savedProfileTexture = ctx.SSSProfileTexture;
|
|
1023
1316
|
const savedParamTexture = ctx.SSSParamTexture;
|
|
1024
|
-
const savedNormalTexture = ctx.
|
|
1317
|
+
const savedNormalTexture = ctx.SceneNormalTexture;
|
|
1025
1318
|
let profileFlags = MaterialVaryingFlags.SSS_STORE_PROFILE;
|
|
1026
|
-
if (normalTexture) {
|
|
1027
|
-
profileFlags |= MaterialVaryingFlags.SSS_STORE_NORMAL;
|
|
1028
|
-
}
|
|
1029
1319
|
device.pushDeviceStates();
|
|
1030
1320
|
try {
|
|
1031
1321
|
device.setFramebuffer(profileFramebuffer);
|
|
1032
1322
|
ctx.SSSProfileTexture = profileTexture;
|
|
1033
1323
|
ctx.SSSParamTexture = paramTexture;
|
|
1034
|
-
ctx.
|
|
1324
|
+
ctx.SceneNormalTexture = normalTexture;
|
|
1035
1325
|
ctx.compositor = null;
|
|
1036
1326
|
ctx.camera.commandBufferReuse = false;
|
|
1037
|
-
ctx.materialFlags = ctx.materialFlags & ~(MaterialVaryingFlags.
|
|
1327
|
+
ctx.materialFlags = ctx.materialFlags & ~(MaterialVaryingFlags.SCENE_STORE_ROUGHNESS | MaterialVaryingFlags.SSS_STORE_PROFILE | MaterialVaryingFlags.SCENE_STORE_NORMAL | MaterialVaryingFlags.SSS_STORE_DIFFUSE | MaterialVaryingFlags.SSS_STORE_TRANSMISSION | MaterialVaryingFlags.SKIN_SSS_STORE) | profileFlags;
|
|
1038
1328
|
_scenePass.transmission = false;
|
|
1039
1329
|
_scenePass.renderOpaque = true;
|
|
1040
1330
|
_scenePass.renderTransparent = false;
|
|
@@ -1054,14 +1344,13 @@ function renderForwardSSSProfile(frame, profileFramebuffer, profileTexture, para
|
|
|
1054
1344
|
ctx.compositor = savedCompositor;
|
|
1055
1345
|
ctx.SSSProfileTexture = savedProfileTexture;
|
|
1056
1346
|
ctx.SSSParamTexture = savedParamTexture;
|
|
1057
|
-
ctx.
|
|
1347
|
+
ctx.SceneNormalTexture = savedNormalTexture;
|
|
1058
1348
|
device.popDeviceStates();
|
|
1059
1349
|
sssRenderQueue.dispose();
|
|
1060
1350
|
}
|
|
1061
1351
|
}
|
|
1062
1352
|
function releaseIntermediateFramebuffer(frame) {
|
|
1063
|
-
//
|
|
1064
|
-
// push/pop their own framebuffer bindings); only the context field remains.
|
|
1353
|
+
// Each pass owns device state; only clear the shared context field.
|
|
1065
1354
|
frame.ctx.intermediateFramebuffer = null;
|
|
1066
1355
|
}
|
|
1067
1356
|
function releaseDepthFramebuffer(frame) {
|
|
@@ -1087,6 +1376,13 @@ function restoreSunLight(frame) {
|
|
|
1087
1376
|
}
|
|
1088
1377
|
}
|
|
1089
1378
|
function cleanupFrame(frame) {
|
|
1379
|
+
const { ctx } = frame;
|
|
1380
|
+
ctx.materialFlags &= ~MaterialVaryingFlags.SCENE_STORE_ROUGHNESS;
|
|
1381
|
+
ctx.materialFlags &= ~MaterialVaryingFlags.SSS_STORE_PROFILE;
|
|
1382
|
+
ctx.materialFlags &= ~MaterialVaryingFlags.SSS_STORE_DIFFUSE;
|
|
1383
|
+
ctx.materialFlags &= ~MaterialVaryingFlags.SCENE_STORE_NORMAL;
|
|
1384
|
+
ctx.materialFlags &= ~MaterialVaryingFlags.SSS_STORE_TRANSMISSION;
|
|
1385
|
+
ctx.materialFlags &= ~MaterialVaryingFlags.SKIN_SSS_STORE;
|
|
1090
1386
|
releaseIntermediateFramebuffer(frame);
|
|
1091
1387
|
releaseDepthFramebuffer(frame);
|
|
1092
1388
|
releaseClusteredLight(frame);
|
|
@@ -1098,10 +1394,10 @@ function cleanupFrame(frame) {
|
|
|
1098
1394
|
const renderQueue = frame.renderQueue;
|
|
1099
1395
|
const transmission = transmissionOverride ?? !!existingDepthFb;
|
|
1100
1396
|
let depthFramebuffer = existingDepthFb;
|
|
1397
|
+
// Current callers must provide the graph-managed prepass framebuffer.
|
|
1398
|
+
console.assert(!!existingDepthFb, 'renderSceneDepth: called without an existing depth framebuffer; the ' + 'self-allocating fallback path is untested in the forward+ pipeline.');
|
|
1101
1399
|
if (!depthFramebuffer) {
|
|
1102
|
-
// Use RenderGraph-allocated textures if provided
|
|
1103
1400
|
{
|
|
1104
|
-
// Allocate through RenderGraph so framebuffer lifetime is owned by the executor.
|
|
1105
1401
|
const format = ctx.device.type === 'webgl' ? ctx.SSRCalcThickness ? 'rgba16f' : 'rgba8unorm' : ctx.SSRCalcThickness ? 'rg32f' : 'r32f';
|
|
1106
1402
|
const mvFormat = 'rgba16f';
|
|
1107
1403
|
if (!ctx.finalFramebuffer) {
|
|
@@ -1151,7 +1447,7 @@ function cleanupFrame(frame) {
|
|
|
1151
1447
|
ctx.device.setFramebuffer(depthFramebuffer);
|
|
1152
1448
|
_depthPass.encodeDepth = depthFramebuffer.getColorAttachments()[0].format === 'rgba8unorm';
|
|
1153
1449
|
_depthPass.clearColor = transmission ? null : _depthPass.encodeDepth ? new Vector4(0, 0, 0, 1) : new Vector4(1, 1, 1, 1);
|
|
1154
|
-
_depthPass.clearDepth = transmission ? null :
|
|
1450
|
+
_depthPass.clearDepth = transmission ? null : DEPTH_CLEAR_VALUE;
|
|
1155
1451
|
_depthPass.clearStencil = null;
|
|
1156
1452
|
_depthPass.transmission = transmission;
|
|
1157
1453
|
if (ctx.SSRCalcThickness && !transmission) {
|
|
@@ -1183,11 +1479,9 @@ function cleanupFrame(frame) {
|
|
|
1183
1479
|
ctx.linearDepthTexture = depthFramebuffer.getColorAttachments()[0];
|
|
1184
1480
|
ctx.depthTexture = depthFramebuffer.getDepthAttachment();
|
|
1185
1481
|
ctx.depthPrepassAttachment = ctx.depthTexture;
|
|
1186
|
-
// HiZ is now built in the dedicated HiZ pass
|
|
1187
1482
|
}
|
|
1188
1483
|
return depthFramebuffer;
|
|
1189
1484
|
}
|
|
1190
|
-
// ─── Sky Motion Vector State ────────────────────────────────────────
|
|
1191
1485
|
let _skyMVProgram = null;
|
|
1192
1486
|
let _skyMVBindGroup = null;
|
|
1193
1487
|
let _skyMVBox = null;
|
|
@@ -1213,7 +1507,7 @@ let _skyMVBox = null;
|
|
|
1213
1507
|
this.$l.prevWorldPos = pb.add(this.$inputs.pos, this.prevCameraPos);
|
|
1214
1508
|
this.$l.clipPos = pb.mul(this.VPMatrix, pb.vec4(this.worldPos, 1));
|
|
1215
1509
|
this.$l.prevClipPos = pb.mul(this.prevVPMatrix, pb.vec4(this.prevWorldPos, 1));
|
|
1216
|
-
this.clipPos.z = this.clipPos.w;
|
|
1510
|
+
this.clipPos.z = ShaderHelper.farthestClipZ(this, this.clipPos.w);
|
|
1217
1511
|
this.$builtins.position = this.clipPos;
|
|
1218
1512
|
this.$outputs.currentPos = this.clipPos;
|
|
1219
1513
|
this.$outputs.prevPos = this.prevClipPos;
|
|
@@ -1246,7 +1540,7 @@ let _skyMVBox = null;
|
|
|
1246
1540
|
device.pushDeviceStates();
|
|
1247
1541
|
device.setProgram(_skyMVProgram);
|
|
1248
1542
|
device.setBindGroup(0, _skyMVBindGroup);
|
|
1249
|
-
device.setRenderStates(AbstractPostEffect.getDefaultRenderState(ctx,
|
|
1543
|
+
device.setRenderStates(AbstractPostEffect.getDefaultRenderState(ctx, DEPTH_COMPARE_DEFAULT));
|
|
1250
1544
|
device.setFramebuffer(fb);
|
|
1251
1545
|
_skyMVBox.draw();
|
|
1252
1546
|
device.popDeviceStates();
|
|
@@ -1256,11 +1550,7 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1256
1550
|
const destination = framebuffer?.getColorAttachment(0) ?? null;
|
|
1257
1551
|
new CopyBlitter().blit(source, destination, fetchSampler('clamp_nearest_nomip'));
|
|
1258
1552
|
}
|
|
1259
|
-
/**
|
|
1260
|
-
* Renders the full scene (no transmission) into the scene-color copy texture
|
|
1261
|
-
* used as refraction background. Runs as its own graph pass before LightPass.
|
|
1262
|
-
* @internal
|
|
1263
|
-
*/ function renderSceneColorGrab(frame, rgCtx, copyHandle, copyFramebufferHandle) {
|
|
1553
|
+
/** Render the refraction background before LightPass. @internal */ function renderSceneColorGrab(frame, rgCtx, copyHandle, copyFramebufferHandle) {
|
|
1264
1554
|
const { ctx, renderQueue } = frame;
|
|
1265
1555
|
const device = ctx.device;
|
|
1266
1556
|
const depthTex = frame.depthFramebuffer?.getDepthAttachment();
|
|
@@ -1270,7 +1560,7 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1270
1560
|
const isolateSceneColorDepth = frame.options.needsTransmissionDepthForSSR;
|
|
1271
1561
|
const savedDepthPrepassAttachment = ctx.depthPrepassAttachment;
|
|
1272
1562
|
const savedMaterialFlags = ctx.materialFlags;
|
|
1273
|
-
//
|
|
1563
|
+
// The background copy has no surface MRT attachments.
|
|
1274
1564
|
const sceneColorMaterialFlags = ctx.materialFlags & ~SURFACE_MRT_FLAGS;
|
|
1275
1565
|
const sceneColorFramebuffer = copyFramebufferHandle ? rgCtx.getFramebuffer(copyFramebufferHandle) : rgCtx.createFramebuffer({
|
|
1276
1566
|
width: copyTex.width,
|
|
@@ -1287,10 +1577,10 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1287
1577
|
_scenePass.transmission = false;
|
|
1288
1578
|
if (isolateSceneColorDepth) {
|
|
1289
1579
|
ctx.depthPrepassAttachment = undefined;
|
|
1290
|
-
_scenePass.clearDepth =
|
|
1580
|
+
_scenePass.clearDepth = DEPTH_CLEAR_VALUE;
|
|
1291
1581
|
_scenePass.clearStencil = 0;
|
|
1292
1582
|
} else {
|
|
1293
|
-
_scenePass.clearDepth = depthTex ? null :
|
|
1583
|
+
_scenePass.clearDepth = depthTex ? null : DEPTH_CLEAR_VALUE;
|
|
1294
1584
|
_scenePass.clearStencil = depthTex ? null : 0;
|
|
1295
1585
|
}
|
|
1296
1586
|
ctx.materialFlags = sceneColorMaterialFlags;
|
|
@@ -1308,11 +1598,13 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1308
1598
|
}
|
|
1309
1599
|
/** @internal */ function renderOpaqueScenePass(frame, sceneColorTex, sceneColorCopyTex, rgCtx, sceneColorFramebufferHandle) {
|
|
1310
1600
|
const { ctx, renderQueue } = frame;
|
|
1311
|
-
// Use RenderGraph-allocated scene color texture
|
|
1312
1601
|
const depthTex = frame.depthFramebuffer?.getDepthAttachment();
|
|
1313
|
-
ctx.materialFlags &= ~(MaterialVaryingFlags.
|
|
1314
|
-
if (ctx.
|
|
1315
|
-
ctx.materialFlags |= MaterialVaryingFlags.
|
|
1602
|
+
ctx.materialFlags &= ~(MaterialVaryingFlags.SCENE_STORE_ROUGHNESS | MaterialVaryingFlags.SSS_STORE_PROFILE | MaterialVaryingFlags.SSS_STORE_DIFFUSE | MaterialVaryingFlags.SCENE_STORE_NORMAL | MaterialVaryingFlags.SSS_STORE_TRANSMISSION | MaterialVaryingFlags.SKIN_SSS_STORE);
|
|
1603
|
+
if (ctx.SceneRoughnessTexture) {
|
|
1604
|
+
ctx.materialFlags |= MaterialVaryingFlags.SCENE_STORE_ROUGHNESS;
|
|
1605
|
+
}
|
|
1606
|
+
if (ctx.SceneNormalTexture) {
|
|
1607
|
+
ctx.materialFlags |= MaterialVaryingFlags.SCENE_STORE_NORMAL;
|
|
1316
1608
|
}
|
|
1317
1609
|
if (ctx.SSS) {
|
|
1318
1610
|
if (ctx.SSSDiffuseTexture) {
|
|
@@ -1325,11 +1617,7 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1325
1617
|
if (ctx.SkinSSSTexture) {
|
|
1326
1618
|
ctx.materialFlags |= MaterialVaryingFlags.SKIN_SSS_STORE;
|
|
1327
1619
|
}
|
|
1328
|
-
//
|
|
1329
|
-
// the graph was built in final-framebuffer-as-intermediate mode (external
|
|
1330
|
-
// depth shared with the final framebuffer AND no opaque-layer effects).
|
|
1331
|
-
// Checking the shared depth first would wrongly route the MRT/opaque-effect
|
|
1332
|
-
// case into the single-color final framebuffer.
|
|
1620
|
+
// Prefer the graph framebuffer; final-target mode has no graph framebuffer.
|
|
1333
1621
|
if (sceneColorFramebufferHandle && !hasSurfaceMRT(ctx)) {
|
|
1334
1622
|
ctx.intermediateFramebuffer = rgCtx.getFramebuffer(sceneColorFramebufferHandle);
|
|
1335
1623
|
} else if (!sceneColorFramebufferHandle && depthTex === ctx.finalFramebuffer?.getDepthAttachment()) {
|
|
@@ -1342,32 +1630,23 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1342
1630
|
depthAttachment: depthTex
|
|
1343
1631
|
});
|
|
1344
1632
|
}
|
|
1345
|
-
//
|
|
1346
|
-
// the end of this pass: graph passes never communicate through leftover
|
|
1347
|
-
// device state. TransparentPass re-binds the same target (or the opaque
|
|
1348
|
-
// chain output) explicitly.
|
|
1633
|
+
// Graph passes do not communicate through leftover device state.
|
|
1349
1634
|
ctx.device.pushDeviceStates();
|
|
1350
1635
|
try {
|
|
1351
|
-
// setFramebuffer
|
|
1352
|
-
// viewport/scissor explicitly to cover that case.
|
|
1636
|
+
// setFramebuffer may no-op, so reset viewport and scissor explicitly.
|
|
1353
1637
|
ctx.device.setFramebuffer(ctx.intermediateFramebuffer);
|
|
1354
1638
|
ctx.device.setViewport(null);
|
|
1355
1639
|
ctx.device.setScissor(null);
|
|
1356
1640
|
_scenePass.transmission = false;
|
|
1357
|
-
_scenePass.
|
|
1641
|
+
_scenePass.renderSky = false;
|
|
1642
|
+
_scenePass.clearDepth = depthTex ? null : DEPTH_CLEAR_VALUE;
|
|
1358
1643
|
_scenePass.clearStencil = depthTex ? null : 0;
|
|
1359
1644
|
if (renderQueue.needSceneColor() && sceneColorCopyTex) {
|
|
1360
|
-
//
|
|
1361
|
-
// color attachment with it and render only transmission/transparent on top.
|
|
1645
|
+
// Seed the main target with the refraction background.
|
|
1362
1646
|
ctx.sceneColorTexture = sceneColorCopyTex;
|
|
1363
1647
|
blitToCurrentColorAttachment(ctx, ctx.sceneColorTexture);
|
|
1364
1648
|
if (hasSurfaceMRT(ctx)) {
|
|
1365
|
-
//
|
|
1366
|
-
// geometry exists only there without roughness/normal (and SSS
|
|
1367
|
-
// lighting) data. Re-render the opaque lists into the MRT scene
|
|
1368
|
-
// target: early-z against the prepass depth keeps this cheap, and the
|
|
1369
|
-
// color output matches the blitted copy on opaque pixels while the
|
|
1370
|
-
// MRT attachments receive the surface data SSR/SSS require.
|
|
1649
|
+
// Re-render opaque lists to populate MRT data missing from the copy.
|
|
1371
1650
|
_scenePass.clearColor = null;
|
|
1372
1651
|
_scenePass.clearDepth = null;
|
|
1373
1652
|
_scenePass.clearStencil = null;
|
|
@@ -1384,28 +1663,49 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1384
1663
|
_scenePass.renderTransparent = false;
|
|
1385
1664
|
_scenePass.render(ctx, null, null, renderQueue);
|
|
1386
1665
|
} finally{
|
|
1387
|
-
// Restore
|
|
1388
|
-
// the transparent pass sets transmission/renderOpaque/renderTransparent
|
|
1389
|
-
// itself rather than inheriting whatever this pass happened to leave.
|
|
1666
|
+
// Restore shared pass flags before the next graph pass.
|
|
1390
1667
|
_scenePass.renderTransparent = true;
|
|
1668
|
+
_scenePass.renderSky = true;
|
|
1391
1669
|
_scenePass.transmission = false;
|
|
1392
1670
|
ctx.device.popDeviceStates();
|
|
1393
1671
|
}
|
|
1394
1672
|
}
|
|
1395
|
-
/**
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1673
|
+
/** Render sky and fog after opaque geometry. @internal */ function renderSkyScenePass(frame, rgCtx, sceneColorFramebufferHandle, sceneColorNoFog) {
|
|
1674
|
+
const { ctx } = frame;
|
|
1675
|
+
const framebuffer = sceneColorFramebufferHandle ? rgCtx.getFramebuffer(sceneColorFramebufferHandle) : ctx.finalFramebuffer;
|
|
1676
|
+
const device = ctx.device;
|
|
1677
|
+
device.pushDeviceStates();
|
|
1678
|
+
try {
|
|
1679
|
+
device.setFramebuffer(framebuffer);
|
|
1680
|
+
device.setViewport(null);
|
|
1681
|
+
device.setScissor(null);
|
|
1682
|
+
ctx.scene.env.sky.renderSky(ctx);
|
|
1683
|
+
if (ctx.scene.env.sky.fogPresents) {
|
|
1684
|
+
// Snapshot between sky and fog. Sky belongs in the copy - a ray that hits
|
|
1685
|
+
// the sky should read the sky - while fog does not, because the fog a
|
|
1686
|
+
// screen-space pass would sample lies along the camera ray rather than the
|
|
1687
|
+
// path it integrates.
|
|
1688
|
+
if (sceneColorNoFog) {
|
|
1689
|
+
const source = framebuffer?.getColorAttachment(0) ?? null;
|
|
1690
|
+
if (source) {
|
|
1691
|
+
new CopyBlitter().blit(source, sceneColorNoFog, fetchSampler('clamp_nearest_nomip'));
|
|
1692
|
+
device.setFramebuffer(framebuffer);
|
|
1693
|
+
device.setViewport(null);
|
|
1694
|
+
device.setScissor(null);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
ctx.scene.env.sky.renderFog(ctx.camera);
|
|
1698
|
+
}
|
|
1699
|
+
} finally{
|
|
1700
|
+
device.popDeviceStates();
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
/** Render transmission, transparency, and OIT over the opaque result. @internal */ function renderTransparentScenePass(frame, rgCtx, opaqueChainOutput, sceneColorFramebufferHandle) {
|
|
1403
1704
|
const { ctx, renderQueue } = frame;
|
|
1404
1705
|
const device = ctx.device;
|
|
1405
1706
|
let framebuffer;
|
|
1406
1707
|
if (opaqueChainOutput) {
|
|
1407
|
-
// Opaque
|
|
1408
|
-
// transparent geometry renders on top of it with the scene depth attached.
|
|
1708
|
+
// Opaque effects redirect transparent rendering to their chain output.
|
|
1409
1709
|
const chainTex = rgCtx.getTexture(opaqueChainOutput);
|
|
1410
1710
|
const depthTex = frame.depthFramebuffer?.getDepthAttachment();
|
|
1411
1711
|
framebuffer = rgCtx.createFramebuffer({
|
|
@@ -1414,39 +1714,34 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1414
1714
|
colorAttachments: chainTex,
|
|
1415
1715
|
depthAttachment: depthTex
|
|
1416
1716
|
});
|
|
1417
|
-
// The chain output
|
|
1717
|
+
// The chain output has no surface MRT attachments.
|
|
1418
1718
|
ctx.materialFlags &= ~SURFACE_MRT_FLAGS;
|
|
1419
1719
|
} else if (sceneColorFramebufferHandle) {
|
|
1420
|
-
//
|
|
1421
|
-
// graph scene color framebuffer the light pass rendered into.
|
|
1720
|
+
// Continue in the light pass target when no opaque effect ran.
|
|
1422
1721
|
framebuffer = rgCtx.getFramebuffer(sceneColorFramebufferHandle);
|
|
1423
1722
|
} else {
|
|
1424
|
-
//
|
|
1723
|
+
// Scene color already resides in the final framebuffer.
|
|
1425
1724
|
framebuffer = ctx.finalFramebuffer;
|
|
1426
1725
|
}
|
|
1427
1726
|
device.pushDeviceStates();
|
|
1428
1727
|
try {
|
|
1429
|
-
// setFramebuffer
|
|
1430
|
-
// viewport/scissor explicitly to cover that case.
|
|
1728
|
+
// setFramebuffer may no-op, so reset viewport and scissor explicitly.
|
|
1431
1729
|
device.setFramebuffer(framebuffer);
|
|
1432
1730
|
device.setViewport(null);
|
|
1433
1731
|
device.setScissor(null);
|
|
1434
|
-
// Derive transmission mode
|
|
1435
|
-
// pass used (renderQueue.needSceneColor()) instead of inheriting leftover
|
|
1436
|
-
// _scenePass state. When scene color is needed the opaque pass seeded the
|
|
1437
|
-
// refraction background and drew the transmission-opaque list, so here we
|
|
1438
|
-
// draw transmission_trans + transparent; otherwise just the transparent
|
|
1439
|
-
// list. Never clear: the opaque result is already in the target.
|
|
1732
|
+
// Derive transmission mode instead of inheriting shared pass state.
|
|
1440
1733
|
_scenePass.transmission = renderQueue.needSceneColor();
|
|
1441
1734
|
_scenePass.clearColor = null;
|
|
1442
1735
|
_scenePass.clearDepth = null;
|
|
1443
1736
|
_scenePass.clearStencil = null;
|
|
1444
1737
|
_scenePass.renderOpaque = false;
|
|
1445
1738
|
_scenePass.renderTransparent = true;
|
|
1739
|
+
_scenePass.renderSky = false;
|
|
1446
1740
|
try {
|
|
1447
1741
|
_scenePass.render(ctx, null, null, renderQueue);
|
|
1448
1742
|
} finally{
|
|
1449
1743
|
_scenePass.renderOpaque = true;
|
|
1744
|
+
_scenePass.renderSky = true;
|
|
1450
1745
|
}
|
|
1451
1746
|
} finally{
|
|
1452
1747
|
device.popDeviceStates();
|
|
@@ -1455,38 +1750,7 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1455
1750
|
/** @internal */ function renderTransmissionDepthPass(frame, rgCtx) {
|
|
1456
1751
|
renderSceneDepth(frame, frame.depthFramebuffer, rgCtx);
|
|
1457
1752
|
}
|
|
1458
|
-
/**
|
|
1459
|
-
* Frame-tail housekeeping shared by the Present and FrameCleanup passes.
|
|
1460
|
-
*
|
|
1461
|
-
* The end-layer post effect chain and the final blit are graph passes now
|
|
1462
|
-
* (see buildForwardPlusGraphInternal step 9/10); this only releases per-frame
|
|
1463
|
-
* state. The compositor's scene ping-pong is flushed back to the intermediate
|
|
1464
|
-
* framebuffer by compositor.end() at the tail of the light pass.
|
|
1465
|
-
*
|
|
1466
|
-
* @internal
|
|
1467
|
-
*/ function finishFrame(frame) {
|
|
1468
|
-
const { ctx } = frame;
|
|
1469
|
-
disposeRenderQueue(frame);
|
|
1470
|
-
ctx.materialFlags &= ~MaterialVaryingFlags.SSR_STORE_ROUGHNESS;
|
|
1471
|
-
ctx.materialFlags &= ~MaterialVaryingFlags.SSS_STORE_PROFILE;
|
|
1472
|
-
ctx.materialFlags &= ~MaterialVaryingFlags.SSS_STORE_DIFFUSE;
|
|
1473
|
-
ctx.materialFlags &= ~MaterialVaryingFlags.SSS_STORE_NORMAL;
|
|
1474
|
-
ctx.materialFlags &= ~MaterialVaryingFlags.SSS_STORE_TRANSMISSION;
|
|
1475
|
-
ctx.materialFlags &= ~MaterialVaryingFlags.SKIN_SSS_STORE;
|
|
1476
|
-
releaseIntermediateFramebuffer(frame);
|
|
1477
|
-
releaseDepthFramebuffer(frame);
|
|
1478
|
-
releaseClusteredLight(frame);
|
|
1479
|
-
restoreSunLight(frame);
|
|
1480
|
-
}
|
|
1481
|
-
// ─── Convenience: Execute Full Pipeline ─────────────────────────────
|
|
1482
|
-
/**
|
|
1483
|
-
* Build, compile, and execute the forward+ pipeline as a render graph.
|
|
1484
|
-
*
|
|
1485
|
-
* This is the drop-in replacement for `SceneRenderer._renderScene`.
|
|
1486
|
-
*
|
|
1487
|
-
* @param ctx - The draw context for this frame.
|
|
1488
|
-
* @public
|
|
1489
|
-
*/ function executeForwardPlusGraph(ctx) {
|
|
1753
|
+
/** Build and execute the Forward+ graph for one frame. @public */ function executeForwardPlusGraph(ctx) {
|
|
1490
1754
|
const device = ctx.device;
|
|
1491
1755
|
const graph = new RenderGraph();
|
|
1492
1756
|
let renderQueue = null;
|
|
@@ -1494,34 +1758,55 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1494
1758
|
let executor = null;
|
|
1495
1759
|
let historyManager = null;
|
|
1496
1760
|
let historyFrameStarted = false;
|
|
1761
|
+
let motionVectorFramePrepared = false;
|
|
1762
|
+
let motionVectorFrameCommitted = false;
|
|
1497
1763
|
try {
|
|
1498
|
-
// Cull scene first (needed to derive options)
|
|
1499
1764
|
renderQueue = _scenePass.cullScene(ctx, ctx.camera);
|
|
1500
1765
|
const options = deriveForwardPlusOptions(ctx.scene, ctx.camera, device.type, renderQueue);
|
|
1766
|
+
options.ssgi &&= supportsSSGIRenderTargets(ctx);
|
|
1501
1767
|
ctx.SSS = options.sss;
|
|
1502
|
-
// Ensure the camera has a history resource manager for temporal effects (TAA, motion blur)
|
|
1503
1768
|
historyManager = ctx.camera.getHistoryResourceManager();
|
|
1504
1769
|
if (!historyManager) {
|
|
1505
1770
|
historyManager = new HistoryResourceManager(_devicePoolAllocator);
|
|
1506
1771
|
ctx.camera.setHistoryResourceManager(historyManager);
|
|
1507
1772
|
}
|
|
1773
|
+
if (!options.ssgi) {
|
|
1774
|
+
historyManager.invalidate(RGHistoryResources.SSGI_SCENE_COLOR);
|
|
1775
|
+
historyManager.invalidate(RGHistoryResources.SSGI_IRRADIANCE);
|
|
1776
|
+
historyManager.invalidate(RGHistoryResources.SSGI_SURFACE);
|
|
1777
|
+
historyManager.invalidate(RGHistoryResources.SSGI_MOMENTS);
|
|
1778
|
+
}
|
|
1508
1779
|
historyManager.beginFrame();
|
|
1509
1780
|
historyFrameStarted = true;
|
|
1510
1781
|
const buildResult = buildForwardPlusGraphInternal(graph, ctx, renderQueue, options);
|
|
1511
1782
|
frame = buildResult.frame;
|
|
1783
|
+
if (options.motionVectors) {
|
|
1784
|
+
ctx.camera.prepareMotionVectorFrame(ctx.camera.TAA, ctx.renderWidth, ctx.renderHeight);
|
|
1785
|
+
motionVectorFramePrepared = true;
|
|
1786
|
+
} else {
|
|
1787
|
+
ctx.camera.clearMotionVectorFrame();
|
|
1788
|
+
}
|
|
1512
1789
|
const compiled = graph.compile([
|
|
1513
1790
|
buildResult.backbuffer
|
|
1514
1791
|
]);
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1792
|
+
executor = new RenderGraphExecutor(_devicePoolAllocator, ctx.renderWidth, ctx.renderHeight, {
|
|
1793
|
+
textureAffinityCache: getTextureAffinityCache(ctx.camera, device)
|
|
1794
|
+
});
|
|
1518
1795
|
if (ctx.finalFramebuffer) {
|
|
1519
1796
|
const backbufferTex = ctx.finalFramebuffer.getColorAttachments()[0];
|
|
1520
1797
|
executor.setImportedTexture(buildResult.backbuffer, backbufferTex);
|
|
1521
1798
|
}
|
|
1799
|
+
if (buildResult.externalDepthImport) {
|
|
1800
|
+
executor.setImportedTexture(buildResult.externalDepthImport.handle, buildResult.externalDepthImport.texture);
|
|
1801
|
+
}
|
|
1522
1802
|
historyManager.bindImportedTextures(executor);
|
|
1523
1803
|
executor.execute(compiled);
|
|
1524
1804
|
historyManager.commitFrame();
|
|
1805
|
+
historyFrameStarted = false;
|
|
1806
|
+
if (motionVectorFramePrepared) {
|
|
1807
|
+
ctx.camera.commitMotionVectorFrame();
|
|
1808
|
+
motionVectorFrameCommitted = true;
|
|
1809
|
+
}
|
|
1525
1810
|
} finally{
|
|
1526
1811
|
if (historyFrameStarted) {
|
|
1527
1812
|
historyManager?.discardFrame();
|
|
@@ -1532,8 +1817,11 @@ function blitToCurrentColorAttachment(ctx, source) {
|
|
|
1532
1817
|
renderQueue?.dispose();
|
|
1533
1818
|
}
|
|
1534
1819
|
executor?.reset();
|
|
1820
|
+
if (motionVectorFramePrepared && !motionVectorFrameCommitted) {
|
|
1821
|
+
ctx.camera.clearMotionVectorFrame();
|
|
1822
|
+
}
|
|
1535
1823
|
}
|
|
1536
1824
|
}
|
|
1537
1825
|
|
|
1538
|
-
export { buildForwardPlusGraph, deriveForwardPlusOptions, executeForwardPlusGraph };
|
|
1826
|
+
export { ForwardPlusModules, buildForwardPlusGraph, createForwardPlusPipeline, deriveForwardPlusOptions, executeForwardPlusGraph, getDefaultForwardPlusPipeline, renderOpaqueScenePass, renderSkyScenePass, renderTransparentScenePass };
|
|
1539
1827
|
//# sourceMappingURL=forward_plus_builder.js.map
|