UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

421 lines 21 kB
import { NodeMaterialBlock } from "../../nodeMaterialBlock.js"; import { NodeMaterialBlockConnectionPointTypes } from "../../Enums/nodeMaterialBlockConnectionPointTypes.js"; import { NodeMaterialBlockTargets } from "../../Enums/nodeMaterialBlockTargets.js"; import { VertexBuffer } from "../../../../Buffers/buffer.js"; import { InputBlock } from "../Input/inputBlock.js"; import { RegisterClass } from "../../../../Misc/typeStore.js"; import { BindMorphTargetParameters, PrepareDefinesForMorphTargets } from "../../../materialHelper.functions.js"; /** * Block used to add morph targets support to vertex shader */ export class MorphTargetsBlock extends NodeMaterialBlock { /** * Create a new MorphTargetsBlock * @param name defines the block name */ constructor(name) { super(name, NodeMaterialBlockTargets.Vertex); this.registerInput("position", NodeMaterialBlockConnectionPointTypes.Vector3); this.registerInput("normal", NodeMaterialBlockConnectionPointTypes.Vector3); this.registerInput("tangent", NodeMaterialBlockConnectionPointTypes.AutoDetect); this.tangent.addExcludedConnectionPointFromAllowedTypes(NodeMaterialBlockConnectionPointTypes.Color4 | NodeMaterialBlockConnectionPointTypes.Vector4 | NodeMaterialBlockConnectionPointTypes.Vector3); this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2); this.registerInput("uv2", NodeMaterialBlockConnectionPointTypes.Vector2); this.registerInput("color", NodeMaterialBlockConnectionPointTypes.Color4); this.registerOutput("positionOutput", NodeMaterialBlockConnectionPointTypes.Vector3); this.registerOutput("normalOutput", NodeMaterialBlockConnectionPointTypes.Vector3); this.registerOutput("tangentOutput", NodeMaterialBlockConnectionPointTypes.Vector4); this.registerOutput("uvOutput", NodeMaterialBlockConnectionPointTypes.Vector2); this.registerOutput("uv2Output", NodeMaterialBlockConnectionPointTypes.Vector2); this.registerOutput("colorOutput", NodeMaterialBlockConnectionPointTypes.Color4); } /** * Gets the current class name * @returns the class name */ getClassName() { return "MorphTargetsBlock"; } /** * Gets the position input component */ get position() { return this._inputs[0]; } /** * Gets the normal input component */ get normal() { return this._inputs[1]; } /** * Gets the tangent input component */ get tangent() { return this._inputs[2]; } /** * Gets the uv input component */ get uv() { return this._inputs[3]; } /** * Gets the uv2 input component */ get uv2() { return this._inputs[4]; } /** * Gets the color input component */ get color() { return this._inputs[5]; } /** * Gets the position output component */ get positionOutput() { return this._outputs[0]; } /** * Gets the normal output component */ get normalOutput() { return this._outputs[1]; } /** * Gets the tangent output component */ get tangentOutput() { return this._outputs[2]; } /** * Gets the uv output component */ get uvOutput() { return this._outputs[3]; } /** * Gets the uv2 output component */ get uv2Output() { return this._outputs[4]; } /** * Gets the color output component */ get colorOutput() { return this._outputs[5]; } initialize(state) { state._excludeVariableName("morphTargetInfluences"); this._initShaderSourceAsync(state.shaderLanguage); } async _initShaderSourceAsync(shaderLanguage) { this._codeIsReady = false; if (shaderLanguage === 1 /* ShaderLanguage.WGSL */) { await Promise.all([ import("../../../../ShadersWGSL/ShadersInclude/morphTargetsVertex.js"), import("../../../../ShadersWGSL/ShadersInclude/morphTargetsVertexDeclaration.js"), import("../../../../ShadersWGSL/ShadersInclude/morphTargetsVertexGlobal.js"), import("../../../../ShadersWGSL/ShadersInclude/morphTargetsVertexGlobalDeclaration.js"), ]); } else { await Promise.all([ import("../../../../Shaders/ShadersInclude/morphTargetsVertex.js"), import("../../../../Shaders/ShadersInclude/morphTargetsVertexDeclaration.js"), import("../../../../Shaders/ShadersInclude/morphTargetsVertexGlobal.js"), import("../../../../Shaders/ShadersInclude/morphTargetsVertexGlobalDeclaration.js"), ]); } this._codeIsReady = true; this.onCodeIsReadyObservable.notifyObservers(this); } autoConfigure(material, additionalFilteringInfo = () => true) { if (!this.position.isConnected) { let positionInput = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "position" && additionalFilteringInfo(b)); if (!positionInput) { positionInput = new InputBlock("position"); positionInput.setAsAttribute(); } positionInput.output.connectTo(this.position); } if (!this.normal.isConnected) { let normalInput = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "normal" && additionalFilteringInfo(b)); if (!normalInput) { normalInput = new InputBlock("normal"); normalInput.setAsAttribute("normal"); } normalInput.output.connectTo(this.normal); } if (!this.tangent.isConnected) { let tangentInput = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "tangent" && additionalFilteringInfo(b)); if (!tangentInput) { tangentInput = new InputBlock("tangent"); tangentInput.setAsAttribute("tangent"); } tangentInput.output.connectTo(this.tangent); } if (!this.uv.isConnected) { let uvInput = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "uv" && additionalFilteringInfo(b)); if (!uvInput) { uvInput = new InputBlock("uv"); uvInput.setAsAttribute("uv"); } uvInput.output.connectTo(this.uv); } if (!this.uv2.isConnected) { let uv2Input = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "uv2" && additionalFilteringInfo(b)); if (!uv2Input) { uv2Input = new InputBlock("uv2"); uv2Input.setAsAttribute("uv2"); } uv2Input.output.connectTo(this.uv2); } if (!this.color.isConnected) { let colorInput = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "color" && additionalFilteringInfo(b)); if (!colorInput) { colorInput = new InputBlock("color"); colorInput.setAsAttribute("color"); } colorInput.output.connectTo(this.color); } } prepareDefines(mesh, nodeMaterial, defines) { if (mesh.morphTargetManager) { const morphTargetManager = mesh.morphTargetManager; if (morphTargetManager?.isUsingTextureForTargets && (morphTargetManager.numMaxInfluencers || morphTargetManager.numInfluencers) !== defines["NUM_MORPH_INFLUENCERS"]) { defines.markAsAttributesDirty(); } } if (!defines._areAttributesDirty) { return; } PrepareDefinesForMorphTargets(mesh, defines); } bind(effect, nodeMaterial, mesh) { if (mesh && mesh.morphTargetManager && mesh.morphTargetManager.numInfluencers > 0) { BindMorphTargetParameters(mesh, effect); if (mesh.morphTargetManager.isUsingTextureForTargets) { mesh.morphTargetManager._bind(effect); } } } replaceRepeatableContent(vertexShaderState, fragmentShaderState, mesh, defines) { const position = this.position; const normal = this.normal; const tangent = this.tangent; const uv = this.uv; const uv2 = this.uv2; const color = this.color; const positionOutput = this.positionOutput; const normalOutput = this.normalOutput; const tangentOutput = this.tangentOutput; const uvOutput = this.uvOutput; const uv2Output = this.uv2Output; const colorOutput = this.colorOutput; const state = vertexShaderState; const repeatCount = defines.NUM_MORPH_INFLUENCERS; const manager = mesh.morphTargetManager; const supportPositions = manager && manager.supportsPositions; const supportNormals = manager && manager.supportsNormals; const supportTangents = manager && manager.supportsTangents; const supportUVs = manager && manager.supportsUVs; const supportUV2s = manager && manager.supportsUV2s; const supportColors = manager && manager.supportsColors; let injectionCode = ""; if (manager?.isUsingTextureForTargets && repeatCount > 0) { injectionCode += `${state._declareLocalVar("vertexID", NodeMaterialBlockConnectionPointTypes.Float)};\n`; } injectionCode += `#ifdef MORPHTARGETS\n`; const isWebGPU = state.shaderLanguage === 1 /* ShaderLanguage.WGSL */; const uniformsPrefix = isWebGPU ? "uniforms." : ""; if (manager?.isUsingTextureForTargets) { injectionCode += `for (${isWebGPU ? "var" : "int"} i = 0; i < NUM_MORPH_INFLUENCERS; i++) {\n`; injectionCode += `if (i >= ${uniformsPrefix}morphTargetCount) { break; }\n`; injectionCode += `vertexID = ${isWebGPU ? "f32(vertexInputs.vertexIndex" : "float(gl_VertexID"}) * ${uniformsPrefix}morphTargetTextureInfo.x;\n`; if (supportPositions) { injectionCode += `#ifdef MORPHTARGETS_POSITION\n`; injectionCode += `${positionOutput.associatedVariableName} += (readVector3FromRawSampler(i, vertexID) - ${position.associatedVariableName}) * ${uniformsPrefix}morphTargetInfluences[i];\n`; injectionCode += `#endif\n`; } injectionCode += `#ifdef MORPHTARGETTEXTURE_HASPOSITIONS\n`; injectionCode += `vertexID += 1.0;\n`; injectionCode += `#endif\n`; if (supportNormals) { injectionCode += `#ifdef MORPHTARGETS_NORMAL\n`; injectionCode += `${normalOutput.associatedVariableName} += (readVector3FromRawSampler(i, vertexID) - ${normal.associatedVariableName}) * ${uniformsPrefix}morphTargetInfluences[i];\n`; injectionCode += `#endif\n`; } injectionCode += `#ifdef MORPHTARGETTEXTURE_HASNORMALS\n`; injectionCode += `vertexID += 1.0;\n`; injectionCode += `#endif\n`; if (supportUVs) { injectionCode += `#ifdef MORPHTARGETS_UV\n`; injectionCode += `${uvOutput.associatedVariableName} += (readVector3FromRawSampler(i, vertexID).xy - ${uv.associatedVariableName}) * ${uniformsPrefix}morphTargetInfluences[i];\n`; injectionCode += `#endif\n`; } injectionCode += `#ifdef MORPHTARGETTEXTURE_HASUVS\n`; injectionCode += `vertexID += 1.0;\n`; injectionCode += `#endif\n`; if (supportTangents) { injectionCode += `#ifdef MORPHTARGETS_TANGENT\n`; injectionCode += `${tangentOutput.associatedVariableName}.xyz += (readVector3FromRawSampler(i, vertexID) - ${tangent.associatedVariableName}.xyz) * ${uniformsPrefix}morphTargetInfluences[i];\n`; if (tangent.type === NodeMaterialBlockConnectionPointTypes.Vector4) { injectionCode += `${tangentOutput.associatedVariableName}.w = ${tangent.associatedVariableName}.w;\n`; } else { injectionCode += `${tangentOutput.associatedVariableName}.w = 1.;\n`; } injectionCode += `#endif\n`; } injectionCode += `#ifdef MORPHTARGETTEXTURE_HASTANGENTS\n`; injectionCode += `vertexID += 1.0;\n`; injectionCode += `#endif\n`; if (supportUV2s) { injectionCode += `#ifdef MORPHTARGETS_UV2\n`; injectionCode += `${uv2Output.associatedVariableName} += (readVector3FromRawSampler(i, vertexID).xy - ${uv2.associatedVariableName}) * morphTargetInfluences[i];\n`; injectionCode += `#endif\n`; } injectionCode += `#ifdef MORPHTARGETTEXTURE_HASUV2S\n`; injectionCode += `vertexID += 1.0;\n`; injectionCode += `#endif\n`; if (supportColors) { injectionCode += `#ifdef MORPHTARGETS_COLOR\n`; injectionCode += `${colorOutput.associatedVariableName} += (readVector4FromRawSampler(i, vertexID) - ${color.associatedVariableName}) * ${uniformsPrefix}morphTargetInfluences[i];\n`; injectionCode += `#endif\n`; } injectionCode += "}\n"; } else { for (let index = 0; index < repeatCount; index++) { if (supportPositions) { injectionCode += `#ifdef MORPHTARGETS_POSITION\n`; injectionCode += `${positionOutput.associatedVariableName} += (position${index} - ${position.associatedVariableName}) * ${uniformsPrefix}morphTargetInfluences[${index}];\n`; injectionCode += `#endif\n`; } if (supportNormals && defines["NORMAL"]) { injectionCode += `#ifdef MORPHTARGETS_NORMAL\n`; injectionCode += `${normalOutput.associatedVariableName} += (normal${index} - ${normal.associatedVariableName}) * ${uniformsPrefix}morphTargetInfluences[${index}];\n`; injectionCode += `#endif\n`; } if (supportUVs && defines["UV1"]) { injectionCode += `#ifdef MORPHTARGETS_UV\n`; injectionCode += `${uvOutput.associatedVariableName}.xy += (uv_${index} - ${uv.associatedVariableName}.xy) * ${uniformsPrefix}morphTargetInfluences[${index}];\n`; injectionCode += `#endif\n`; } if (supportTangents && defines["TANGENT"]) { injectionCode += `#ifdef MORPHTARGETS_TANGENT\n`; injectionCode += `${tangentOutput.associatedVariableName}.xyz += (tangent${index} - ${tangent.associatedVariableName}.xyz) * ${uniformsPrefix}morphTargetInfluences[${index}];\n`; if (tangent.type === NodeMaterialBlockConnectionPointTypes.Vector4) { injectionCode += `${tangentOutput.associatedVariableName}.w = ${tangent.associatedVariableName}.w;\n`; } else { injectionCode += `${tangentOutput.associatedVariableName}.w = 1.;\n`; } injectionCode += `#endif\n`; } if (supportUV2s && defines["UV2"]) { injectionCode += `#ifdef MORPHTARGETS_UV2\n`; injectionCode += `${uv2Output.associatedVariableName}.xy += (uv2_${index} - ${uv2.associatedVariableName}.xy) * morphTargetInfluences[${index}];\n`; injectionCode += `#endif\n`; } if (supportColors && defines["VERTEXCOLOR_NME"]) { injectionCode += `#ifdef MORPHTARGETS_COLOR\n`; injectionCode += `${colorOutput.associatedVariableName} += (color${index} - ${color.associatedVariableName}) * ${uniformsPrefix}morphTargetInfluences[${index}];\n`; injectionCode += `#endif\n`; } } } injectionCode += `#endif\n`; state.compilationString = state.compilationString.replace(this._repeatableContentAnchor, injectionCode); if (repeatCount > 0) { for (let index = 0; index < repeatCount; index++) { if (supportPositions) { state.attributes.push(VertexBuffer.PositionKind + index); } if (supportNormals && defines["NORMAL"]) { state.attributes.push(VertexBuffer.NormalKind + index); } if (supportTangents && defines["TANGENT"]) { state.attributes.push(VertexBuffer.TangentKind + index); } if (supportUVs && defines["UV1"]) { state.attributes.push(VertexBuffer.UVKind + "_" + index); } if (supportUV2s && defines["UV2"]) { state.attributes.push(VertexBuffer.UV2Kind + "_" + index); } if (supportColors && defines["VERTEXCOLOR_NME"]) { state.attributes.push(VertexBuffer.ColorKind + index); } } } } _buildBlock(state) { super._buildBlock(state); // Register for defines state.sharedData.blocksWithDefines.push(this); // Register for binding state.sharedData.bindableBlocks.push(this); // Register for repeatable content generation state.sharedData.repeatableContentBlocks.push(this); // Emit code const position = this.position; const normal = this.normal; const tangent = this.tangent; const uv = this.uv; const uv2 = this.uv2; const color = this.color; const positionOutput = this.positionOutput; const normalOutput = this.normalOutput; const tangentOutput = this.tangentOutput; const uvOutput = this.uvOutput; const uv2Output = this.uv2Output; const colorOutput = this.colorOutput; const comments = `//${this.name}`; state.uniforms.push("morphTargetInfluences"); state.uniforms.push("morphTargetCount"); state.uniforms.push("morphTargetTextureInfo"); state.uniforms.push("morphTargetTextureIndices"); state.samplers.push("morphTargets"); state._emitFunctionFromInclude("morphTargetsVertexGlobalDeclaration", comments); state._emitFunctionFromInclude("morphTargetsVertexDeclaration", comments, { repeatKey: "maxSimultaneousMorphTargets", }); state.compilationString += `${state._declareOutput(positionOutput)} = ${position.associatedVariableName};\n`; state.compilationString += `#ifdef NORMAL\n`; state.compilationString += `${state._declareOutput(normalOutput)} = ${normal.associatedVariableName};\n`; state.compilationString += `#else\n`; state.compilationString += `${state._declareOutput(normalOutput)} = vec3(0., 0., 0.);\n`; state.compilationString += `#endif\n`; state.compilationString += `#ifdef TANGENT\n`; state.compilationString += `${state._declareOutput(tangentOutput)} = ${tangent.associatedVariableName};\n`; state.compilationString += `#else\n`; state.compilationString += `${state._declareOutput(tangentOutput)} = vec4(0., 0., 0., 0.);\n`; state.compilationString += `#endif\n`; state.compilationString += `#ifdef UV1\n`; state.compilationString += `${state._declareOutput(uvOutput)} = ${uv.associatedVariableName};\n`; state.compilationString += `#else\n`; state.compilationString += `${state._declareOutput(uvOutput)} = vec2(0., 0.);\n`; state.compilationString += `#endif\n`; state.compilationString += `#ifdef UV2\n`; state.compilationString += `${state._declareOutput(uv2Output)} = ${uv2.associatedVariableName};\n`; state.compilationString += `#else\n`; state.compilationString += `${state._declareOutput(uv2Output)} = vec2(0., 0.);\n`; state.compilationString += `#endif\n`; state.compilationString += `#ifdef VERTEXCOLOR_NME\n`; state.compilationString += `${state._declareOutput(colorOutput)} = ${color.associatedVariableName};\n`; state.compilationString += `#else\n`; state.compilationString += `${state._declareOutput(colorOutput)} = vec4(0., 0., 0., 0.);\n`; state.compilationString += `#endif\n`; // Repeatable content this._repeatableContentAnchor = state._repeatableContentAnchor; state.compilationString += this._repeatableContentAnchor; return this; } } RegisterClass("BABYLON.MorphTargetsBlock", MorphTargetsBlock); //# sourceMappingURL=morphTargetsBlock.js.map