@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.
294 lines (293 loc) • 14.4 kB
JavaScript
import { backbufferDepthStencilTextureHandle } from "../../frameGraphTypes.js";
import { Color4 } from "../../../Maths/math.color.js";
import { MaterialHelperGeometryRendering } from "../../../Materials/materialHelper.geometryrendering.js";
import { FrameGraphTask } from "../../frameGraphTask.js";
import { ObjectRenderer } from "../../../Rendering/objectRenderer.js";
const clearColors = [new Color4(0, 0, 0, 0), new Color4(1, 1, 1, 1), new Color4(1e8, 1e8, 1e8, 1e8)];
/**
* Task used to render geometry to a set of textures.
*/
export class FrameGraphGeometryRendererTask extends FrameGraphTask {
/**
* Gets or sets the camera used for rendering.
*/
get camera() {
return this._camera;
}
set camera(camera) {
this._camera = camera;
this._renderer.activeCamera = this.camera;
}
/**
* 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;
}
}
/**
* The object renderer used by the geometry renderer task.
*/
get objectRenderer() {
return this._renderer;
}
/**
* 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.
*/
constructor(name, frameGraph, scene, options) {
super(name, frameGraph);
/**
* Whether depth testing is enabled (default is true).
*/
this.depthTest = true;
/**
* Whether depth writing is enabled (default is true).
*/
this.depthWrite = true;
/**
* 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;
/**
* The list of texture descriptions used by the geometry renderer task.
*/
this.textureDescriptions = [];
this._scene = scene;
this._engine = this._scene.getEngine();
this._renderer = new ObjectRenderer(name, scene, options);
this._renderer.renderSprites = false;
this._renderer.renderParticles = false;
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.name = name;
this._clearAttachmentsLayout = new Map();
this._allAttachmentsLayout = [];
this.outputDepthTexture = this._frameGraph.textureManager.createDanglingHandle();
this.geometryViewDepthTexture = 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;
}
isReady() {
return this._renderer.isReadyForRendering(this._textureWidth, this._textureHeight);
}
record() {
if (this.textureDescriptions.length === 0 || this.objectList === undefined) {
throw new Error(`FrameGraphGeometryRendererTask ${this.name}: object list and at least one geometry texture description must be provided`);
}
// Make sure the renderList / particleSystemList are set when FrameGraphGeometryRendererTask.isReady() is called!
this._renderer.renderList = this.objectList.meshes;
this._renderer.particleSystemList = this.objectList.particleSystems;
const outputTextureHandle = this._createMultiRenderTargetTexture();
const depthEnabled = this._checkDepthTextureCompatibility();
this._buildClearAttachmentsLayout();
this._registerForRenderPassId(this._renderer.renderPassId);
const outputTextureDescription = this._frameGraph.textureManager.getTextureDescription(outputTextureHandle[0]);
this._textureWidth = outputTextureDescription.size.width;
this._textureHeight = outputTextureDescription.size.height;
// Create pass
MaterialHelperGeometryRendering.MarkAsDirty(this._renderer.renderPassId, this.objectList.meshes || this._scene.meshes);
const pass = this._frameGraph.addRenderPass(this.name);
pass.setRenderTarget(outputTextureHandle);
for (let i = 0; i < this.textureDescriptions.length; i++) {
const description = this.textureDescriptions[i];
const handle = outputTextureHandle[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 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);
break;
case 11:
this._frameGraph.textureManager.resolveDanglingHandle(this.geometryLinearVelocityTexture, handle);
break;
}
}
pass.setRenderTargetDepth(this.depthTexture);
pass.setExecuteFunc((context) => {
this._renderer.renderList = this.objectList.meshes;
this._renderer.particleSystemList = this.objectList.particleSystems;
context.setDepthStates(this.depthTest && depthEnabled, this.depthWrite && depthEnabled);
this._clearAttachmentsLayout.forEach((layout, clearType) => {
context.clearColorAttachments(clearColors[clearType], layout);
});
context.bindAttachments(this._allAttachmentsLayout);
context.render(this._renderer, this._textureWidth, this._textureHeight);
});
const passDisabled = this._frameGraph.addRenderPass(this.name + "_disabled", true);
passDisabled.setRenderTarget(outputTextureHandle);
passDisabled.setRenderTargetDepth(this.depthTexture);
passDisabled.setExecuteFunc((_context) => { });
}
dispose() {
MaterialHelperGeometryRendering.DeleteConfiguration(this._renderer.renderPassId);
this._renderer.dispose();
super.dispose();
}
_createMultiRenderTargetTexture() {
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 baseHandle = this._frameGraph.textureManager.createRenderTargetTexture(this.name, {
size: this.size,
sizeIsPercentage: this.sizeIsPercentage,
options: {
createMipMaps: false,
samples: this.samples,
types,
formats,
useSRGBBuffers,
labels,
},
});
const handles = [];
for (let i = 0; i < this.textureDescriptions.length; i++) {
handles.push(baseHandle + i);
}
return handles;
}
_checkDepthTextureCompatibility() {
let depthEnabled = false;
if (this.depthTexture !== undefined) {
if (this.depthTexture === backbufferDepthStencilTextureHandle) {
throw new Error(`FrameGraphGeometryRendererTask ${this.name}: the depth/stencil back buffer is not allowed as a depth texture`);
}
const depthTextureDescription = this._frameGraph.textureManager.getTextureDescription(this.depthTexture);
if (depthTextureDescription.options.samples !== this.samples) {
throw new Error(`FrameGraphGeometryRendererTask ${this.name}: the depth texture and the output texture must have the same number of samples`);
}
this._frameGraph.textureManager.resolveDanglingHandle(this.outputDepthTexture, this.depthTexture);
depthEnabled = true;
}
return depthEnabled;
}
_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);
}
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;
}
configuration.reverseCulling = this.reverseCulling;
}
}
//# sourceMappingURL=geometryRendererTask.js.map