Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { FrameGraphTextureHandle, FrameGraph, Scene } from "core/index";
import type { FrameGraphTextureHandle, FrameGraph, Scene, FrameGraphMultiValueType } from "core/index";
import { CascadedShadowGenerator } from "../../../Lights/Shadows/cascadedShadowGenerator";
import { FrameGraphShadowGeneratorTask } from "./shadowGeneratorTask";
import { DirectionalLight } from "../../../Lights/directionalLight";
import { DepthTextureType, ThinMinMaxReducer } from "../../../Misc/thinMinMaxReducer";
import { FrameGraphPostProcessTask } from "../PostProcesses/postProcessTask";
import { Constants } from "../../../Engines/constants";
import { textureSizeIsObject } from "../../../Materials/Textures/textureCreationOptions";
import { FrameGraphTaskMultiProperty } from "../../frameGraph.decorators";

/**
* Task used to generate a cascaded shadow map from a list of objects.
Expand Down Expand Up @@ -34,39 +35,35 @@ export class FrameGraphCascadedShadowGeneratorTask extends FrameGraphShadowGener
*/
public depthTextureType: DepthTextureType = DepthTextureType.NormalizedViewDepth;

private _numCascades = CascadedShadowGenerator.DEFAULT_CASCADES_COUNT;
/**
* The number of cascades.
*/
public get numCascades() {
return this._numCascades;
}
@FrameGraphTaskMultiProperty("_numCascadesSetter")
public numCascades = CascadedShadowGenerator.DEFAULT_CASCADES_COUNT;

public set numCascades(value: number) {
if (value === this._numCascades) {
return;
}
/**
* Multi value version of numCascades.
*/
public numCascadesMulti: FrameGraphMultiValueType<number>;

this._numCascades = value;
protected _numCascadesSetter(_oldValue: number) {
this._setupShadowGenerator();
}

private _debug = false;
/**
* Gets or sets a value indicating whether the shadow generator should display the cascades.
*/
public get debug() {
return this._debug;
}
@FrameGraphTaskMultiProperty("_debugSetter")
public debug = false;

public set debug(value: boolean) {
if (value === this._debug) {
return;
}
/**
* Multi value version of debug.
*/
public debugMulti: FrameGraphMultiValueType<boolean>;

this._debug = value;
protected _debugSetter(_oldValue: boolean) {
if (this._shadowGenerator) {
this._shadowGenerator.debug = value;
this._shadowGenerator.debug = this.debug;
}
}

Expand Down Expand Up @@ -270,7 +267,7 @@ export class FrameGraphCascadedShadowGeneratorTask extends FrameGraphShadowGener
throw new Error(`FrameGraphCascadedShadowGeneratorTask ${this.name}: the CSM shadow generator only supports directional lights.`);
}
this._shadowGenerator = new CascadedShadowGenerator(this.mapSize, this.light, this.useFloat32TextureType, this.camera, this.useRedTextureFormat);
this._shadowGenerator.numCascades = this._numCascades;
this._shadowGenerator.numCascades = this.numCascades;
}

protected override _setupShadowGenerator() {
Expand All @@ -281,7 +278,7 @@ export class FrameGraphCascadedShadowGeneratorTask extends FrameGraphShadowGener
return;
}

shadowGenerator.debug = this._debug;
shadowGenerator.debug = this.debug;
shadowGenerator.stabilizeCascades = this._stabilizeCascades;
shadowGenerator.lambda = this._lambda;
shadowGenerator.cascadeBlendPercentage = this._cascadeBlendPercentage;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { FrameGraph, FrameGraphTextureHandle, FrameGraphRenderPass } from "core/index";
import type { FrameGraph, FrameGraphTextureHandle, FrameGraphRenderPass, FrameGraphMultiValueType } from "core/index";
import { Color4, TmpColors } from "../../../Maths/math.color";
import { FrameGraphTask } from "../../frameGraphTask";
import { backbufferColorTextureHandle } from "../../frameGraphTypes";
import { FrameGraphTaskMultiProperty } from "../../frameGraph.decorators";

