Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 24 additions & 14 deletions packages/dev/core/src/Cameras/camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ export class Camera extends Node {
@serialize()
public isStereoscopicSideBySide: boolean;

/**
* Ignores camera maxZ when computing the projection matrix (ie. use 0 instead of maxZ), meaning objects won't be culled by the far plane
*/
@serialize()
public ignoreCameraMaxZ = false;

/**
* Defines the list of custom render target which are rendered to and then used as the input to this camera's render. Eg. display another camera view on a TV in the main scene
* This is pretty helpful if you wish to make a camera render to a texture you could reuse somewhere
Expand Down Expand Up @@ -653,7 +659,9 @@ export class Camera extends Node {

/** @internal */
public _isSynchronizedProjectionMatrix(): boolean {
let isSynchronized = this._cache.mode === this.mode && this._cache.minZ === this.minZ && this._cache.maxZ === this.maxZ;
const maxZ = this.ignoreCameraMaxZ ? 0 : this.maxZ;

let isSynchronized = this._cache.mode === this.mode && this._cache.minZ === this.minZ && this._cache.maxZ === maxZ;

if (!isSynchronized) {
return false;
Expand Down Expand Up @@ -933,10 +941,12 @@ export class Camera extends Node {
return this._projectionMatrix;
}

const maxZ = this.ignoreCameraMaxZ ? 0 : this.maxZ;

// Cache
this._cache.mode = this.mode;
this._cache.minZ = this.minZ;
this._cache.maxZ = this.maxZ;
this._cache.maxZ = maxZ;

// Matrix
this._refreshFrustumPlanes = true;
Expand Down Expand Up @@ -974,8 +984,8 @@ export class Camera extends Node {
getProjectionMatrix(
this.fov,
engine.getAspectRatio(this),
reverseDepth ? this.maxZ : this.minZ,
reverseDepth ? this.minZ : this.maxZ,
reverseDepth ? maxZ : this.minZ,
reverseDepth ? this.minZ : maxZ,
this._projectionMatrix,
this.fovMode === Camera.FOVMODE_VERTICAL_FIXED,
engine.isNDCHalfZRange,
Expand All @@ -992,8 +1002,8 @@ export class Camera extends Node {
this.orthoRight ?? halfWidth,
this.orthoBottom ?? -halfHeight,
this.orthoTop ?? halfHeight,
reverseDepth ? this.maxZ : this.minZ,
reverseDepth ? this.minZ : this.maxZ,
reverseDepth ? maxZ : this.minZ,
reverseDepth ? this.minZ : maxZ,
this.oblique.length,
this.oblique.angle,
this._computeObliqueDistance(this.oblique.offset),
Expand All @@ -1006,8 +1016,8 @@ export class Camera extends Node {
this.orthoRight ?? halfWidth,
this.orthoBottom ?? -halfHeight,
this.orthoTop ?? halfHeight,
reverseDepth ? this.maxZ : this.minZ,
reverseDepth ? this.minZ : this.maxZ,
reverseDepth ? maxZ : this.minZ,
reverseDepth ? this.minZ : maxZ,
this._projectionMatrix,
engine.isNDCHalfZRange
);
Expand All @@ -1019,8 +1029,8 @@ export class Camera extends Node {
this.orthoRight ?? halfWidth,
this.orthoBottom ?? -halfHeight,
this.orthoTop ?? halfHeight,
reverseDepth ? this.maxZ : this.minZ,
reverseDepth ? this.minZ : this.maxZ,
reverseDepth ? maxZ : this.minZ,
reverseDepth ? this.minZ : maxZ,
this.oblique.length,
this.oblique.angle,
this._computeObliqueDistance(this.oblique.offset),
Expand All @@ -1033,8 +1043,8 @@ export class Camera extends Node {
this.orthoRight ?? halfWidth,
this.orthoBottom ?? -halfHeight,
this.orthoTop ?? halfHeight,
reverseDepth ? this.maxZ : this.minZ,
reverseDepth ? this.minZ : this.maxZ,
reverseDepth ? maxZ : this.minZ,
reverseDepth ? this.minZ : maxZ,
this._projectionMatrix,
engine.isNDCHalfZRange
);
Expand Down Expand Up @@ -1335,7 +1345,7 @@ export class Camera extends Node {
this._cameraRigParams.vrMetrics.aspectRatioFov,
this._cameraRigParams.vrMetrics.aspectRatio,
this.minZ,
this.maxZ,
this.ignoreCameraMaxZ ? 0 : this.maxZ,
this._cameraRigParams.vrWorkMatrix,
true,
this.getEngine().isNDCHalfZRange
Expand Down Expand Up @@ -1374,7 +1384,7 @@ export class Camera extends Node {
public _updateRigCameras() {
for (let i = 0; i < this._rigCameras.length; i++) {
this._rigCameras[i].minZ = this.minZ;
this._rigCameras[i].maxZ = this.maxZ;
this._rigCameras[i].maxZ = this.ignoreCameraMaxZ ? 0 : this.maxZ;
this._rigCameras[i].fov = this.fov;
this._rigCameras[i].upVector.copyFrom(this.upVector);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class NodeRenderGraphBloomPostProcessBlock extends NodeRenderGraphBasePos
}

/** The luminance threshold to find bright areas of the image to bloom. */
@editableInPropertyPage("Threshold", PropertyTypeForEdition.Float, "PROPERTIES", { min: 0, max: 2 })
@editableInPropertyPage("Threshold", PropertyTypeForEdition.Float, "PROPERTIES", { min: 0, max: 1 })
public get threshold(): number {
return this._frameGraphTask.bloom.threshold;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class NodeRenderGraphChromaticAberrationPostProcessBlock extends NodeRend
}

/** The amount the effect will increase for pixels closer to the edge of the screen */
@editableInPropertyPage("Radial intensity", PropertyTypeForEdition.Float, "PROPERTIES", { min: 0.1, max: 5 })
@editableInPropertyPage("Radial intensity", PropertyTypeForEdition.Float, "PROPERTIES", { min: -1, max: 5 })
public get radialIntensity(): number {
return this._frameGraphTask.postProcess.radialIntensity;
}
Expand Down
101 changes: 101 additions & 0 deletions packages/dev/core/src/FrameGraph/Node/Blocks/computeShaderBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import type { NodeRenderGraphConnectionPoint, Scene, FrameGraph, IComputeShaderPath, IComputeShaderOptions } from "core/index";
import { RegisterClass } from "../../../Misc/typeStore";
import { NodeRenderGraphBlockConnectionPointTypes } from "../Types/nodeRenderGraphTypes";
import { NodeRenderGraphBlock } from "../nodeRenderGraphBlock";
import { FrameGraphComputeShaderTask } from "../../Tasks/Misc/computeShaderTask";

/**
* Block used to execute a compute shader in the frame graph
*/
export class NodeRenderGraphComputeShaderBlock extends NodeRenderGraphBlock {
protected override _frameGraphTask: FrameGraphComputeShaderTask;

/**
* Gets the frame graph task associated with this block
*/
public override get task() {
return this._frameGraphTask;
}

/**
* Creates a new NodeRenderGraphComputeShaderBlock
* @param name defines the block name
* @param frameGraph defines the hosting frame graph
* @param scene defines the hosting scene
* @param computeShaderPath defines the compute shader path or source
* @param computeShaderOptions defines the compute shader options
*/
public constructor(
name: string,
frameGraph: FrameGraph,
scene: Scene,
computeShaderPath: string | IComputeShaderPath = "@compute @workgroup_size(1, 1, 1)\nfn main() {}",
computeShaderOptions: IComputeShaderOptions = { bindingsMapping: {} }
) {
super(name, frameGraph, scene);

this._additionalConstructionParameters = [computeShaderPath, computeShaderOptions];

this._addDependenciesInput(
NodeRenderGraphBlockConnectionPointTypes.Camera | NodeRenderGraphBlockConnectionPointTypes.ShadowLight | NodeRenderGraphBlockConnectionPointTypes.ObjectList
);

this.registerOutput("output", NodeRenderGraphBlockConnectionPointTypes.ResourceContainer);

this._frameGraphTask = new FrameGraphComputeShaderTask(name, frameGraph, computeShaderPath, computeShaderOptions);
}

private _createTask(shaderPath: string | IComputeShaderPath, shaderOptions?: IComputeShaderOptions) {
const dispatchSize = this._frameGraphTask.dispatchSize;
const indirectDispatch = this._frameGraphTask.indirectDispatch;
const execute = this._frameGraphTask.execute;

this._frameGraphTask.dispose();
this._frameGraphTask = new FrameGraphComputeShaderTask(this.name, this._frameGraph, shaderPath, shaderOptions);

this._frameGraphTask.dispatchSize = dispatchSize;
this._frameGraphTask.indirectDispatch = indirectDispatch;
this._frameGraphTask.execute = execute;

this._additionalConstructionParameters = [shaderPath, shaderOptions];
}

/**
* Gets or sets the execute function
*/
public get shaderPath(): string | IComputeShaderPath {
return this._frameGraphTask.computeShader.shaderPath;
}

public set shaderPath(path: string | IComputeShaderPath) {
this._createTask(path, this.shaderOptions);
}

/**
* Gets or sets the execute when task disabled function
*/
public get shaderOptions(): IComputeShaderOptions {
return this._frameGraphTask.computeShader.options;
}

public set shaderOptions(options: IComputeShaderOptions) {
this._createTask(this.shaderPath, options);
}

/**
* Gets the current class name
* @returns the class name
*/
public override getClassName() {
return "NodeRenderGraphComputeShaderBlock";
}

/**
* Gets the output component
*/
public get output(): NodeRenderGraphConnectionPoint {
return this._outputs[0];
}
}

RegisterClass("BABYLON.NodeRenderGraphComputeShaderBlock", NodeRenderGraphComputeShaderBlock);
24 changes: 23 additions & 1 deletion packages/dev/core/src/FrameGraph/Node/Blocks/executeBlock.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { NodeRenderGraphConnectionPoint, Scene, FrameGraph } from "core/index";
import type { NodeRenderGraphConnectionPoint, Scene, FrameGraph, FrameGraphContext } from "core/index";
import { RegisterClass } from "../../../Misc/typeStore";
import { NodeRenderGraphBlockConnectionPointTypes } from "../Types/nodeRenderGraphTypes";
import { NodeRenderGraphBlock } from "../nodeRenderGraphBlock";
Expand Down Expand Up @@ -35,6 +35,28 @@ export class NodeRenderGraphExecuteBlock extends NodeRenderGraphBlock {
this._frameGraphTask = new FrameGraphExecuteTask(name, frameGraph);
}

/**
* Gets or sets the execute function
*/
public get func(): (context: FrameGraphContext) => void {
return this._frameGraphTask.func;
}

public set func(func: (context: FrameGraphContext) => void) {
this._frameGraphTask.func = func;
}

/**
* Gets or sets the execute when task disabled function
*/
public get funcDisabled(): ((context: FrameGraphContext) => void) | undefined {
return this._frameGraphTask.funcDisabled;
}

public set funcDisabled(func: ((context: FrameGraphContext) => void) | undefined) {
this._frameGraphTask.funcDisabled = func;
}

/**
* Gets the current class name
* @returns the class name
Expand Down
1 change: 1 addition & 0 deletions packages/dev/core/src/FrameGraph/Node/Blocks/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./computeShaderBlock";
export * from "./cullObjectsBlock";
export * from "./elbowBlock";
export * from "./executeBlock";
Expand Down
2 changes: 2 additions & 0 deletions packages/dev/core/src/FrameGraph/Node/Blocks/inputBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export class NodeRenderGraphInputBlock extends NodeRenderGraphBlock {
formats: [Constants.TEXTUREFORMAT_RGBA],
samples: 1,
useSRGBBuffers: [false],
creationFlags: [0],
},
sizeIsPercentage: true,
isHistoryTexture: false,
Expand All @@ -105,6 +106,7 @@ export class NodeRenderGraphInputBlock extends NodeRenderGraphBlock {
types: [Constants.TEXTURETYPE_UNSIGNED_BYTE],
formats: [Constants.TEXTUREFORMAT_DEPTH24_STENCIL8],
useSRGBBuffers: [false],
creationFlags: [0],
labels: [this.name],
samples: 1,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class NodeRenderGraphOutputBlock extends NodeRenderGraphBlock {
this._isUnique = true;

this.registerInput("texture", NodeRenderGraphBlockConnectionPointTypes.Texture);
this._addDependenciesInput();

this.texture.addAcceptedConnectionPointTypes(NodeRenderGraphBlockConnectionPointTypes.TextureAll);

Expand Down
10 changes: 7 additions & 3 deletions packages/dev/core/src/FrameGraph/Node/nodeRenderGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,12 +366,16 @@ export class NodeRenderGraph {
* Returns a promise that resolves when the node render graph is ready to be executed
* This method must be called after the graph has been built (NodeRenderGraph.build called)!
* @param timeStep Time step in ms between retries (default is 16)
* @param maxTimeout Maximum time in ms to wait for the graph to be ready (default is 30000)
* @param maxTimeout Maximum time in ms to wait for the graph to be ready (default is 5000)
* @returns The promise that resolves when the graph is ready
*/
// eslint-disable-next-line @typescript-eslint/promise-function-async, no-restricted-syntax
public whenReadyAsync(timeStep = 16, maxTimeout = 30000): Promise<void> {
return this._frameGraph.whenReadyAsync(timeStep, maxTimeout);
public whenReadyAsync(timeStep = 16, maxTimeout = 5000): Promise<void> {
this._frameGraph.pausedExecution = true;
// eslint-disable-next-line github/no-then
return this._frameGraph.whenReadyAsync(timeStep, maxTimeout).then(() => {
this._frameGraph.pausedExecution = false;
});
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/dev/core/src/FrameGraph/Node/nodeRenderGraphBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,14 @@ export class NodeRenderGraphBlock {

const dependencies = this.getInputByName("dependencies")!;

Object.defineProperty(this, "dependencies", {
get: function (this: FrameGraphTask) {
return dependencies;
},
enumerable: true,
configurable: true,
});

dependencies.addExcludedConnectionPointFromAllowedTypes(
NodeRenderGraphBlockConnectionPointTypes.TextureAllButBackBuffer |
NodeRenderGraphBlockConnectionPointTypes.ResourceContainer |
Expand Down
12 changes: 11 additions & 1 deletion packages/dev/core/src/FrameGraph/Passes/pass.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
import type { Nullable, FrameGraphContext, IFrameGraphPass, FrameGraphTask } from "core/index";

/**
* @internal
* Base class for a frame graph pass.
*/
export class FrameGraphPass<T extends FrameGraphContext> implements IFrameGraphPass {
private _executeFunc: (context: T) => void;

/**
* Whether the pass is disabled. Disabled passes will be skipped during execution.
*/
public disabled = false;

/** @internal */
constructor(
public name: string,
protected readonly _parentTask: FrameGraphTask,
protected readonly _context: T
) {}

/**
* Executes the pass.
* @param func The function to execute for the pass.
*/
public setExecuteFunc(func: (context: T) => void) {
this._executeFunc = func;
}

/** @internal */
public _execute() {
if (!this.disabled) {
this._executeFunc(this._context);
}
}

/** @internal */
public _isValid(): Nullable<string> {
return this._executeFunc !== undefined ? null : "Execute function is not set (call setExecuteFunc to set it)";
}
Expand Down
Loading