@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.
177 lines • 8.73 kB
JavaScript
import { backbufferColorTextureHandle, backbufferDepthStencilTextureHandle } from "../../frameGraphTypes.js";
import { FrameGraphTask } from "../../frameGraphTask.js";
import { ObjectRenderer } from "../../../Rendering/objectRenderer.js";
import { FrameGraphCascadedShadowGeneratorTask } from "./csmShadowGeneratorTask.js";
/**
* Task used to render objects to a texture.
*/
export class FrameGraphObjectRendererTask extends FrameGraphTask {
/**
* Gets or sets the camera used to render the objects.
*/
get camera() {
return this._camera;
}
set camera(camera) {
this._camera = camera;
this._renderer.activeCamera = this.camera;
}
/**
* The object renderer used to render the objects.
*/
get objectRenderer() {
return this._renderer;
}
get name() {
return this._name;
}
set name(value) {
this._name = value;
if (this._renderer) {
this._renderer.name = value;
}
}
/**
* Constructs a new object 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);
/**
* The shadow generators used to render the objects (optional).
*/
this.shadowGenerators = [];
/**
* If depth testing should be enabled (default is true).
*/
this.depthTest = true;
/**
* If depth writing should be enabled (default is true).
*/
this.depthWrite = true;
/**
* If shadows should be disabled (default is false).
*/
this.disableShadows = false;
/**
* If image processing should be disabled (default is false).
* false means that the default image processing configuration will be applied (the one from the scene)
*/
this.disableImageProcessing = false;
this._onBeforeRenderObservable = null;
this._onAfterRenderObservable = null;
this._externalObjectRenderer = false;
this._scene = scene;
this._externalObjectRenderer = !!existingObjectRenderer;
this._renderer = existingObjectRenderer ?? new ObjectRenderer(name, scene, options);
this.name = name;
if (!this._externalObjectRenderer) {
this._renderer.onBeforeRenderingManagerRenderObservable.add(() => {
if (!this._renderer.options.doNotChangeAspectRatio) {
scene.updateTransformMatrix(true);
}
});
}
this.outputTexture = this._frameGraph.textureManager.createDanglingHandle();
this.outputDepthTexture = this._frameGraph.textureManager.createDanglingHandle();
}
isReady() {
return this._renderer.isReadyForRendering(this._textureWidth, this._textureHeight);
}
record(skipCreationOfDisabledPasses = false, additionalExecute) {
if (this.targetTexture === undefined || this.objectList === undefined) {
throw new Error(`FrameGraphObjectRendererTask ${this.name}: targetTexture and objectList are required`);
}
// Make sure the renderList / particleSystemList are set when FrameGraphObjectRendererTask.isReady() is called!
this._renderer.renderList = this.objectList.meshes;
this._renderer.particleSystemList = this.objectList.particleSystems;
this._renderer.disableImageProcessing = this.disableImageProcessing;
const outputTextureDescription = this._frameGraph.textureManager.getTextureDescription(this.targetTexture);
let depthEnabled = false;
if (this.depthTexture !== undefined) {
if (this.depthTexture === backbufferDepthStencilTextureHandle && this.targetTexture !== backbufferColorTextureHandle) {
throw new Error(`FrameGraphObjectRendererTask ${this.name}: the back buffer color texture is the only color texture allowed when the depth is the back buffer depth/stencil`);
}
if (this.depthTexture !== backbufferDepthStencilTextureHandle && this.targetTexture === backbufferColorTextureHandle) {
throw new Error(`FrameGraphObjectRendererTask ${this.name}: the back buffer depth/stencil texture is the only depth texture allowed when the target is the back buffer color`);
}
const depthTextureDescription = this._frameGraph.textureManager.getTextureDescription(this.depthTexture);
if (depthTextureDescription.options.samples !== outputTextureDescription.options.samples) {
throw new Error(`FrameGraphObjectRendererTask ${this.name}: the depth texture and the output texture must have the same number of samples`);
}
depthEnabled = true;
}
this._frameGraph.textureManager.resolveDanglingHandle(this.outputTexture, this.targetTexture);
if (this.depthTexture !== undefined) {
this._frameGraph.textureManager.resolveDanglingHandle(this.outputDepthTexture, this.depthTexture);
}
this._textureWidth = outputTextureDescription.size.width;
this._textureHeight = outputTextureDescription.size.height;
this._setLightsForShadow();
const pass = this._frameGraph.addRenderPass(this.name);
pass.setRenderTarget(this.targetTexture);
pass.setRenderTargetDepth(this.depthTexture);
pass.setExecuteFunc((context) => {
this._renderer.renderList = this.objectList.meshes;
this._renderer.particleSystemList = this.objectList.particleSystems;
this._renderer.disableImageProcessing = this.disableImageProcessing;
context.setDepthStates(this.depthTest && depthEnabled, this.depthWrite && depthEnabled);
context.render(this._renderer, this._textureWidth, this._textureHeight);
additionalExecute?.(context);
});
if (!skipCreationOfDisabledPasses) {
const passDisabled = this._frameGraph.addRenderPass(this.name + "_disabled", true);
passDisabled.setRenderTarget(this.targetTexture);
passDisabled.setRenderTargetDepth(this.depthTexture);
passDisabled.setExecuteFunc((_context) => { });
}
return pass;
}
dispose() {
this._renderer.onBeforeRenderObservable.remove(this._onBeforeRenderObservable);
this._renderer.onAfterRenderObservable.remove(this._onAfterRenderObservable);
if (!this._externalObjectRenderer) {
this._renderer.dispose();
}
super.dispose();
}
_setLightsForShadow() {
const lightsForShadow = new Set();
const shadowEnabled = new Map();
if (this.shadowGenerators) {
for (const shadowGeneratorTask of this.shadowGenerators) {
const shadowGenerator = shadowGeneratorTask.shadowGenerator;
const light = shadowGenerator.getLight();
if (light.isEnabled() && light.shadowEnabled) {
lightsForShadow.add(light);
if (FrameGraphCascadedShadowGeneratorTask.IsCascadedShadowGenerator(shadowGeneratorTask)) {
light._shadowGenerators.set(shadowGeneratorTask.camera, shadowGenerator);
}
else {
light._shadowGenerators.set(null, shadowGenerator);
}
}
}
}
this._renderer.onBeforeRenderObservable.remove(this._onBeforeRenderObservable);
this._onBeforeRenderObservable = this._renderer.onBeforeRenderObservable.add(() => {
for (let i = 0; i < this._scene.lights.length; i++) {
const light = this._scene.lights[i];
shadowEnabled.set(light, light.shadowEnabled);
light.shadowEnabled = !this.disableShadows && lightsForShadow.has(light);
}
});
this._renderer.onAfterRenderObservable.remove(this._onAfterRenderObservable);
this._onAfterRenderObservable = this._renderer.onAfterRenderObservable.add(() => {
for (let i = 0; i < this._scene.lights.length; i++) {
const light = this._scene.lights[i];
light.shadowEnabled = shadowEnabled.get(light);
}
});
}
}
//# sourceMappingURL=objectRendererTask.js.map