/**
* Task used to clear a texture.
Expand Down Expand Up @@ -35,8 +36,14 @@ export class FrameGraphClearTextureTask extends FrameGraphTask {
/**
* The value to use to clear the stencil buffer (default: 0).
*/
@FrameGraphTaskMultiProperty()
public stencilValue = 0;

/**
* Multi value version of stencilValue.
*/
public stencilValueMulti: FrameGraphMultiValueType<number>;

/**
* The color texture to clear.
*/
Expand Down
131 changes: 131 additions & 0 deletions packages/dev/core/src/FrameGraph/frameGraph.decorators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import type { FrameGraphTask } from "core/index";

interface IFrameGraphEvaluate {
evaluate: () => boolean;
}

/**
* Interface used to evaluate a property in a multi values task property.
*/
export interface IFrameGraphEvaluateProperty<T> extends IFrameGraphEvaluate {
/**
* The value to use if evaluate() returns true.
*/
value: T;
}

/**
* An array of IFrameGraphEvaluateProperty.
*/
export type FrameGraphMultiValueType<T> = Array<IFrameGraphEvaluateProperty<T>>;

/** @internal */
export class FrameGraphTaskProperty<T> {
private _multi?: FrameGraphMultiValueType<T>;
private _value: T;

constructor(
private _task: FrameGraphTask,
defaultValue: T,
private _setter?: (oldValue: T) => void
) {
_task.multiProperties.push(this);
(this._value as any) = defaultValue;
}

public evaluate(): void {
if (this._multi === undefined) {
return;
}
for (const entry of this._multi) {
if (entry.evaluate()) {
const oldValue = this._value;
this._value = entry.value;
if (oldValue !== this._value && this._setter) {
this._setter.call(this._task, oldValue);
}
return;
}
}
}

public get multi(): FrameGraphMultiValueType<T> {
if (this._multi === undefined) {
this._multi = [];
}
return this._multi;
}

public set multi(value: FrameGraphMultiValueType<T>) {
this._multi = value;
}

public get value(): T {
return this._value;
}

public set value(value: T) {
this._multi = undefined;
this._value = value;
}
}

/**
* Decorator to create a multi-value property for a frame graph task.
* @param setterName Optional name of the setter to call when the property changes.
* @returns Internal use only.
*/
export function FrameGraphTaskMultiProperty(setterName?: string) {
return (target: any, propertyKey: string) => {
const propertyObjectName = propertyKey + "Prop";

Object.defineProperty(target, propertyKey, {
get: function (this: FrameGraphTask) {
const prop = (this as any)[propertyObjectName];
return prop && prop.evaluateMulti ? prop.value : prop;
},
set: function (this: FrameGraphTask, value: any) {
const prop = (this as any)[propertyObjectName];
let oldValue: any;
if (prop && prop.evaluateMulti) {
oldValue = prop.value;
this.multiProperties.splice(this.multiProperties.indexOf(prop), 1);
} else {
oldValue = prop;
}
if (oldValue === value) {
return;
}
(this as any)[propertyObjectName] = value;
if (setterName) {
(this as any)[setterName].call(this, oldValue);
}
},
enumerable: true,
configurable: true,
});

Object.defineProperty(target, propertyKey + "Multi", {
get: function (this: FrameGraphTask) {
let prop = (this as any)[propertyObjectName] as FrameGraphTaskProperty<any>;
if (!prop || !prop.evaluate) {
prop = new FrameGraphTaskProperty<any>(this, prop, setterName ? (this as any)[setterName] : undefined);
(this as any)[propertyObjectName] = prop;
}

return prop.multi;
},
set: function (this: FrameGraphTask, value: FrameGraphMultiValueType<any>) {
let prop = (this as any)[propertyObjectName] as FrameGraphTaskProperty<any>;
if (!prop || !prop.evaluate) {
prop = new FrameGraphTaskProperty<any>(this, prop, setterName ? (this as any)[setterName] : undefined);
(this as any)[propertyObjectName] = prop;
}

prop.multi = value;
},
enumerable: true,
configurable: true,
});
};
}
25 changes: 25 additions & 0 deletions packages/dev/core/src/FrameGraph/frameGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,18 @@ export class FrameGraph implements IDisposable {
return pass;
}

