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.

352 lines (351 loc) 18.1 kB
import { Color4 } from "../../../Maths/math.color.js"; import { MaterialHelperGeometryRendering } from "../../../Materials/materialHelper.geometryrendering.js"; import { FrameGraphObjectRendererTask } from "./objectRendererTask.js"; const ClearColors = [new Color4(0, 0, 0, 0), new Color4(1, 1, 1, 1), new Color4(0, 0, 0, 0)]; /** * Task used to render geometry to a set of textures. */ export class FrameGraphGeometryRendererTask extends FrameGraphObjectRendererTask { /** * Whether to reverse culling (default is false). */ get reverseCulling() { return this._reverseCulling; } set reverseCulling(value) { this._reverseCulling = value; const configuration = MaterialHelperGeometryRendering.GetConfiguration(this._renderer.renderPassId); if (configuration) { configuration.reverseCulling = value; } } /** * Indicates whether the depth pre-pass is disabled (default is true). * Materials that require depth pre-pass (Material.needDepthPrePass == true) don't work with the geometry renderer, that's why this setting is true by default. * However, if the geometry renderer doesn't generate any geometry textures but only renders to the main target texture, then depth pre-pass can be enabled. */ get disableDepthPrePass() { return this._disableDepthPrePass; } set disableDepthPrePass(value) { this._disableDepthPrePass = value; this._renderer.disableDepthPrePass = value; } /** * Gets or sets the name of the task. */ get name() { return this._name; } set name(value) { this._name = value; if (this._renderer) { this._renderer.name = value; } } /** * Constructs a new geometry renderer task. * @param name The name of the task. * @param frameGraph The frame graph the task belongs to. * @param scene The scene the frame graph is associated with. * @param options The options of the object renderer. * @param existingObjectRenderer An existing object renderer to use (optional). If provided, the options parameter will be ignored. */ constructor(name, frameGraph, scene, options, existingObjectRenderer) { super(name, frameGraph, scene, options, existingObjectRenderer); /** * The size of the output textures (default is 100% of the back buffer texture size). */ this.size = { width: 100, height: 100 }; /** * Whether the size is a percentage of the back buffer size (default is true). */ this.sizeIsPercentage = true; /** * The number of samples to use for the output textures (default is 1). */ this.samples = 1; this._reverseCulling = false; /** * Indicates if a mesh shouldn't be rendered when its material has depth write disabled (default is true). */ this.dontRenderWhenMaterialDepthWriteIsDisabled = true; this._disableDepthPrePass = true; /** * The list of texture descriptions used by the geometry renderer task. */ this.textureDescriptions = []; this.renderSprites = false; this.renderParticles = false; this.enableBoundingBoxRendering = false; this.enableOutlineRendering = false; this._renderer.disableDepthPrePass = true; this._renderer.customIsReadyFunction = (mesh, refreshRate, preWarm) => { if (this.dontRenderWhenMaterialDepthWriteIsDisabled && mesh.material && mesh.material.disableDepthWrite) { return !!preWarm; } return mesh.isReady(refreshRate === 0); }; this._renderer.onBeforeRenderingManagerRenderObservable.add(() => { if (!this._renderer.options.doNotChangeAspectRatio) { scene.updateTransformMatrix(true); } }); this._clearAttachmentsLayout = new Map(); this._allAttachmentsLayout = []; this.geometryViewDepthTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryNormViewDepthTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryScreenDepthTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryViewNormalTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryWorldNormalTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryLocalPositionTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryWorldPositionTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryAlbedoTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryReflectivityTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryVelocityTexture = this._frameGraph.textureManager.createDanglingHandle(); this.geometryLinearVelocityTexture = this._frameGraph.textureManager.createDanglingHandle(); } /** * Gets the list of excluded meshes from the velocity texture. */ get excludedSkinnedMeshFromVelocityTexture() { return MaterialHelperGeometryRendering.GetConfiguration(this._renderer.renderPassId).excludedSkinnedMesh; } /** * Excludes the given skinned mesh from computing bones velocities. * Computing bones velocities can have a cost. The cost can be saved by calling this function and by passing the skinned mesh to ignore. * @param skinnedMesh The mesh containing the skeleton to ignore when computing the velocity map. */ excludeSkinnedMeshFromVelocityTexture(skinnedMesh) { if (skinnedMesh.skeleton) { const list = this.excludedSkinnedMeshFromVelocityTexture; if (list.indexOf(skinnedMesh) === -1) { list.push(skinnedMesh); } } } /** * Removes the given skinned mesh from the excluded meshes to integrate bones velocities while rendering the velocity map. * @param skinnedMesh The mesh containing the skeleton that has been ignored previously. * @see excludeSkinnedMesh to exclude a skinned mesh from bones velocity computation. */ removeExcludedSkinnedMeshFromVelocityTexture(skinnedMesh) { const list = this.excludedSkinnedMeshFromVelocityTexture; const index = list.indexOf(skinnedMesh); if (index !== -1) { list.splice(index, 1); } } getClassName() { return "FrameGraphGeometryRendererTask"; } record(skipCreationOfDisabledPasses = false, additionalExecute) { this._buildClearAttachmentsLayout(); this._registerForRenderPassId(this._renderer.renderPassId); MaterialHelperGeometryRendering.MarkAsDirty(this._renderer.renderPassId, this.objectList.meshes || this._scene.meshes); const pass = super.record(skipCreationOfDisabledPasses, additionalExecute); const outputTextureHandles = pass.renderTarget; let needPreviousWorldMatrices = false; for (let i = 0; i < this.textureDescriptions.length; i++) { const description = this.textureDescriptions[i]; const handle = outputTextureHandles[i]; const index = MaterialHelperGeometryRendering.GeometryTextureDescriptions.findIndex((f) => f.type === description.type); const geometryDescription = MaterialHelperGeometryRendering.GeometryTextureDescriptions[index]; switch (geometryDescription.type) { case 5: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryViewDepthTexture, handle); break; case 13: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryNormViewDepthTexture, handle); break; case 10: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryScreenDepthTexture, handle); break; case 6: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryViewNormalTexture, handle); break; case 8: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryWorldNormalTexture, handle); break; case 9: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryLocalPositionTexture, handle); break; case 1: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryWorldPositionTexture, handle); break; case 12: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryAlbedoTexture, handle); break; case 3: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryReflectivityTexture, handle); break; case 2: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryVelocityTexture, handle); needPreviousWorldMatrices = true; break; case 11: this._frameGraph.textureManager.resolveDanglingHandle(this.geometryLinearVelocityTexture, handle); needPreviousWorldMatrices = true; break; } } this._scene.needsPreviousWorldMatrices = needPreviousWorldMatrices; return pass; } dispose() { MaterialHelperGeometryRendering.DeleteConfiguration(this._renderer.renderPassId); this._renderer.dispose(); super.dispose(); } _resolveDanglingHandles(_targetTextures) { if (this.targetTexture !== undefined) { this._frameGraph.textureManager.resolveDanglingHandle(this.outputTexture, Array.isArray(this.targetTexture) ? this.targetTexture[0] : this.targetTexture); } if (this.depthTexture !== undefined) { this._frameGraph.textureManager.resolveDanglingHandle(this.outputDepthTexture, this.depthTexture); } } _checkParameters() { if (this.objectList === undefined || this.camera === undefined) { throw new Error(`FrameGraphGeometryRendererTask ${this.name}: object list and camera must be provided`); } } _checkTextureCompatibility(targetTextures) { let depthEnabled = false; let dimensions = null; if (this.targetTexture !== undefined) { const outputTextureDescription = this._frameGraph.textureManager.getTextureDescription(Array.isArray(this.targetTexture) ? this.targetTexture[0] : this.targetTexture); if (this.samples !== outputTextureDescription.options.samples) { throw new Error(`FrameGraphGeometryRendererTask ${this.name}: the target texture and the output geometry textures must have the same number of samples`); } dimensions = outputTextureDescription.size; } if (this.depthTexture !== undefined) { const depthTextureDescription = this._frameGraph.textureManager.getTextureDescription(this.depthTexture); if (depthTextureDescription.options.samples !== this.samples && this.textureDescriptions.length > 0) { throw new Error(`FrameGraphGeometryRendererTask ${this.name}: the depth texture and the output geometry textures must have the same number of samples`); } this._frameGraph.textureManager.resolveDanglingHandle(this.outputDepthTexture, this.depthTexture); depthEnabled = true; dimensions = depthTextureDescription.size; } const geomTextureDimensions = this.sizeIsPercentage ? this._frameGraph.textureManager.getAbsoluteDimensions(this.size) : this.size; if (dimensions !== null) { if (geomTextureDimensions.width !== dimensions.width || geomTextureDimensions.height !== dimensions.height) { throw new Error(`FrameGraphGeometryRendererTask ${this.name}: the geometry textures (size: ${geomTextureDimensions.width}x${geomTextureDimensions.height}) and the target/depth texture (size: ${dimensions.width}x${dimensions.height}) must have the same dimensions.`); } } depthEnabled = depthEnabled || super._checkTextureCompatibility(targetTextures); return depthEnabled; } _getTargetHandles() { const types = []; const formats = []; const labels = []; const useSRGBBuffers = []; for (let i = 0; i < this.textureDescriptions.length; i++) { const description = this.textureDescriptions[i]; const index = MaterialHelperGeometryRendering.GeometryTextureDescriptions.findIndex((f) => f.type === description.type); if (index === -1) { throw new Error(`FrameGraphGeometryRendererTask ${this.name}: unknown texture type ${description.type}`); } types[i] = description.textureType; formats[i] = description.textureFormat; labels[i] = MaterialHelperGeometryRendering.GeometryTextureDescriptions[index].name; useSRGBBuffers[i] = false; } const handles = []; if (this.textureDescriptions.length > 0) { const baseHandle = this._frameGraph.textureManager.createRenderTargetTexture(this.name, { size: this.size, sizeIsPercentage: this.sizeIsPercentage, options: { createMipMaps: false, samples: this.samples, types, formats, useSRGBBuffers, labels, }, }); for (let i = 0; i < this.textureDescriptions.length; i++) { handles.push(baseHandle + i); } } if (this.targetTexture !== undefined) { if (Array.isArray(this.targetTexture)) { handles.push(...this.targetTexture); } else { handles.push(this.targetTexture); } } return handles; } _prepareRendering(context, depthEnabled) { context.setDepthStates(this.depthTest && depthEnabled, this.depthWrite && depthEnabled); context.pushDebugGroup(`Clear attachments`); this._clearAttachmentsLayout.forEach((layout, clearType) => { context.clearColorAttachments(ClearColors[clearType], layout); }); context.restoreDefaultFramebuffer(); context.popDebugGroup(); return this._allAttachmentsLayout; } _buildClearAttachmentsLayout() { const clearAttachmentsLayout = new Map(); const allAttachmentsLayout = []; for (let i = 0; i < this.textureDescriptions.length; i++) { const description = this.textureDescriptions[i]; const index = MaterialHelperGeometryRendering.GeometryTextureDescriptions.findIndex((f) => f.type === description.type); const geometryDescription = MaterialHelperGeometryRendering.GeometryTextureDescriptions[index]; let layout = clearAttachmentsLayout.get(geometryDescription.clearType); if (layout === undefined) { layout = []; clearAttachmentsLayout.set(geometryDescription.clearType, layout); for (let j = 0; j < i; j++) { layout[j] = false; } } clearAttachmentsLayout.forEach((layout, clearType) => { layout.push(clearType === geometryDescription.clearType); }); allAttachmentsLayout.push(true); } if (this.targetTexture !== undefined) { // We don't clear the target texture, but we need to add a layout for it in clearAttachmentsLayout to be able to use clearColorAttachments with the correct number of attachments in _prepareRendering. // We also need to add a value in allAttachmentsLayout for the target texture. let layout = clearAttachmentsLayout.get(0 /* GeometryRenderingTextureClearType.Zero */); if (layout === undefined) { layout = []; clearAttachmentsLayout.set(0 /* GeometryRenderingTextureClearType.Zero */, layout); for (let j = 0; j < this.textureDescriptions.length - 1; j++) { layout[j] = false; } } clearAttachmentsLayout.forEach((layout) => { layout.push(false); }); allAttachmentsLayout.push(true); } this._clearAttachmentsLayout = new Map(); clearAttachmentsLayout.forEach((layout, clearType) => { this._clearAttachmentsLayout.set(clearType, this._engine.buildTextureLayout(layout)); }); this._allAttachmentsLayout = this._engine.buildTextureLayout(allAttachmentsLayout); } _registerForRenderPassId(renderPassId) { const configuration = MaterialHelperGeometryRendering.CreateConfiguration(renderPassId); for (let i = 0; i < this.textureDescriptions.length; i++) { const description = this.textureDescriptions[i]; const index = MaterialHelperGeometryRendering.GeometryTextureDescriptions.findIndex((f) => f.type === description.type); const geometryDescription = MaterialHelperGeometryRendering.GeometryTextureDescriptions[index]; configuration.defines[geometryDescription.defineIndex] = i; } if (this.targetTexture !== undefined) { configuration.defines["PREPASS_COLOR_INDEX"] = this.textureDescriptions.length; } configuration.reverseCulling = this.reverseCulling; } } //# sourceMappingURL=geometryRendererTask.js.map