diff --git a/packages/dev/core/src/Decorators/nodeDecorator.ts b/packages/dev/core/src/Decorators/nodeDecorator.ts index 96d775529ef..b0ad690caca 100644 --- a/packages/dev/core/src/Decorators/nodeDecorator.ts +++ b/packages/dev/core/src/Decorators/nodeDecorator.ts @@ -17,6 +17,8 @@ export const enum PropertyTypeForEdition { Vector3, /** property is a list of values */ List, + /** property is a Color3 */ + Color3, /** property is a Color4 */ Color4, /** property (int) should be edited as a combo box with a list of sampling modes */ diff --git a/packages/dev/core/src/FrameGraph/Node/Blocks/Rendering/baseObjectRendererBlock.ts b/packages/dev/core/src/FrameGraph/Node/Blocks/Rendering/baseObjectRendererBlock.ts index 766dd33834b..0358882d724 100644 --- a/packages/dev/core/src/FrameGraph/Node/Blocks/Rendering/baseObjectRendererBlock.ts +++ b/packages/dev/core/src/FrameGraph/Node/Blocks/Rendering/baseObjectRendererBlock.ts @@ -246,6 +246,26 @@ export class NodeRenderGraphBaseObjectRendererBlock extends NodeRenderGraphBlock this._createFrameGraphObjectWithState(this.doNotChangeAspectRatio, value); } + /** If true, MSAA color textures will be resolved at the end of the render pass (default: true) */ + @editableInPropertyPage("Resolve MSAA colors", PropertyTypeForEdition.Boolean, "PROPERTIES") + public get resolveMSAAColors() { + return this._frameGraphTask.resolveMSAAColors; + } + + public set resolveMSAAColors(value: boolean) { + this._frameGraphTask.resolveMSAAColors = value; + } + + /** If true, MSAA depth texture will be resolved at the end of the render pass (default: false) */ + @editableInPropertyPage("Resolve MSAA depth", PropertyTypeForEdition.Boolean, "PROPERTIES") + public get resolveMSAADepth() { + return this._frameGraphTask.resolveMSAADepth; + } + + public set resolveMSAADepth(value: boolean) { + this._frameGraphTask.resolveMSAADepth = value; + } + /** * Gets the current class name * @returns the class name @@ -358,6 +378,8 @@ export class NodeRenderGraphBaseObjectRendererBlock extends NodeRenderGraphBlock codes.push(`${this._codeVariableName}.enableOutlineRendering = ${this.enableOutlineRendering};`); codes.push(`${this._codeVariableName}.disableShadows = ${this.disableShadows};`); codes.push(`${this._codeVariableName}.renderInLinearSpace = ${this.renderInLinearSpace};`); + codes.push(`${this._codeVariableName}.resolveMSAAColors = ${this.resolveMSAAColors};`); + codes.push(`${this._codeVariableName}.resolveMSAADepth = ${this.resolveMSAADepth};`); return super._dumpPropertiesCode() + codes.join("\n"); } @@ -373,6 +395,8 @@ export class NodeRenderGraphBaseObjectRendererBlock extends NodeRenderGraphBlock serializationObject.enableOutlineRendering = this.enableOutlineRendering; serializationObject.disableShadows = this.disableShadows; serializationObject.renderInLinearSpace = this.renderInLinearSpace; + serializationObject.resolveMSAAColors = this.resolveMSAAColors; + serializationObject.resolveMSAADepth = this.resolveMSAADepth; return serializationObject; } @@ -388,5 +412,7 @@ export class NodeRenderGraphBaseObjectRendererBlock extends NodeRenderGraphBlock this.enableOutlineRendering = serializationObject.enableOutlineRendering ?? true; this.disableShadows = serializationObject.disableShadows; this.renderInLinearSpace = !!serializationObject.renderInLinearSpace; + this.resolveMSAAColors = serializationObject.resolveMSAAColors ?? true; + this.resolveMSAADepth = serializationObject.resolveMSAADepth ?? false; } } diff --git a/packages/dev/core/src/FrameGraph/Node/Blocks/Rendering/geometryRendererBlock.ts b/packages/dev/core/src/FrameGraph/Node/Blocks/Rendering/geometryRendererBlock.ts index 32e9eafcd0b..318fbd7034a 100644 --- a/packages/dev/core/src/FrameGraph/Node/Blocks/Rendering/geometryRendererBlock.ts +++ b/packages/dev/core/src/FrameGraph/Node/Blocks/Rendering/geometryRendererBlock.ts @@ -202,6 +202,26 @@ export class NodeRenderGraphGeometryRendererBlock extends NodeRenderGraphBlock { this._frameGraphTask.dontRenderWhenMaterialDepthWriteIsDisabled = value; } + /** If true, MSAA color textures will be resolved at the end of the render pass (default: true) */ + @editableInPropertyPage("Resolve MSAA colors", PropertyTypeForEdition.Boolean, "PROPERTIES") + public get resolveMSAAColors() { + return this._frameGraphTask.resolveMSAAColors; + } + + public set resolveMSAAColors(value: boolean) { + this._frameGraphTask.resolveMSAAColors = value; + } + + /** If true, MSAA depth texture will be resolved at the end of the render pass (default: false) */ + @editableInPropertyPage("Resolve MSAA depth", PropertyTypeForEdition.Boolean, "PROPERTIES") + public get resolveMSAADepth() { + return this._frameGraphTask.resolveMSAADepth; + } + + public set resolveMSAADepth(value: boolean) { + this._frameGraphTask.resolveMSAADepth = value; + } + // View depth @editableInPropertyPage("View depth format", PropertyTypeForEdition.TextureFormat, "GEOMETRY BUFFERS") public viewDepthFormat = Constants.TEXTUREFORMAT_RED; @@ -509,6 +529,8 @@ export class NodeRenderGraphGeometryRendererBlock extends NodeRenderGraphBlock { codes.push(`${this._codeVariableName}.velocityType = ${this.velocityType};`); codes.push(`${this._codeVariableName}.linearVelocityFormat = ${this.linearVelocityFormat};`); codes.push(`${this._codeVariableName}.linearVelocityType = ${this.linearVelocityType};`); + codes.push(`${this._codeVariableName}.resolveMSAAColors = ${this.resolveMSAAColors};`); + codes.push(`${this._codeVariableName}.resolveMSAADepth = ${this.resolveMSAADepth};`); return super._dumpPropertiesCode() + codes.join("\n"); } @@ -542,6 +564,8 @@ export class NodeRenderGraphGeometryRendererBlock extends NodeRenderGraphBlock { serializationObject.velocityType = this.velocityType; serializationObject.linearVelocityFormat = this.linearVelocityFormat; serializationObject.linearVelocityType = this.linearVelocityType; + serializationObject.resolveMSAAColors = this.resolveMSAAColors; + serializationObject.resolveMSAADepth = this.resolveMSAADepth; return serializationObject; } @@ -575,6 +599,8 @@ export class NodeRenderGraphGeometryRendererBlock extends NodeRenderGraphBlock { this.velocityType = serializationObject.velocityType; this.linearVelocityFormat = serializationObject.linearVelocityFormat; this.linearVelocityType = serializationObject.linearVelocityType; + this.resolveMSAAColors = serializationObject.resolveMSAAColors ?? true; + this.resolveMSAADepth = serializationObject.resolveMSAADepth ?? false; } } diff --git a/packages/dev/core/src/FrameGraph/Node/Blocks/Textures/clearBlock.ts b/packages/dev/core/src/FrameGraph/Node/Blocks/Textures/clearBlock.ts index 8289888efdc..c87693cad27 100644 --- a/packages/dev/core/src/FrameGraph/Node/Blocks/Textures/clearBlock.ts +++ b/packages/dev/core/src/FrameGraph/Node/Blocks/Textures/clearBlock.ts @@ -135,8 +135,8 @@ export class NodeRenderGraphClearBlock extends NodeRenderGraphBlock { protected override _buildBlock(state: NodeRenderGraphBuildState) { super._buildBlock(state); - this._propagateInputValueToOutput(this.target, this.output); - this._propagateInputValueToOutput(this.depth, this.outputDepth); + this.output.value = this._frameGraphTask.outputTexture; + this.outputDepth.value = this._frameGraphTask.outputDepthTexture; this._frameGraphTask.targetTexture = this.target.connectedPoint?.value as FrameGraphTextureHandle; this._frameGraphTask.depthTexture = this.depth.connectedPoint?.value as FrameGraphTextureHandle; diff --git a/packages/dev/core/src/FrameGraph/Node/Blocks/Textures/generateMipmapsBlock.ts b/packages/dev/core/src/FrameGraph/Node/Blocks/Textures/generateMipmapsBlock.ts index 49b747764e1..442cafa74e5 100644 --- a/packages/dev/core/src/FrameGraph/Node/Blocks/Textures/generateMipmapsBlock.ts +++ b/packages/dev/core/src/FrameGraph/Node/Blocks/Textures/generateMipmapsBlock.ts @@ -60,7 +60,7 @@ export class NodeRenderGraphGenerateMipmapsBlock extends NodeRenderGraphBlock { protected override _buildBlock(state: NodeRenderGraphBuildState) { super._buildBlock(state); - this._propagateInputValueToOutput(this.target, this.output); + this.output.value = this._frameGraphTask.outputTexture; this._frameGraphTask.targetTexture = this.target.connectedPoint?.value as FrameGraphTextureHandle; } diff --git a/packages/dev/core/src/FrameGraph/Node/nodeRenderGraph.ts b/packages/dev/core/src/FrameGraph/Node/nodeRenderGraph.ts index f23f583ac6a..eba70aeaa27 100644 --- a/packages/dev/core/src/FrameGraph/Node/nodeRenderGraph.ts +++ b/packages/dev/core/src/FrameGraph/Node/nodeRenderGraph.ts @@ -162,8 +162,10 @@ export class NodeRenderGraph { this._frameGraph.name = name; if (options.rebuildGraphOnEngineResize) { - this._resizeObserver = this._engine.onResizeObservable.add(() => { + this._resizeObserver = this._engine.onResizeObservable.add(async () => { this.build(); + + await this.whenReadyAsync(); }); } } diff --git a/packages/dev/core/src/FrameGraph/Passes/cullPass.ts b/packages/dev/core/src/FrameGraph/Passes/objectListPass.ts similarity index 62% rename from packages/dev/core/src/FrameGraph/Passes/cullPass.ts rename to packages/dev/core/src/FrameGraph/Passes/objectListPass.ts index 504b40885d5..70e2ddeb8ea 100644 --- a/packages/dev/core/src/FrameGraph/Passes/cullPass.ts +++ b/packages/dev/core/src/FrameGraph/Passes/objectListPass.ts @@ -2,31 +2,31 @@ import type { Nullable, AbstractEngine, IFrameGraphPass, FrameGraphContext, Fram import { FrameGraphPass } from "./pass"; /** - * Cull pass used to filter objects that are not visible. + * Object list pass used to generate a list of objects. */ -export class FrameGraphCullPass extends FrameGraphPass { +export class FrameGraphObjectListPass extends FrameGraphPass { protected readonly _engine: AbstractEngine; protected _objectList: FrameGraphObjectList; /** - * Checks if a pass is a cull pass. + * Checks if a pass is an object list pass. * @param pass The pass to check. - * @returns True if the pass is a cull pass, else false. + * @returns True if the pass is an object list pass, else false. */ - public static IsCullPass(pass: IFrameGraphPass): pass is FrameGraphCullPass { - return (pass as FrameGraphCullPass).setObjectList !== undefined; + public static IsObjectListPass(pass: IFrameGraphPass): pass is FrameGraphObjectListPass { + return (pass as FrameGraphObjectListPass).setObjectList !== undefined; } /** - * Gets the object list used by the cull pass. + * Gets the object list used by the pass. */ public get objectList(): FrameGraphObjectList { return this._objectList; } /** - * Sets the object list to use for culling. - * @param objectList The object list to use for culling. + * Sets the object list to use for the pass. + * @param objectList The object list to use for the pass. */ public setObjectList(objectList: FrameGraphObjectList) { this._objectList = objectList; diff --git a/packages/dev/core/src/FrameGraph/Passes/renderPass.ts b/packages/dev/core/src/FrameGraph/Passes/renderPass.ts index 4997a1b2d05..723d74b344e 100644 --- a/packages/dev/core/src/FrameGraph/Passes/renderPass.ts +++ b/packages/dev/core/src/FrameGraph/Passes/renderPass.ts @@ -21,19 +21,26 @@ export class FrameGraphRenderPass extends FrameGraphPass { @@ -82,7 +82,7 @@ export class FrameGraphCullObjectsTask extends FrameGraphTask { } }); - const passDisabled = this._frameGraph.addCullPass(this.name + "_disabled", true); + const passDisabled = this._frameGraph.addObjectListPass(this.name + "_disabled", true); passDisabled.setObjectList(this.outputObjectList); passDisabled.setExecuteFunc((_context) => { diff --git a/packages/dev/core/src/FrameGraph/Tasks/Rendering/geometryRendererTask.ts b/packages/dev/core/src/FrameGraph/Tasks/Rendering/geometryRendererTask.ts index 108b582fa26..2cd8fe30caf 100644 --- a/packages/dev/core/src/FrameGraph/Tasks/Rendering/geometryRendererTask.ts +++ b/packages/dev/core/src/FrameGraph/Tasks/Rendering/geometryRendererTask.ts @@ -115,6 +115,16 @@ export class FrameGraphGeometryRendererTask extends FrameGraphTask { */ public dontRenderWhenMaterialDepthWriteIsDisabled = true; + /** + * If true, the output geometry texture(s) will be resolved at the end of the render pass, if samples is greater than 1 (default: true) + */ + public resolveMSAAColors = true; + + /** + * If true, depthTexture will be resolved at the end of the render pass, if this texture is provided and samples is greater than 1 (default: true) + */ + public resolveMSAADepth = false; + /** * The list of texture descriptions used by the geometry renderer task. */ @@ -403,6 +413,9 @@ export class FrameGraphGeometryRendererTask extends FrameGraphTask { this._renderer.renderList = this.objectList.meshes; this._renderer.particleSystemList = this.objectList.particleSystems; + pass.frameGraphRenderTarget!.renderTargetWrapper!.resolveMSAAColors = this.resolveMSAAColors; + pass.frameGraphRenderTarget!.renderTargetWrapper!.resolveMSAADepth = this.resolveMSAADepth; + context.setDepthStates(this.depthTest && depthEnabled, this.depthWrite && depthEnabled); this._clearAttachmentsLayout.forEach((layout, clearType) => { diff --git a/packages/dev/core/src/FrameGraph/Tasks/Rendering/objectRendererTask.ts b/packages/dev/core/src/FrameGraph/Tasks/Rendering/objectRendererTask.ts index 99328783dd2..f254e678156 100644 --- a/packages/dev/core/src/FrameGraph/Tasks/Rendering/objectRendererTask.ts +++ b/packages/dev/core/src/FrameGraph/Tasks/Rendering/objectRendererTask.ts @@ -185,6 +185,16 @@ export class FrameGraphObjectRendererTask extends FrameGraphTask { this._renderer.enableOutlineRendering = value; } + /** + * If true, targetTexture will be resolved at the end of the render pass, if this/these texture(s) is/are MSAA (default: true) + */ + public resolveMSAAColors = true; + + /** + * If true, depthTexture will be resolved at the end of the render pass, if this texture is provided and is MSAA (default: false). + */ + public resolveMSAADepth = false; + /** * The output texture. * This texture will point to the same texture than the targetTexture property. @@ -318,6 +328,12 @@ export class FrameGraphObjectRendererTask extends FrameGraphTask { this._renderer.renderList = this.objectList.meshes; this._renderer.particleSystemList = this.objectList.particleSystems; + const renderTargetWrapper = pass.frameGraphRenderTarget!.renderTargetWrapper; + if (renderTargetWrapper) { + renderTargetWrapper.resolveMSAAColors = this.resolveMSAAColors; + renderTargetWrapper.resolveMSAADepth = this.resolveMSAADepth; + } + // The cast to "any" is to avoid an error in ES6 in case you don't import boundingBoxRenderer const boundingBoxRenderer = (this as any).getBoundingBoxRenderer?.() as Nullable; diff --git a/packages/dev/core/src/FrameGraph/Tasks/Texture/clearTextureTask.ts b/packages/dev/core/src/FrameGraph/Tasks/Texture/clearTextureTask.ts index 15e76884586..0177f90aca1 100644 --- a/packages/dev/core/src/FrameGraph/Tasks/Texture/clearTextureTask.ts +++ b/packages/dev/core/src/FrameGraph/Tasks/Texture/clearTextureTask.ts @@ -69,7 +69,7 @@ export class FrameGraphClearTextureTask extends FrameGraphTask { this.outputDepthTexture = this._frameGraph.textureManager.createDanglingHandle(); } - public record(): FrameGraphRenderPass { + public record(skipCreationOfDisabledPasses = false): FrameGraphRenderPass { if (this.targetTexture === undefined && this.depthTexture === undefined) { throw new Error(`FrameGraphClearTextureTask ${this.name}: targetTexture and depthTexture can't both be undefined.`); } @@ -112,11 +112,13 @@ export class FrameGraphClearTextureTask extends FrameGraphTask { context.clearAttachments(color, attachments, !!this.clearColor, !!this.clearDepth, !!this.clearStencil, this.stencilValue); }); - const passDisabled = this._frameGraph.addRenderPass(this.name + "_disabled", true); + if (!skipCreationOfDisabledPasses) { + const passDisabled = this._frameGraph.addRenderPass(this.name + "_disabled", true); - passDisabled.setRenderTarget(targetTextures); - passDisabled.setRenderTargetDepth(this.depthTexture); - passDisabled.setExecuteFunc((_context) => {}); + passDisabled.setRenderTarget(targetTextures); + passDisabled.setRenderTargetDepth(this.depthTexture); + passDisabled.setExecuteFunc((_context) => {}); + } return pass; } diff --git a/packages/dev/core/src/FrameGraph/frameGraph.ts b/packages/dev/core/src/FrameGraph/frameGraph.ts index e435b931074..61c20d8b08b 100644 --- a/packages/dev/core/src/FrameGraph/frameGraph.ts +++ b/packages/dev/core/src/FrameGraph/frameGraph.ts @@ -1,7 +1,7 @@ import type { Scene, AbstractEngine, FrameGraphTask, Nullable, NodeRenderGraph, IDisposable } from "core/index"; import { FrameGraphPass } from "./Passes/pass"; import { FrameGraphRenderPass } from "./Passes/renderPass"; -import { FrameGraphCullPass } from "./Passes/cullPass"; +import { FrameGraphObjectListPass } from "./Passes/objectListPass"; import { FrameGraphRenderContext } from "./frameGraphRenderContext"; import { FrameGraphContext } from "./frameGraphContext"; import { FrameGraphTextureManager } from "./frameGraphTextureManager"; @@ -16,7 +16,7 @@ import "core/Engines/WebGPU/Extensions/engine.multiRender"; enum FrameGraphPassType { Normal = 0, Render = 1, - Cull = 2, + ObjectList = 2, } /** @@ -170,13 +170,13 @@ export class FrameGraph implements IDisposable { } /** - * Adds a cull pass to a task. This method can only be called during a Task.record execution. + * Adds an object list pass to a task. This method can only be called during a Task.record execution. * @param name The name of the pass * @param whenTaskDisabled If true, the pass will be added to the list of passes to execute when the task is disabled (default is false) - * @returns The cull pass created + * @returns The object list pass created */ - public addCullPass(name: string, whenTaskDisabled = false): FrameGraphCullPass { - return this._addPass(name, FrameGraphPassType.Cull, whenTaskDisabled) as FrameGraphCullPass; + public addObjectListPass(name: string, whenTaskDisabled = false): FrameGraphObjectListPass { + return this._addPass(name, FrameGraphPassType.ObjectList, whenTaskDisabled) as FrameGraphObjectListPass; } private _addPass(name: string, passType: FrameGraphPassType, whenTaskDisabled = false): FrameGraphPass | FrameGraphRenderPass { @@ -190,8 +190,8 @@ export class FrameGraph implements IDisposable { case FrameGraphPassType.Render: pass = new FrameGraphRenderPass(name, this._currentProcessedTask, this._renderContext, this._engine); break; - case FrameGraphPassType.Cull: - pass = new FrameGraphCullPass(name, this._currentProcessedTask, this._passContext, this._engine); + case FrameGraphPassType.ObjectList: + pass = new FrameGraphObjectListPass(name, this._currentProcessedTask, this._passContext, this._engine); break; default: pass = new FrameGraphPass(name, this._currentProcessedTask, this._passContext); @@ -242,6 +242,19 @@ export class FrameGraph implements IDisposable { } } + /** + * Checks if the frame graph is ready to be executed. + * Note that you can use the whenReadyAsync method to wait for the frame graph to be ready. + * @returns True if the frame graph is ready to be executed, else false + */ + public isReady(): boolean { + let ready = this._renderContext._isReady(); + for (const task of this._tasks) { + ready &&= task.isReady(); + } + return ready; + } + /** * Returns a promise that resolves when the frame graph is ready to be executed * This method must be called after the graph has been built (FrameGraph.build called)! @@ -251,7 +264,7 @@ export class FrameGraph implements IDisposable { */ public async whenReadyAsync(timeStep = 16, maxTimeout = 5000): Promise { let firstNotReadyTask: FrameGraphTask | null = null; - return await new Promise((resolve) => { + return await new Promise((resolve, reject) => { this._whenReadyAsyncCancel = _RetryWithInterval( () => { let ready = this._renderContext._isReady(); @@ -286,6 +299,7 @@ export class FrameGraph implements IDisposable { Logger.Error(err); } } + reject(new Error(err)); }, timeStep, maxTimeout diff --git a/packages/dev/core/src/FrameGraph/frameGraphTask.ts b/packages/dev/core/src/FrameGraph/frameGraphTask.ts index 9bb5676c9d1..a27f3834247 100644 --- a/packages/dev/core/src/FrameGraph/frameGraphTask.ts +++ b/packages/dev/core/src/FrameGraph/frameGraphTask.ts @@ -1,5 +1,5 @@ import type { FrameGraph, FrameGraphObjectList, IFrameGraphPass, Nullable, FrameGraphTextureHandle, InternalTexture, FrameGraphRenderContext } from "core/index"; -import { FrameGraphCullPass } from "./Passes/cullPass"; +import { FrameGraphObjectListPass } from "./Passes/objectListPass"; import { FrameGraphRenderPass } from "./Passes/renderPass"; import { Observable } from "core/Misc/observable"; @@ -145,7 +145,7 @@ export abstract class FrameGraphTask { } } outputDepthTexture = pass.renderTargetDepth !== undefined ? this._frameGraph.textureManager.getTextureFromHandle(pass.renderTargetDepth) : null; - } else if (FrameGraphCullPass.IsCullPass(pass)) { + } else if (FrameGraphObjectListPass.IsObjectListPass(pass)) { outputObjectList = pass.objectList; } } @@ -170,7 +170,7 @@ export abstract class FrameGraphTask { } disabledOutputTextureHandle = handles; disabledOutputDepthTexture = pass.renderTargetDepth !== undefined ? this._frameGraph.textureManager.getTextureFromHandle(pass.renderTargetDepth) : null; - } else if (FrameGraphCullPass.IsCullPass(pass)) { + } else if (FrameGraphObjectListPass.IsObjectListPass(pass)) { disabledOutputObjectList = pass.objectList; } } diff --git a/packages/dev/core/src/FrameGraph/index.ts b/packages/dev/core/src/FrameGraph/index.ts index 8aefdb085b9..d569d5dce12 100644 --- a/packages/dev/core/src/FrameGraph/index.ts +++ b/packages/dev/core/src/FrameGraph/index.ts @@ -6,7 +6,7 @@ export * from "./Node/nodeRenderGraphBuildState"; export * from "./Node/Types/nodeRenderGraphTypes"; export * from "./Node/Blocks/index"; -export * from "./Passes/cullPass"; +export * from "./Passes/objectListPass"; export * from "./Passes/pass"; export * from "./Passes/renderPass"; diff --git a/packages/dev/core/src/Materials/shaderMaterial.ts b/packages/dev/core/src/Materials/shaderMaterial.ts index 4efd1180e7e..25e29068690 100644 --- a/packages/dev/core/src/Materials/shaderMaterial.ts +++ b/packages/dev/core/src/Materials/shaderMaterial.ts @@ -34,6 +34,7 @@ import { PushAttributesForInstances, } from "./materialHelper.functions"; import type { IColor3Like, IColor4Like, IVector2Like, IVector3Like, IVector4Like } from "core/Maths/math.like"; +import type { InternalTexture } from "./Textures/internalTexture"; const OnCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; @@ -118,6 +119,7 @@ export class ShaderMaterial extends PushMaterial { private _shaderPath: IShaderPath | string; private _options: IShaderMaterialOptions; private _textures: { [name: string]: BaseTexture } = {}; + private _internalTextures: { [name: string]: InternalTexture } = {}; private _textureArrays: { [name: string]: BaseTexture[] } = {}; private _externalTextures: { [name: string]: ExternalTexture } = {}; private _floats: { [name: string]: number } = {}; @@ -266,6 +268,21 @@ export class ShaderMaterial extends PushMaterial { return this; } + /** + * Set an internal texture in the shader. + * @param name Define the name of the uniform samplers as defined in the shader + * @param texture Define the texture to bind to this sampler + * @returns the material itself allowing "fluent" like uniform updates + */ + public setInternalTexture(name: string, texture: InternalTexture): ShaderMaterial { + if (this._options.samplers.indexOf(name) === -1) { + this._options.samplers.push(name); + } + this._internalTextures[name] = texture; + + return this; + } + /** * Remove a texture from the material. * @param name Define the name of the texture to remove @@ -839,6 +856,12 @@ export class ShaderMaterial extends PushMaterial { } } + for (const name in this._internalTextures) { + if (!this._internalTextures[name].isReady) { + return false; + } + } + // Alpha test if (mesh && this.needAlphaTestingForMesh(mesh)) { defines.push("#define ALPHATEST"); @@ -1077,6 +1100,10 @@ export class ShaderMaterial extends PushMaterial { effect.setTexture(name, this._textures[name]); } + for (name in this._internalTextures) { + effect._bindTexture(name, this._internalTextures[name]); + } + // Texture arrays for (name in this._textureArrays) { effect.setTextureArray(name, this._textureArrays[name]); @@ -1273,6 +1300,13 @@ export class ShaderMaterial extends PushMaterial { } } + const internalTexture = texture.getInternalTexture(); + for (const name in this._internalTextures) { + if (this._internalTextures[name] === internalTexture) { + return true; + } + } + for (const name in this._textureArrays) { const array = this._textureArrays[name]; for (let index = 0; index < array.length; index++) { @@ -1321,6 +1355,10 @@ export class ShaderMaterial extends PushMaterial { result.setTexture(key, this._textures[key]); } + for (const key in this._internalTextures) { + result.setInternalTexture(key, this._internalTextures[key]); + } + // TextureArray for (const key in this._textureArrays) { result.setTextureArray(key, this._textureArrays[key]); @@ -1461,6 +1499,9 @@ export class ShaderMaterial extends PushMaterial { for (name in this._textures) { this._textures[name].dispose(); } + for (name in this._internalTextures) { + this._internalTextures[name].dispose(); + } for (name in this._textureArrays) { const array = this._textureArrays[name]; @@ -1471,6 +1512,7 @@ export class ShaderMaterial extends PushMaterial { } this._textures = {}; + this._internalTextures = {}; super.dispose(forceDisposeEffect, forceDisposeTextures, notBoundToMesh); } diff --git a/packages/tools/nodeRenderGraphEditor/src/graphSystem/properties/genericNodePropertyComponent.tsx b/packages/tools/nodeRenderGraphEditor/src/graphSystem/properties/genericNodePropertyComponent.tsx index 4e600bfa081..5ea35f2f96b 100644 --- a/packages/tools/nodeRenderGraphEditor/src/graphSystem/properties/genericNodePropertyComponent.tsx +++ b/packages/tools/nodeRenderGraphEditor/src/graphSystem/properties/genericNodePropertyComponent.tsx @@ -12,11 +12,11 @@ import { SliderLineComponent } from "shared-ui-components/lines/sliderLineCompon import { Color4LineComponent } from "shared-ui-components/lines/color4LineComponent"; import { MatrixLineComponent } from "shared-ui-components/lines/matrixLineComponent"; import type { NodeRenderGraphBlock } from "core/FrameGraph/Node/nodeRenderGraphBlock"; -import type { IEditablePropertyListOption } from "core/Decorators/nodeDecorator"; -import type { IPropertyDescriptionForEdition } from "core/Decorators/nodeDecorator"; +import type { IEditablePropertyListOption, IPropertyDescriptionForEdition } from "core/Decorators/nodeDecorator"; import { PropertyTypeForEdition } from "core/Decorators/nodeDecorator"; import { Constants } from "core/Engines/constants"; import { ForceRebuild } from "shared-ui-components/nodeGraphSystem/automaticProperties"; +import { Color3LineComponent } from "shared-ui-components/lines/color3LineComponent"; // eslint-disable-next-line @typescript-eslint/naming-convention export const samplingModeList = [ @@ -282,6 +282,19 @@ export class GenericPropertyTabComponent extends React.Component ForceRebuild(block, this.props.stateManager, propertyName, options.notifiers)} + /> + ); + break; + } case PropertyTypeForEdition.Color4: { components.push(