/**
* Evaluates the multi-valued properties of all tasks in the frame graph.
*/
public evaluateMultiValuedProperties(): void {
for (const task of this._tasks) {
if (task.available && !task.available()) {
continue;
}
task.evaluateMultiValuedProperties();
}
}

/**
* Builds the frame graph.
* This method should be called after all tasks have been added to the frame graph (FrameGraph.addTask) and before the graph is executed (FrameGraph.execute).
Expand All @@ -211,7 +223,13 @@ export class FrameGraph implements IDisposable {
this.textureManager._releaseTextures(false);

try {
this.evaluateMultiValuedProperties();

for (const task of this._tasks) {
if (task.available && !task.available()) {
continue;
}

task._reset();

this._currentProcessedTask = task;
Expand Down Expand Up @@ -256,6 +274,9 @@ export class FrameGraph implements IDisposable {
() => {
let ready = this._renderContext._isReady();
for (const task of this._tasks) {
if (task.available && !task.available()) {
continue;
}
const taskIsReady = task.isReady();
if (!taskIsReady && !firstNotReadyTask) {
firstNotReadyTask = task;
Expand Down Expand Up @@ -306,6 +327,10 @@ export class FrameGraph implements IDisposable {
this.textureManager._updateHistoryTextures();

for (const task of this._tasks) {
if (task.available && !task.available()) {
continue;
}

const passes = task._getPasses();

for (const pass of passes) {
Expand Down
36 changes: 35 additions & 1 deletion packages/dev/core/src/FrameGraph/frameGraphTask.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import type { FrameGraph, FrameGraphObjectList, IFrameGraphPass, Nullable, FrameGraphTextureHandle, InternalTexture, FrameGraphRenderContext } from "core/index";
import type {
FrameGraph,
FrameGraphObjectList,
IFrameGraphPass,
Nullable,
FrameGraphTextureHandle,
InternalTexture,
FrameGraphRenderContext,
FrameGraphTaskProperty,
} from "core/index";
import { FrameGraphCullPass } from "./Passes/cullPass";
import { FrameGraphRenderPass } from "./Passes/renderPass";
import { Observable } from "core/Misc/observable";
Expand All @@ -12,11 +21,27 @@ export abstract class FrameGraphTask {

private readonly _passes: IFrameGraphPass[] = [];
private readonly _passesDisabled: IFrameGraphPass[] = [];
private readonly _multiProperties: FrameGraphTaskProperty<any>[] = [];

/**
* The multi-value properties of the task.
* @internal
*/
public get multiProperties() {
return this._multiProperties;
}

// Note: must be a getter/setter even if there's no specific processing, otherwise inherited classes can't make it a getter/setter!
// Same thing for the disabled property
protected _name: string;

/**
* A function that returns whether the task is available.
* If not defined, the task is always available.
* If the task is not available, it will be skipped at build and execution time.
*/
public available?: () => boolean;

/**
* The name of the task.
*/
Expand Down Expand Up @@ -78,6 +103,15 @@ export abstract class FrameGraphTask {
return true;
}

/**
* Evaluates the multi-valued properties of the task.
*/
public evaluateMultiValuedProperties(): void {
for (const prop of this._multiProperties) {
prop.evaluate();
}
}

/**
* Disposes of the task.
*/
Expand Down
1 change: 1 addition & 0 deletions packages/dev/core/src/FrameGraph/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export * from "./Tasks/Rendering/shadowGeneratorTask";
export * from "./Tasks/Rendering/taaObjectRendererTask";
export * from "./Tasks/Rendering/utilityLayerRendererTask";

export * from "./frameGraph.decorators";
export * from "./frameGraph";
export * from "./frameGraphContext";
export * from "./frameGraphObjectList";
Expand Down
Loading