UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

207 lines (206 loc) 9.91 kB
import { Matrix, Vector4 } from "../../../../Maths/math.vector.js"; import { ThinCustomPostProcess } from "../../../../PostProcesses/thinCustomPostProcess.js"; import { FrameGraphTask } from "../../../frameGraphTask.js"; import { Color4 } from "../../../../Maths/math.color.js"; /** * Task used to trace IBL shadows from a voxel grid. * @internal */ export class FrameGraphIblShadowsTracingTask extends FrameGraphTask { get sampleDirections() { return this._sampleDirections; } set sampleDirections(value) { this._sampleDirections = Math.max(1, Math.round(value)); } get ssShadowSampleCount() { return this._ssShadowSampleCount; } set ssShadowSampleCount(value) { this._ssShadowSampleCount = Math.max(1, Math.round(value)); } get ssShadowStride() { return this._ssShadowStride; } set ssShadowStride(value) { this._ssShadowStride = Math.max(1, Math.round(value)); } constructor(name, frameGraph) { super(name, frameGraph); this._sampleDirections = 2; this.voxelShadowOpacity = 1; this.ssShadowOpacity = 1; this._ssShadowSampleCount = 16; this._ssShadowStride = 8; /** Scale factor applied to voxelGridSize / 2^resolutionExp to get the max SSS ray distance. */ this.ssShadowDistanceScale = 1.25; /** Scale factor applied to voxelGridSize to get the SSS surface thickness. */ this.ssShadowThicknessScale = 1.0; this.envRotation = 0; this.voxelNormalBias = 1.4; this.voxelDirectionBias = 1.75; this.worldScaleMatrix = Matrix.Identity(); this._shadowParameters = new Vector4(0, 0, 0, 0); this._sssParameters = new Vector4(0, 0, 0, 0); this._opacityParameters = new Vector4(0, 0, 0, 0); this._voxelBiasParameters = new Vector4(0, 0, 0, 0); this._cameraInvView = Matrix.Identity(); this._cameraInvProj = Matrix.Identity(); this._cameraInvViewProjection = Matrix.Identity(); this._frameId = 0; this._coloredShadows = false; this._currentDefines = ""; this.postProcess = new ThinCustomPostProcess(name, frameGraph.engine, { fragmentShader: "iblShadowVoxelTracing", uniforms: [ "viewMtx", "projMtx", "invProjMtx", "invViewMtx", "invVPMtx", "wsNormalizationMtx", "shadowParameters", "voxelBiasParameters", "sssParameters", "shadowOpacity", ], samplers: ["depthSampler", "worldNormalSampler", "blueNoiseSampler", "icdfSampler", "voxelGridSampler", "iblSampler"], shaderLanguage: frameGraph.engine.isWebGPU ? 1 /* ShaderLanguage.WGSL */ : 0 /* ShaderLanguage.GLSL */, }); this._postProcessDrawWrapper = this.postProcess.drawWrapper; this.outputTexture = this._frameGraph.textureManager.createDanglingHandle(); } getClassName() { return "FrameGraphIblShadowsTracingTask"; } // eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax initAsync() { if (this._frameGraph.engine.isWebGPU) { return import("../../../../ShadersWGSL/iblShadowVoxelTracing.fragment.js"); } return import("../../../../Shaders/iblShadowVoxelTracing.fragment.js"); } get coloredShadows() { return this._coloredShadows; } set coloredShadows(value) { if (this._coloredShadows === value) { return; } this._coloredShadows = value; this._updateDefines(); } isReady() { return this.postProcess.isReady(); } record() { if (this.camera === undefined || this.voxelGridTexture === undefined || this.depthTexture === undefined || this.normalTexture === undefined || this.icdfTexture === undefined) { throw new Error(`FrameGraphIblShadowsTracingTask ${this.name}: camera, voxelGridTexture, depthTexture, normalTexture and icdfTexture are required`); } const textureManager = this._frameGraph.textureManager; const size = textureManager.getTextureAbsoluteDimensions(this.depthTexture); const creationOptions = { size, sizeIsPercentage: false, isHistoryTexture: false, options: { createMipMaps: false, samples: 1, types: [0], formats: [5], useSRGBBuffers: [false], creationFlags: [0], labels: [`${this.name} Output`], }, }; textureManager.resolveDanglingHandle(this.outputTexture, undefined, `${this.name} Output`, creationOptions); this._updateDefines(); const pass = this._frameGraph.addRenderPass(this.name); const dependencies = [this.voxelGridTexture, this.depthTexture, this.normalTexture, this.icdfTexture]; if (this.environmentTexture !== undefined) { dependencies.push(this.environmentTexture); } if (this.blueNoiseTexture !== undefined) { dependencies.push(this.blueNoiseTexture); } pass.addDependencies(dependencies); pass.setRenderTarget(this.outputTexture); pass.setExecuteFunc((context) => { if (this.icdfTexture === undefined || this.blueNoiseTexture === undefined || (this.coloredShadows && this.environmentTexture === undefined)) { context.clear(new Color4(1, 1, 1, 1), true, false, false); return; } context.setTextureSamplingMode(this.depthTexture, 1); context.setTextureSamplingMode(this.normalTexture, 1); context.setTextureSamplingMode(this.icdfTexture, 1); context.setTextureSamplingMode(this.blueNoiseTexture, 1); const view = this.camera.getViewMatrix(); const projection = this.camera.getProjectionMatrix(); projection.invertToRef(this._cameraInvProj); view.invertToRef(this._cameraInvView); this.camera.getTransformationMatrix().invertToRef(this._cameraInvViewProjection); const voxelGridSize = textureManager.getTextureAbsoluteDimensions(this.voxelGridTexture); const highestMip = Math.floor(Math.log2(Math.max(1, voxelGridSize.width))); this._frameId++; let rotation = 0.0; if (this.environmentTexture) { rotation = this._frameGraph.scene.environmentTexture.rotationY ?? 0; } rotation = this._frameGraph.scene.useRightHandedSystem ? -(rotation + 0.5 * Math.PI) : rotation - 0.5 * Math.PI; rotation = rotation % (2.0 * Math.PI); this._shadowParameters.set(this.sampleDirections, this._frameId, 1.0, rotation); this._voxelBiasParameters.set(this.voxelNormalBias, this.voxelDirectionBias, highestMip, 0.0); const gridSize = this.voxelizationTask?.voxelGridSize ?? 1.0; const resExp = this.voxelizationTask?.resolutionExp ?? 6; const sssMaxDist = (this.ssShadowDistanceScale * gridSize) / (1 << resExp); const sssThickness = this.ssShadowThicknessScale * 0.005 * gridSize; this._sssParameters.set(this.ssShadowSampleCount, this.ssShadowStride, sssMaxDist, sssThickness); this._opacityParameters.set(this.voxelShadowOpacity, this.ssShadowOpacity, 0.0, 0.0); context.applyFullScreenEffect(this._postProcessDrawWrapper, () => { const effect = this._postProcessDrawWrapper.effect; context.bindTextureHandle(effect, "voxelGridSampler", this.voxelGridTexture); context.bindTextureHandle(effect, "depthSampler", this.depthTexture); context.bindTextureHandle(effect, "worldNormalSampler", this.normalTexture); context.bindTextureHandle(effect, "icdfSampler", this.icdfTexture); context.bindTextureHandle(effect, "blueNoiseSampler", this.blueNoiseTexture); if (this.coloredShadows && this.environmentTexture !== undefined) { context.bindTextureHandle(effect, "iblSampler", this.environmentTexture); } effect.setMatrix("viewMtx", view); effect.setMatrix("projMtx", projection); effect.setMatrix("invProjMtx", this._cameraInvProj); effect.setMatrix("invViewMtx", this._cameraInvView); effect.setMatrix("invVPMtx", this._cameraInvViewProjection); effect.setMatrix("wsNormalizationMtx", this.worldScaleMatrix); effect.setVector4("shadowParameters", this._shadowParameters); effect.setVector4("voxelBiasParameters", this._voxelBiasParameters); effect.setVector4("sssParameters", this._sssParameters); effect.setVector4("shadowOpacity", this._opacityParameters); this.postProcess.bind(); }, undefined, false, false, true); }); } dispose() { this.postProcess.dispose(); super.dispose(); } _updateDefines() { const defines = ["#define WORLD_NORMAL_UNSIGNED"]; if (this._frameGraph.scene.useRightHandedSystem) { defines.push("#define RIGHT_HANDED"); } if (this.coloredShadows) { defines.push("#define COLOR_SHADOWS 1u"); } const defineString = defines.join("\n"); if (defineString !== this._currentDefines) { this._currentDefines = defineString; this.postProcess.updateEffect(this._currentDefines); } } } //# sourceMappingURL=iblShadowsTracingTask.js.map