From 10dc64a48a1d407f13dfa2d74306f5227ce490c4 Mon Sep 17 00:00:00 2001 From: David Catuhe Date: Wed, 18 Sep 2024 18:10:50 -0700 Subject: [PATCH 1/8] Initial loop components --- .../core/src/Materials/Node/Blocks/index.ts | 3 + .../src/Materials/Node/Blocks/loopBlock.ts | 119 ++++++++++++++++++ .../Materials/Node/Blocks/storageReadBlock.ts | 65 ++++++++++ .../Node/Blocks/storageWriteBlock.ts | 65 ++++++++++ .../core/src/Materials/Node/nodeMaterial.ts | 57 +++++++-- .../src/Materials/Node/nodeMaterialBlock.ts | 56 ++++++++- .../Node/nodeMaterialBlockConnectionPoint.ts | 12 ++ .../Materials/Node/nodeMaterialBuildState.ts | 4 + packages/tools/nodeEditor/src/blockTools.ts | 9 ++ .../components/nodeList/nodeListComponent.tsx | 4 + 10 files changed, 378 insertions(+), 16 deletions(-) create mode 100644 packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts create mode 100644 packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts create mode 100644 packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts diff --git a/packages/dev/core/src/Materials/Node/Blocks/index.ts b/packages/dev/core/src/Materials/Node/Blocks/index.ts index bd7589e3fe7..bacf06c8eed 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/index.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/index.ts @@ -63,3 +63,6 @@ export * from "./matrixTransposeBlock"; export * from "./meshAttributeExistsBlock"; export * from "./curveBlock"; export * from "./colorConverterBlock"; +export * from "./loopBlock"; +export * from "./storageReadBlock"; +export * from "./storageWriteBlock"; diff --git a/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts new file mode 100644 index 00000000000..69647e2e00c --- /dev/null +++ b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts @@ -0,0 +1,119 @@ +import { NodeMaterialBlock } from "../nodeMaterialBlock"; +import { NodeMaterialBlockConnectionPointTypes } from "../Enums/nodeMaterialBlockConnectionPointTypes"; +import type { NodeMaterialBuildState } from "../nodeMaterialBuildState"; +import type { NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; +import { NodeMaterialBlockTargets } from "../Enums/nodeMaterialBlockTargets"; +import { RegisterClass } from "../../../Misc/typeStore"; +import { editableInPropertyPage, PropertyTypeForEdition } from "core/Decorators/nodeDecorator"; +import type { Scene } from "core/scene"; +import { ShaderLanguage } from "core/Materials/shaderLanguage"; +/** + * Block used to repeat code + */ +export class LoopBlock extends NodeMaterialBlock { + /** + * Gets or sets the source range + */ + @editableInPropertyPage("Iterations", PropertyTypeForEdition.Int) + public iterations = 4; + + /** + * Creates a new LoopBlock + * @param name defines the block name + */ + public constructor(name: string) { + super(name, NodeMaterialBlockTargets.Neutral); + + this.registerInput("input", NodeMaterialBlockConnectionPointTypes.AutoDetect); + this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.BasedOnInput); + this.registerOutput("index", NodeMaterialBlockConnectionPointTypes.Int); + this.registerOutput("loopID", NodeMaterialBlockConnectionPointTypes.Object); + + this._outputs[0]._typeConnectionSource = this._inputs[0]; + this._outputs[0]._forPostBuild = true; + + this._outputs[2]._redirectedSource = this._inputs[0]; + } + + /** + * Gets the current class name + * @returns the class name + */ + public override getClassName() { + return "LoopBlock"; + } + + /** + * Gets the main input component + */ + public get input(): NodeMaterialConnectionPoint { + return this._inputs[0]; + } + + /** + * Gets the output component + */ + public get output(): NodeMaterialConnectionPoint { + return this._outputs[0]; + } + + /** + * Gets the index component which will be incremented at each iteration + */ + public get index(): NodeMaterialConnectionPoint { + return this._outputs[1]; + } + + /** + * Gets the loop ID component + */ + public get loopID(): NodeMaterialConnectionPoint { + return this._outputs[2]; + } + + protected override _buildBlock(state: NodeMaterialBuildState) { + super._buildBlock(state); + + const output = this._outputs[0]; + + const indexName = state._getFreeVariableName("index"); + + const decl = state.shaderLanguage === ShaderLanguage.WGSL ? "var" : "int"; + + // Declare storage variable and store initial value + state.compilationString += state._declareOutput(output) + ` = ${this.input.associatedVariableName};\n`; + + // Loop + state.compilationString += `for (${decl} ${indexName} = 0; ${indexName} < ${this.iterations}; ${indexName}++){\n`; + + return this; + } + + protected override _postBuildBlock(state: NodeMaterialBuildState) { + super._postBuildBlock(state); + + state.compilationString += `}\n`; + + return this; + } + + protected override _dumpPropertiesCode() { + return super._dumpPropertiesCode() + `${this._codeVariableName}.iterations = ${this.iterations};\n`; + } + + public override serialize(): any { + const serializationObject = super.serialize(); + + serializationObject.iterations = this.iterations; + + return serializationObject; + } + + public override _deserialize(serializationObject: any, scene: Scene, rootUrl: string) { + super._deserialize(serializationObject, scene, rootUrl); + + this.iterations = serializationObject.iterations; + } +} + +RegisterClass("BABYLON.LoopBlock", LoopBlock); diff --git a/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts new file mode 100644 index 00000000000..25a096aeb4a --- /dev/null +++ b/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts @@ -0,0 +1,65 @@ +import { NodeMaterialBlock } from "../nodeMaterialBlock"; +import { NodeMaterialBlockConnectionPointTypes } from "../Enums/nodeMaterialBlockConnectionPointTypes"; +import type { NodeMaterialBuildState } from "../nodeMaterialBuildState"; +import type { NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; +import { NodeMaterialBlockTargets } from "../Enums/nodeMaterialBlockTargets"; +import { RegisterClass } from "../../../Misc/typeStore"; +import type { LoopBlock } from "./loopBlock"; +/** + * Block used to read from a variable within a loop + */ +export class StorageReadBlock extends NodeMaterialBlock { + /** + * Creates a new StorageReadBlock + * @param name defines the block name + */ + public constructor(name: string) { + super(name, NodeMaterialBlockTargets.Neutral); + + this.registerInput("loopID", NodeMaterialBlockConnectionPointTypes.Object); + this.registerOutput("value", NodeMaterialBlockConnectionPointTypes.AutoDetect); + + this._outputs[0]._linkedConnectionSource = this._inputs[0]; + this._inputs[0]._preventBubbleUp = true; + } + + /** + * Gets the current class name + * @returns the class name + */ + public override getClassName() { + return "StorageReadBlock"; + } + + /** + * Gets the loop link component + */ + public get loopID(): NodeMaterialConnectionPoint { + return this._inputs[0]; + } + + /** + * Gets the value component + */ + public get value(): NodeMaterialConnectionPoint { + return this._outputs[0]; + } + + protected override _buildBlock(state: NodeMaterialBuildState) { + super._buildBlock(state); + + const value = this._outputs[0]; + + if (!this.loopID.isConnected) { + return this; + } + + const loopBlock = this.loopID.connectedPoint!.ownerBlock as LoopBlock; + + state.compilationString += state._declareOutput(value) + ` = ${loopBlock.output.associatedVariableName};\n`; + + return this; + } +} + +RegisterClass("BABYLON.StorageReadBlock", StorageReadBlock); diff --git a/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts new file mode 100644 index 00000000000..55c2b01a8bb --- /dev/null +++ b/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts @@ -0,0 +1,65 @@ +import { NodeMaterialBlock } from "../nodeMaterialBlock"; +import { NodeMaterialBlockConnectionPointTypes } from "../Enums/nodeMaterialBlockConnectionPointTypes"; +import type { NodeMaterialBuildState } from "../nodeMaterialBuildState"; +import type { NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; +import { NodeMaterialBlockTargets } from "../Enums/nodeMaterialBlockTargets"; +import { RegisterClass } from "../../../Misc/typeStore"; +import type { LoopBlock } from "./loopBlock"; +/** + * Block used to write to a variable within a loop + */ +export class StorageWriteBlock extends NodeMaterialBlock { + /** + * Creates a new StorageWriteBlock + * @param name defines the block name + */ + public constructor(name: string) { + super(name, NodeMaterialBlockTargets.Neutral); + + this.registerInput("loopID", NodeMaterialBlockConnectionPointTypes.Object); + this.registerInput("value", NodeMaterialBlockConnectionPointTypes.AutoDetect); + + this._linkConnectionTypes(0, 1); + this._inputs[0]._preventBubbleUp = true; + } + + /** + * Gets the current class name + * @returns the class name + */ + public override getClassName() { + return "StorageWriteBlock"; + } + + /** + * Gets the loop link component + */ + public get loopID(): NodeMaterialConnectionPoint { + return this._inputs[0]; + } + + /** + * Gets the value component + */ + public get value(): NodeMaterialConnectionPoint { + return this._inputs[1]; + } + + protected override _buildBlock(state: NodeMaterialBuildState) { + super._buildBlock(state); + + const value = this._inputs[1]; + + if (!this.loopID.isConnected) { + return this; + } + + const loopBlock = this.loopID.connectedPoint!.ownerBlock as LoopBlock; + + state.compilationString += `${loopBlock.output.associatedVariableName} = ${value.associatedVariableName};\n`; + + return this; + } +} + +RegisterClass("BABYLON.StorageWriteBlock", StorageWriteBlock); diff --git a/packages/dev/core/src/Materials/Node/nodeMaterial.ts b/packages/dev/core/src/Materials/Node/nodeMaterial.ts index f6116f18cc8..8a3d38f6b0b 100644 --- a/packages/dev/core/src/Materials/Node/nodeMaterial.ts +++ b/packages/dev/core/src/Materials/Node/nodeMaterial.ts @@ -69,6 +69,7 @@ import { PrepareDefinesForCamera, PrepareDefinesForPrePass } from "../materialHe import type { IImageProcessingConfigurationDefines } from "../imageProcessingConfiguration.defines"; import { ShaderLanguage } from "../shaderLanguage"; import { AbstractEngine } from "../../Engines/abstractEngine"; +import type { LoopBlock } from "./Blocks/loopBlock"; const onCreatedEffectParameters = { effect: null as unknown as Effect, subMesh: null as unknown as Nullable }; @@ -727,13 +728,7 @@ export class NodeMaterial extends PushMaterial { this._initializeBlock(block, state, nodesToProcessForOtherBuildState, autoConfigure); } - private _initializeBlock(node: NodeMaterialBlock, state: NodeMaterialBuildState, nodesToProcessForOtherBuildState: NodeMaterialBlock[], autoConfigure = true) { - node.initialize(state); - if (autoConfigure) { - node.autoConfigure(this); - } - node._preparationId = this._buildId; - + private _attachBlock(node: NodeMaterialBlock) { if (this.attachedBlocks.indexOf(node) === -1) { if (node.isUnique) { const className = node.getClassName(); @@ -747,12 +742,22 @@ export class NodeMaterial extends PushMaterial { } this.attachedBlocks.push(node); } + } + + private _initializeBlock(node: NodeMaterialBlock, state: NodeMaterialBuildState, nodesToProcessForOtherBuildState: NodeMaterialBlock[], autoConfigure = true) { + node.initialize(state); + if (autoConfigure) { + node.autoConfigure(this); + } + node._preparationId = this._buildId; + + this._attachBlock(node); for (const input of node.inputs) { input.associatedVariableName = ""; const connectedPoint = input.connectedPoint; - if (connectedPoint) { + if (connectedPoint && !input._preventBubbleUp) { const block = connectedPoint.ownerBlock; if (block !== node) { this._processInitializeOnLink(block, state, nodesToProcessForOtherBuildState, autoConfigure); @@ -760,8 +765,22 @@ export class NodeMaterial extends PushMaterial { } } - // Teleportation - if (node.isTeleportOut) { + // Loop + if (node.isLoop) { + // We need to keep the storage write block in the active blocks + const loopBlock = node as LoopBlock; + if (loopBlock.loopID.hasEndpoints) { + for (const endpoint of loopBlock.loopID.endpoints) { + const block = endpoint.ownerBlock; + if (block.outputs.length !== 0) { + continue; + } + state._terminalBlocks.add(block); // Attach the storage write only + this._processInitializeOnLink(block, state, nodesToProcessForOtherBuildState, autoConfigure); + } + } + } else if (node.isTeleportOut) { + // Teleportation const teleport = node as NodeMaterialTeleportOutBlock; if (teleport.entryPoint) { this._processInitializeOnLink(teleport.entryPoint, state, nodesToProcessForOtherBuildState, autoConfigure); @@ -778,9 +797,9 @@ export class NodeMaterial extends PushMaterial { node.buildId = id; } - for (const inputs of node.inputs) { - const connectedPoint = inputs.connectedPoint; - if (connectedPoint) { + for (const input of node.inputs) { + const connectedPoint = input.connectedPoint; + if (connectedPoint && !input._preventBubbleUp) { const block = connectedPoint.ownerBlock; if (block !== node) { this._resetDualBlocks(block, id); @@ -794,6 +813,18 @@ export class NodeMaterial extends PushMaterial { if (teleportOut.entryPoint) { this._resetDualBlocks(teleportOut.entryPoint, id); } + } else if (node.isLoop) { + // Loop + const loopBlock = node as LoopBlock; + if (loopBlock.loopID.hasEndpoints) { + for (const endpoint of loopBlock.loopID.endpoints) { + const block = endpoint.ownerBlock; + if (block.outputs.length !== 0) { + continue; + } + this._resetDualBlocks(block, id); + } + } } } diff --git a/packages/dev/core/src/Materials/Node/nodeMaterialBlock.ts b/packages/dev/core/src/Materials/Node/nodeMaterialBlock.ts index 4bf0f979730..ace30308516 100644 --- a/packages/dev/core/src/Materials/Node/nodeMaterialBlock.ts +++ b/packages/dev/core/src/Materials/Node/nodeMaterialBlock.ts @@ -26,6 +26,7 @@ export class NodeMaterialBlock { protected _target: NodeMaterialBlockTargets; private _isFinalMerger = false; private _isInput = false; + private _isLoop = false; private _isTeleportOut = false; private _isTeleportIn = false; private _name = ""; @@ -124,6 +125,13 @@ export class NodeMaterialBlock { return this._isTeleportIn; } + /** + * Gets a boolean indicating if this block is a loop + */ + public get isLoop(): boolean { + return this._isLoop; + } + /** * Gets or sets the build Id */ @@ -207,9 +215,21 @@ export class NodeMaterialBlock { this._target = target; this._originalTargetIsNeutral = target === NodeMaterialBlockTargets.Neutral; this._isFinalMerger = isFinalMerger; - this._isInput = this.getClassName() === "InputBlock"; - this._isTeleportOut = this.getClassName() === "NodeMaterialTeleportOutBlock"; - this._isTeleportIn = this.getClassName() === "NodeMaterialTeleportInBlock"; + switch (this.getClassName()) { + case "InputBlock": + this._isInput = true; + break; + case "NodeMaterialTeleportOutBlock": + this._isTeleportOut = true; + break; + case "NodeMaterialTeleportInBlock": + this._isTeleportIn = true; + break; + case "LoopBlock": + this._isLoop = true; + break; + } + this._name = name; this.uniqueId = UniqueIdGenerator.UniqueId; } @@ -440,6 +460,11 @@ export class NodeMaterialBlock { // Empty. Must be defined by child nodes } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected _postBuildBlock(state: NodeMaterialBuildState) { + // Empty. Must be defined by child nodes + } + /** * Add uniforms, samplers and uniform buffers at compilation time * @param state defines the state to update @@ -702,6 +727,31 @@ export class NodeMaterialBlock { // Compile connected blocks for (const output of this._outputs) { + if (output._forPostBuild) { + continue; + } + if ((output.target & state.target) === 0) { + continue; + } + + for (const endpoint of output.endpoints) { + const block = endpoint.ownerBlock; + + if (block) { + if (((block.target & state.target) !== 0 && activeBlocks.indexOf(block) !== -1) || state._terminalBlocks.has(block)) { + this._processBuild(block, state, endpoint, activeBlocks); + } + } + } + } + + this._postBuildBlock(state); + + // Compile post build connected blocks + for (const output of this._outputs) { + if (!output._forPostBuild) { + continue; + } if ((output.target & state.target) === 0) { continue; } diff --git a/packages/dev/core/src/Materials/Node/nodeMaterialBlockConnectionPoint.ts b/packages/dev/core/src/Materials/Node/nodeMaterialBlockConnectionPoint.ts index f338cf90eb3..43a5e19a7ad 100644 --- a/packages/dev/core/src/Materials/Node/nodeMaterialBlockConnectionPoint.ts +++ b/packages/dev/core/src/Materials/Node/nodeMaterialBlockConnectionPoint.ts @@ -71,6 +71,9 @@ export class NodeMaterialConnectionPoint { return false; } + /** @internal */ + public _preventBubbleUp = false; + /** @internal */ public readonly _ownerBlock: NodeMaterialBlock; @@ -99,6 +102,9 @@ export class NodeMaterialConnectionPoint { private _associatedVariableName: string; private readonly _direction: NodeMaterialConnectionPointDirection; + /** @internal */ + public _redirectedSource: Nullable = null; + private _typeConnectionSourceBackingField: Nullable = null; private _typeConnectionSourceTypeChangedObserver: Nullable>; @@ -165,6 +171,9 @@ export class NodeMaterialConnectionPoint { /** @internal */ public _enforceAssociatedVariableName = false; + /** @internal */ + public _forPostBuild = false; + /** Gets the direction of the point */ public get direction() { return this._direction; @@ -255,6 +264,9 @@ export class NodeMaterialConnectionPoint { } if (this._linkedConnectionSource && this._linkedConnectionSource.isConnected) { + if (this._linkedConnectionSource.connectedPoint!._redirectedSource && this._linkedConnectionSource.connectedPoint!._redirectedSource.isConnected) { + return this._linkedConnectionSource.connectedPoint!._redirectedSource.type; + } return this._linkedConnectionSource.type; } } diff --git a/packages/dev/core/src/Materials/Node/nodeMaterialBuildState.ts b/packages/dev/core/src/Materials/Node/nodeMaterialBuildState.ts index b39b1b060e8..37c6b29316c 100644 --- a/packages/dev/core/src/Materials/Node/nodeMaterialBuildState.ts +++ b/packages/dev/core/src/Materials/Node/nodeMaterialBuildState.ts @@ -5,6 +5,7 @@ import { ShaderLanguage } from "../shaderLanguage"; import type { NodeMaterialConnectionPoint } from "./nodeMaterialBlockConnectionPoint"; import { ShaderStore as EngineShaderStore } from "../../Engines/shaderStore"; import { Constants } from "../../Engines/constants"; +import type { NodeMaterialBlock } from "./nodeMaterialBlock"; /** * Class used to store node based material build state @@ -55,6 +56,9 @@ export class NodeMaterialBuildState { */ public sharedData: NodeMaterialBuildStateSharedData; + /** @internal */ + public _terminalBlocks: Set = new Set(); + /** @internal */ public _vertexState: NodeMaterialBuildState; diff --git a/packages/tools/nodeEditor/src/blockTools.ts b/packages/tools/nodeEditor/src/blockTools.ts index c684d410e09..59d57182df6 100644 --- a/packages/tools/nodeEditor/src/blockTools.ts +++ b/packages/tools/nodeEditor/src/blockTools.ts @@ -102,10 +102,19 @@ import { PrePassTextureBlock } from "core/Materials/Node/Blocks/Input/prePassTex import { NodeMaterialTeleportInBlock } from "core/Materials/Node/Blocks/Teleport/teleportInBlock"; import { NodeMaterialTeleportOutBlock } from "core/Materials/Node/Blocks/Teleport/teleportOutBlock"; import { ColorConverterBlock } from "core/Materials/Node/Blocks/colorConverterBlock"; +import { LoopBlock } from "core/Materials/Node/Blocks/loopBlock"; +import { StorageReadBlock } from "core/Materials/Node/Blocks/storageReadBlock"; +import { StorageWriteBlock } from "core/Materials/Node/Blocks/storageWriteBlock"; export class BlockTools { public static GetBlockFromString(data: string, scene: Scene, nodeMaterial: NodeMaterial) { switch (data) { + case "StorageWriteBlock": + return new StorageWriteBlock("StorageWrite"); + case "StorageReadBlock": + return new StorageReadBlock("StorageRead"); + case "LoopBlock": + return new LoopBlock("Loop"); case "ColorConverterBlock": return new ColorConverterBlock("ColorConverter"); case "TeleportInBlock": diff --git a/packages/tools/nodeEditor/src/components/nodeList/nodeListComponent.tsx b/packages/tools/nodeEditor/src/components/nodeList/nodeListComponent.tsx index 7e49209c43e..5be813d60ee 100644 --- a/packages/tools/nodeEditor/src/components/nodeList/nodeListComponent.tsx +++ b/packages/tools/nodeEditor/src/components/nodeList/nodeListComponent.tsx @@ -187,6 +187,9 @@ export class NodeListComponent extends React.Component Date: Thu, 19 Sep 2024 09:07:47 -0700 Subject: [PATCH 2/8] Loop done --- .../Node/Blocks/Dual/imageSourceBlock.ts | 21 ++++++ .../Node/Blocks/Dual/textureBlock.ts | 67 ++++++++++++------- .../src/Materials/Node/Blocks/loopBlock.ts | 32 +++++++-- .../Materials/Node/Blocks/storageReadBlock.ts | 14 ++-- .../Node/Blocks/storageWriteBlock.ts | 26 +++++-- .../core/src/Materials/Node/nodeMaterial.ts | 5 +- .../graphSystem/display/loopDisplayManager.ts | 22 ++++++ .../graphSystem/registerToDisplayLedger.ts | 2 + 8 files changed, 149 insertions(+), 40 deletions(-) create mode 100644 packages/tools/nodeEditor/src/graphSystem/display/loopDisplayManager.ts diff --git a/packages/dev/core/src/Materials/Node/Blocks/Dual/imageSourceBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/Dual/imageSourceBlock.ts index 034670ad7db..fe1952d3ef2 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/Dual/imageSourceBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/Dual/imageSourceBlock.ts @@ -13,6 +13,7 @@ import { NodeMaterial } from "../../nodeMaterial"; import type { Scene } from "../../../../scene"; import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject"; import { EngineStore } from "../../../../Engines/engineStore"; +import { ShaderLanguage } from "core/Materials/shaderLanguage"; /** * Block used to provide an image for a TextureBlock */ @@ -68,6 +69,8 @@ export class ImageSourceBlock extends NodeMaterialBlock { NodeMaterialBlockTargets.VertexAndFragment, new NodeMaterialConnectionPointCustomObject("source", this, NodeMaterialConnectionPointDirection.Output, ImageSourceBlock, "ImageSourceBlock") ); + + this.registerOutput("dimensions", NodeMaterialBlockConnectionPointTypes.Vector2); } public override bind(effect: Effect) { @@ -101,6 +104,13 @@ export class ImageSourceBlock extends NodeMaterialBlock { return this._outputs[0]; } + /** + * Gets the dimension component + */ + public get dimensions(): NodeMaterialConnectionPoint { + return this._outputs[1]; + } + protected override _buildBlock(state: NodeMaterialBuildState) { super._buildBlock(state); @@ -113,6 +123,17 @@ export class ImageSourceBlock extends NodeMaterialBlock { state.sharedData.bindableBlocks.push(this); } + if (this.dimensions.isConnected) { + let affect: string = ""; + if (state.shaderLanguage === ShaderLanguage.WGSL) { + affect = `vec2f(textureDimensions(${this._samplerName}, 0).xy)`; + } else { + affect = `vec2(textureSize(${this._samplerName}, 0).xy)`; + } + + state.compilationString += `${state._declareOutput(this.dimensions)} = ${affect};\n`; + } + state._emit2DSampler(this._samplerName); return this; diff --git a/packages/dev/core/src/Materials/Node/Blocks/Dual/textureBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/Dual/textureBlock.ts index c20c68da602..e3749e52f22 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/Dual/textureBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/Dual/textureBlock.ts @@ -271,7 +271,37 @@ export class TextureBlock extends NodeMaterialBlock { return this._outputs[6]; } - public override get target() { + private _isTiedToFragment(input: NodeMaterialConnectionPoint) { + if (input.target === NodeMaterialBlockTargets.Fragment) { + return true; + } + + if (input.target === NodeMaterialBlockTargets.Vertex) { + return false; + } + + if (input.target === NodeMaterialBlockTargets.Neutral || input.target === NodeMaterialBlockTargets.VertexAndFragment) { + const parentBlock = input.ownerBlock; + + if (parentBlock.target === NodeMaterialBlockTargets.Fragment) { + return true; + } + + for (const input of parentBlock.inputs) { + if (!input.isConnected) { + continue; + } + if (this._isTiedToFragment(input.connectedPoint!)) { + return true; + } + } + } + + return false; + } + + private _cachedTarget: Nullable = null; + private _getEffectiveTarget() { if (this._fragmentOnly) { return NodeMaterialBlockTargets.Fragment; } @@ -286,35 +316,19 @@ export class TextureBlock extends NodeMaterialBlock { return NodeMaterialBlockTargets.VertexAndFragment; } - let parent = this.uv.connectedPoint; - - while (parent) { - if (parent.target === NodeMaterialBlockTargets.Fragment) { - return NodeMaterialBlockTargets.Fragment; - } - - if (parent.target === NodeMaterialBlockTargets.Vertex) { - return NodeMaterialBlockTargets.VertexAndFragment; - } - - if (parent.target === NodeMaterialBlockTargets.Neutral || parent.target === NodeMaterialBlockTargets.VertexAndFragment) { - const parentBlock = parent.ownerBlock; + if (this._isTiedToFragment(this.uv.connectedPoint!)) { + return NodeMaterialBlockTargets.Fragment; + } - if (parentBlock.target === NodeMaterialBlockTargets.Fragment) { - return NodeMaterialBlockTargets.Fragment; - } + return NodeMaterialBlockTargets.VertexAndFragment; + } - parent = null; - for (const input of parentBlock.inputs) { - if (input.connectedPoint) { - parent = input.connectedPoint; - break; - } - } - } + public override get target() { + if (!this._cachedTarget) { + this._cachedTarget = this._getEffectiveTarget(); } - return NodeMaterialBlockTargets.VertexAndFragment; + return this._cachedTarget; } public override set target(value: NodeMaterialBlockTargets) {} @@ -576,6 +590,7 @@ export class TextureBlock extends NodeMaterialBlock { } protected override _buildBlock(state: NodeMaterialBuildState) { + this._cachedTarget = null; super._buildBlock(state); if (this.source.isConnected) { diff --git a/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts index 69647e2e00c..6fef5228e9c 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts @@ -1,12 +1,13 @@ import { NodeMaterialBlock } from "../nodeMaterialBlock"; import { NodeMaterialBlockConnectionPointTypes } from "../Enums/nodeMaterialBlockConnectionPointTypes"; import type { NodeMaterialBuildState } from "../nodeMaterialBuildState"; -import type { NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; +import { NodeMaterialConnectionPointDirection, type NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; import { NodeMaterialBlockTargets } from "../Enums/nodeMaterialBlockTargets"; import { RegisterClass } from "../../../Misc/typeStore"; import { editableInPropertyPage, PropertyTypeForEdition } from "core/Decorators/nodeDecorator"; import type { Scene } from "core/scene"; import { ShaderLanguage } from "core/Materials/shaderLanguage"; +import { NodeMaterialConnectionPointCustomObject } from "../nodeMaterialConnectionPointCustomObject"; /** * Block used to repeat code */ @@ -25,14 +26,23 @@ export class LoopBlock extends NodeMaterialBlock { super(name, NodeMaterialBlockTargets.Neutral); this.registerInput("input", NodeMaterialBlockConnectionPointTypes.AutoDetect); + this.registerInput("iterations", NodeMaterialBlockConnectionPointTypes.Float, true); this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.BasedOnInput); - this.registerOutput("index", NodeMaterialBlockConnectionPointTypes.Int); - this.registerOutput("loopID", NodeMaterialBlockConnectionPointTypes.Object); + this.registerOutput("index", NodeMaterialBlockConnectionPointTypes.Float, NodeMaterialBlockTargets.Fragment); + this.registerOutput( + "loopID", + NodeMaterialBlockConnectionPointTypes.Object, + undefined, + new NodeMaterialConnectionPointCustomObject("loopID", this, NodeMaterialConnectionPointDirection.Output, LoopBlock, "LoopBlock") + ); this._outputs[0]._typeConnectionSource = this._inputs[0]; this._outputs[0]._forPostBuild = true; this._outputs[2]._redirectedSource = this._inputs[0]; + + this._outputs[1]._preventBubbleUp = true; + this._outputs[2]._preventBubbleUp = true; } /** @@ -50,6 +60,13 @@ export class LoopBlock extends NodeMaterialBlock { return this._inputs[0]; } + /** + * Gets the iterations input component + */ + public get iterationsInput(): NodeMaterialConnectionPoint { + return this._inputs[1]; + } + /** * Gets the output component */ @@ -75,16 +92,23 @@ export class LoopBlock extends NodeMaterialBlock { super._buildBlock(state); const output = this._outputs[0]; + const index = this._outputs[1]; const indexName = state._getFreeVariableName("index"); const decl = state.shaderLanguage === ShaderLanguage.WGSL ? "var" : "int"; + const castFloat = state.shaderLanguage === ShaderLanguage.WGSL ? "f32" : "float"; + const castInt = state.shaderLanguage === ShaderLanguage.WGSL ? "u32" : "int"; // Declare storage variable and store initial value state.compilationString += state._declareOutput(output) + ` = ${this.input.associatedVariableName};\n`; + // Iterations + const iterations = this.iterationsInput.isConnected ? `${castInt}(${this.iterationsInput.associatedVariableName})` : this.iterations; + // Loop - state.compilationString += `for (${decl} ${indexName} = 0; ${indexName} < ${this.iterations}; ${indexName}++){\n`; + state.compilationString += `for (${decl} ${indexName} = 0; ${indexName} < ${iterations}; ${indexName}++){\n`; + state.compilationString += `${state._declareOutput(index)} = ${castFloat}(${indexName});\n`; return this; } diff --git a/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts index 25a096aeb4a..cc8c9955a50 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts @@ -1,10 +1,11 @@ import { NodeMaterialBlock } from "../nodeMaterialBlock"; import { NodeMaterialBlockConnectionPointTypes } from "../Enums/nodeMaterialBlockConnectionPointTypes"; import type { NodeMaterialBuildState } from "../nodeMaterialBuildState"; -import type { NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; +import { NodeMaterialConnectionPointDirection, type NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; import { NodeMaterialBlockTargets } from "../Enums/nodeMaterialBlockTargets"; import { RegisterClass } from "../../../Misc/typeStore"; -import type { LoopBlock } from "./loopBlock"; +import { LoopBlock } from "./loopBlock"; +import { NodeMaterialConnectionPointCustomObject } from "../nodeMaterialConnectionPointCustomObject"; /** * Block used to read from a variable within a loop */ @@ -16,11 +17,16 @@ export class StorageReadBlock extends NodeMaterialBlock { public constructor(name: string) { super(name, NodeMaterialBlockTargets.Neutral); - this.registerInput("loopID", NodeMaterialBlockConnectionPointTypes.Object); + this.registerInput( + "loopID", + NodeMaterialBlockConnectionPointTypes.Object, + false, + undefined, + new NodeMaterialConnectionPointCustomObject("loopID", this, NodeMaterialConnectionPointDirection.Input, LoopBlock, "LoopBlock") + ); this.registerOutput("value", NodeMaterialBlockConnectionPointTypes.AutoDetect); this._outputs[0]._linkedConnectionSource = this._inputs[0]; - this._inputs[0]._preventBubbleUp = true; } /** diff --git a/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts index 55c2b01a8bb..ffa7deb053f 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts @@ -1,10 +1,11 @@ import { NodeMaterialBlock } from "../nodeMaterialBlock"; import { NodeMaterialBlockConnectionPointTypes } from "../Enums/nodeMaterialBlockConnectionPointTypes"; import type { NodeMaterialBuildState } from "../nodeMaterialBuildState"; -import type { NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; +import { NodeMaterialConnectionPointDirection, type NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; import { NodeMaterialBlockTargets } from "../Enums/nodeMaterialBlockTargets"; import { RegisterClass } from "../../../Misc/typeStore"; -import type { LoopBlock } from "./loopBlock"; +import { LoopBlock } from "./loopBlock"; +import { NodeMaterialConnectionPointCustomObject } from "../nodeMaterialConnectionPointCustomObject"; /** * Block used to write to a variable within a loop */ @@ -16,11 +17,16 @@ export class StorageWriteBlock extends NodeMaterialBlock { public constructor(name: string) { super(name, NodeMaterialBlockTargets.Neutral); - this.registerInput("loopID", NodeMaterialBlockConnectionPointTypes.Object); + this.registerInput( + "loopID", + NodeMaterialBlockConnectionPointTypes.Object, + false, + undefined, + new NodeMaterialConnectionPointCustomObject("loopID", this, NodeMaterialConnectionPointDirection.Input, LoopBlock, "LoopBlock") + ); this.registerInput("value", NodeMaterialBlockConnectionPointTypes.AutoDetect); this._linkConnectionTypes(0, 1); - this._inputs[0]._preventBubbleUp = true; } /** @@ -45,6 +51,18 @@ export class StorageWriteBlock extends NodeMaterialBlock { return this._inputs[1]; } + /** Gets a boolean indicating that this connection will be used in the fragment shader + * @returns true if connected in fragment shader + */ + public override isConnectedInFragmentShader() { + if (!this.loopID.isConnected) { + return false; + } + const loopBlock = this.loopID.connectedPoint!.ownerBlock as LoopBlock; + + return loopBlock.output.isConnectedInFragmentShader; + } + protected override _buildBlock(state: NodeMaterialBuildState) { super._buildBlock(state); diff --git a/packages/dev/core/src/Materials/Node/nodeMaterial.ts b/packages/dev/core/src/Materials/Node/nodeMaterial.ts index 8a3d38f6b0b..9a0a7d24496 100644 --- a/packages/dev/core/src/Materials/Node/nodeMaterial.ts +++ b/packages/dev/core/src/Materials/Node/nodeMaterial.ts @@ -757,7 +757,7 @@ export class NodeMaterial extends PushMaterial { input.associatedVariableName = ""; const connectedPoint = input.connectedPoint; - if (connectedPoint && !input._preventBubbleUp) { + if (connectedPoint && !connectedPoint._preventBubbleUp) { const block = connectedPoint.ownerBlock; if (block !== node) { this._processInitializeOnLink(block, state, nodesToProcessForOtherBuildState, autoConfigure); @@ -799,7 +799,7 @@ export class NodeMaterial extends PushMaterial { for (const input of node.inputs) { const connectedPoint = input.connectedPoint; - if (connectedPoint && !input._preventBubbleUp) { + if (connectedPoint && !connectedPoint._preventBubbleUp) { const block = connectedPoint.ownerBlock; if (block !== node) { this._resetDualBlocks(block, id); @@ -1960,6 +1960,7 @@ export class NodeMaterial extends PushMaterial { this._vertexOutputNodes.length = 0; this._fragmentOutputNodes.length = 0; this.attachedBlocks.length = 0; + this._buildIsInProgress = false; } /** diff --git a/packages/tools/nodeEditor/src/graphSystem/display/loopDisplayManager.ts b/packages/tools/nodeEditor/src/graphSystem/display/loopDisplayManager.ts new file mode 100644 index 00000000000..e028b5037a7 --- /dev/null +++ b/packages/tools/nodeEditor/src/graphSystem/display/loopDisplayManager.ts @@ -0,0 +1,22 @@ +import type { IDisplayManager } from "shared-ui-components/nodeGraphSystem/interfaces/displayManager"; +import type { INodeData } from "shared-ui-components/nodeGraphSystem/interfaces/nodeData"; + +export class LoopDisplayManager implements IDisplayManager { + public getHeaderClass() { + return ""; + } + + public shouldDisplayPortLabels(): boolean { + return true; + } + + public getHeaderText(nodeData: INodeData): string { + return nodeData.data.name; + } + + public getBackgroundColor(): string { + return "rgb(86, 185, 120)"; + } + + public updatePreviewContent(nodeData: INodeData, contentArea: HTMLDivElement): void {} +} diff --git a/packages/tools/nodeEditor/src/graphSystem/registerToDisplayLedger.ts b/packages/tools/nodeEditor/src/graphSystem/registerToDisplayLedger.ts index 526ead52d40..d355b838162 100644 --- a/packages/tools/nodeEditor/src/graphSystem/registerToDisplayLedger.ts +++ b/packages/tools/nodeEditor/src/graphSystem/registerToDisplayLedger.ts @@ -15,8 +15,10 @@ import { MeshAttributeExistsDisplayManager } from "./display/meshAttributeExists import { CurveDisplayManager } from "./display/curveDisplayManager"; import { TeleportOutDisplayManager } from "./display/teleportOutDisplayManager"; import { TeleportInDisplayManager } from "./display/teleportInDisplayManager"; +import { LoopDisplayManager } from "./display/loopDisplayManager"; export const RegisterToDisplayManagers = () => { + DisplayLedger.RegisteredControls["LoopBlock"] = LoopDisplayManager; DisplayLedger.RegisteredControls["InputBlock"] = InputDisplayManager; DisplayLedger.RegisteredControls["VertexOutputBlock"] = OutputDisplayManager; DisplayLedger.RegisteredControls["FragmentOutputBlock"] = OutputDisplayManager; From 7f25a7714bddab42a01306ed0437bcf254825145 Mon Sep 17 00:00:00 2001 From: Deltakosh Date: Thu, 19 Sep 2024 09:46:54 -0700 Subject: [PATCH 3/8] Fix webgpu --- packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts index 6fef5228e9c..70234595c18 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts @@ -98,7 +98,7 @@ export class LoopBlock extends NodeMaterialBlock { const decl = state.shaderLanguage === ShaderLanguage.WGSL ? "var" : "int"; const castFloat = state.shaderLanguage === ShaderLanguage.WGSL ? "f32" : "float"; - const castInt = state.shaderLanguage === ShaderLanguage.WGSL ? "u32" : "int"; + const castInt = state.shaderLanguage === ShaderLanguage.WGSL ? "i32" : "int"; // Declare storage variable and store initial value state.compilationString += state._declareOutput(output) + ` = ${this.input.associatedVariableName};\n`; From f9fb5fdceee36a44a8d0ed80eb2629dc7362cd79 Mon Sep 17 00:00:00 2001 From: Deltakosh Date: Thu, 19 Sep 2024 10:56:19 -0700 Subject: [PATCH 4/8] Fix tests --- .../src/Materials/Node/Blocks/Dual/textureBlock.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/dev/core/src/Materials/Node/Blocks/Dual/textureBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/Dual/textureBlock.ts index e3749e52f22..cf158ea3fa2 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/Dual/textureBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/Dual/textureBlock.ts @@ -300,7 +300,6 @@ export class TextureBlock extends NodeMaterialBlock { return false; } - private _cachedTarget: Nullable = null; private _getEffectiveTarget() { if (this._fragmentOnly) { return NodeMaterialBlockTargets.Fragment; @@ -320,15 +319,11 @@ export class TextureBlock extends NodeMaterialBlock { return NodeMaterialBlockTargets.Fragment; } - return NodeMaterialBlockTargets.VertexAndFragment; + return NodeMaterialBlockTargets.Fragment; } public override get target() { - if (!this._cachedTarget) { - this._cachedTarget = this._getEffectiveTarget(); - } - - return this._cachedTarget; + return this._getEffectiveTarget(); } public override set target(value: NodeMaterialBlockTargets) {} @@ -590,7 +585,6 @@ export class TextureBlock extends NodeMaterialBlock { } protected override _buildBlock(state: NodeMaterialBuildState) { - this._cachedTarget = null; super._buildBlock(state); if (this.source.isConnected) { From baa1a496467e367aa7e5d34c0cc0fcfc58a9bd6b Mon Sep 17 00:00:00 2001 From: Deltakosh Date: Thu, 19 Sep 2024 13:07:41 -0700 Subject: [PATCH 5/8] Address feedback --- packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts | 3 ++- .../dev/core/src/Materials/Node/Blocks/storageReadBlock.ts | 2 +- .../dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts index 70234595c18..de8f338d7b9 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts @@ -1,7 +1,8 @@ import { NodeMaterialBlock } from "../nodeMaterialBlock"; import { NodeMaterialBlockConnectionPointTypes } from "../Enums/nodeMaterialBlockConnectionPointTypes"; import type { NodeMaterialBuildState } from "../nodeMaterialBuildState"; -import { NodeMaterialConnectionPointDirection, type NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; +import { NodeMaterialConnectionPointDirection } from "../nodeMaterialBlockConnectionPoint"; +import type { NodeMaterialConnectionPoint } from "../nodeMaterialBlockConnectionPoint"; import { NodeMaterialBlockTargets } from "../Enums/nodeMaterialBlockTargets"; import { RegisterClass } from "../../../Misc/typeStore"; import { editableInPropertyPage, PropertyTypeForEdition } from "core/Decorators/nodeDecorator"; diff --git a/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts index cc8c9955a50..9c51aa7b0f1 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/storageReadBlock.ts @@ -54,7 +54,7 @@ export class StorageReadBlock extends NodeMaterialBlock { protected override _buildBlock(state: NodeMaterialBuildState) { super._buildBlock(state); - const value = this._outputs[0]; + const value = this.value; if (!this.loopID.isConnected) { return this; diff --git a/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts index ffa7deb053f..4cbab9e4696 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/storageWriteBlock.ts @@ -66,7 +66,7 @@ export class StorageWriteBlock extends NodeMaterialBlock { protected override _buildBlock(state: NodeMaterialBuildState) { super._buildBlock(state); - const value = this._inputs[1]; + const value = this.value; if (!this.loopID.isConnected) { return this; From f27ca77d67d673c68fe37cccb7996854ab4ee811 Mon Sep 17 00:00:00 2001 From: Deltakosh Date: Thu, 19 Sep 2024 13:12:31 -0700 Subject: [PATCH 6/8] . --- packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts index de8f338d7b9..ee72aec30a1 100644 --- a/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts +++ b/packages/dev/core/src/Materials/Node/Blocks/loopBlock.ts @@ -14,7 +14,8 @@ import { NodeMaterialConnectionPointCustomObject } from "../nodeMaterialConnecti */ export class LoopBlock extends NodeMaterialBlock { /** - * Gets or sets the source range + * Gets or sets number of iterations + * Will be ignored if the iterations input is connected */ @editableInPropertyPage("Iterations", PropertyTypeForEdition.Int) public iterations = 4; From b18b960a2b540f25173f4c00c427e23655d45618 Mon Sep 17 00:00:00 2001 From: Deltakosh Date: Thu, 19 Sep 2024 13:24:01 -0700 Subject: [PATCH 7/8] Fix focus mode --- .../src/nodeGraphSystem/graphFrame.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/dev/sharedUiComponents/src/nodeGraphSystem/graphFrame.ts b/packages/dev/sharedUiComponents/src/nodeGraphSystem/graphFrame.ts index 02e08cd2391..2c20a71a8bc 100644 --- a/packages/dev/sharedUiComponents/src/nodeGraphSystem/graphFrame.ts +++ b/packages/dev/sharedUiComponents/src/nodeGraphSystem/graphFrame.ts @@ -764,6 +764,13 @@ export class GraphFrame { link.path.style.opacity = ""; link.selectionPath.style.pointerEvents = ""; } + for (const frame of this._ownerCanvas.frames) { + if (frame !== this) { + frame.element.style.transition = ""; + frame.element.style.opacity = ""; + frame.element.style.pointerEvents = ""; + } + } return; } this._isFocused = true; @@ -782,6 +789,14 @@ export class GraphFrame { link.selectionPath.style.pointerEvents = "none"; } } + + for (const frame of this._ownerCanvas.frames) { + if (frame !== this) { + frame.element.style.transition = "opacity 0.5s"; + frame.element.style.opacity = "0.05"; + frame.element.style.pointerEvents = "none"; + } + } } public refresh() { From a700cf170a2cca4dac48cf51d4c37c6c2773016b Mon Sep 17 00:00:00 2001 From: Deltakosh Date: Thu, 19 Sep 2024 13:37:22 -0700 Subject: [PATCH 8/8] Better wire representation when focused --- .../dev/sharedUiComponents/src/nodeGraphSystem/graphFrame.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/dev/sharedUiComponents/src/nodeGraphSystem/graphFrame.ts b/packages/dev/sharedUiComponents/src/nodeGraphSystem/graphFrame.ts index 2c20a71a8bc..b2fb95c6cf1 100644 --- a/packages/dev/sharedUiComponents/src/nodeGraphSystem/graphFrame.ts +++ b/packages/dev/sharedUiComponents/src/nodeGraphSystem/graphFrame.ts @@ -783,6 +783,11 @@ export class GraphFrame { } } for (const link of this._ownerCanvas.links) { + if (this._nodes.indexOf(link.nodeA) === -1 || this._nodes.indexOf(link.nodeB!) === -1) { + link.path.style.transition = "opacity 0.5s"; + link.path.style.opacity = "0.3"; + link.selectionPath.style.pointerEvents = "none"; + } if (this._nodes.indexOf(link.nodeA) === -1 && this._nodes.indexOf(link.nodeB!) === -1) { link.path.style.transition = "opacity 0.5s"; link.path.style.opacity = "0.05";