123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- import { NodeMaterialBlock } from '../../nodeMaterialBlock';
- import { NodeMaterialBlockConnectionPointTypes } from '../../nodeMaterialBlockConnectionPointTypes';
- import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
- import { NodeMaterialBlockTargets } from '../../nodeMaterialBlockTargets';
- import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPoint';
- import { AbstractMesh } from '../../../../Meshes/abstractMesh';
- import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
- import { Effect } from '../../../effect';
- import { Mesh } from '../../../../Meshes/mesh';
- import { MaterialHelper } from '../../../materialHelper';
- import { VertexBuffer } from '../../../../Meshes/buffer';
- import { InputBlock } from '../Input/inputBlock';
- /**
- * Block used to add morph targets support to vertex shader
- */
- export class MorphTargetsBlock extends NodeMaterialBlock {
- private _repeatableContentAnchor: string;
- private _repeatebleContentGenerated = 0;
- /**
- * Create a new MorphTargetsBlock
- * @param name defines the block name
- */
- public constructor(name: string) {
- super(name, NodeMaterialBlockTargets.Vertex);
- this.registerInput("position", NodeMaterialBlockConnectionPointTypes.Vector3);
- this.registerInput("normal", NodeMaterialBlockConnectionPointTypes.Vector3);
- this.registerInput("tangent", NodeMaterialBlockConnectionPointTypes.Vector3);
- this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2);
- this.registerOutput("positionOutput", NodeMaterialBlockConnectionPointTypes.Vector3);
- this.registerOutput("normalOutput", NodeMaterialBlockConnectionPointTypes.Vector3);
- this.registerOutput("tangentOutput", NodeMaterialBlockConnectionPointTypes.Vector3);
- this.registerOutput("uvOutput", NodeMaterialBlockConnectionPointTypes.Vector2);
- }
- /**
- * Gets the current class name
- * @returns the class name
- */
- public getClassName() {
- return "MorphTargetsBlock";
- }
- /**
- * Gets the position input component
- */
- public get position(): NodeMaterialConnectionPoint {
- return this._inputs[0];
- }
- /**
- * Gets the normal input component
- */
- public get normal(): NodeMaterialConnectionPoint {
- return this._inputs[1];
- }
- /**
- * Gets the tangent input component
- */
- public get tangent(): NodeMaterialConnectionPoint {
- return this._inputs[2];
- }
- /**
- * Gets the tangent input component
- */
- public get uv(): NodeMaterialConnectionPoint {
- return this._inputs[3];
- }
- /**
- * Gets the position output component
- */
- public get positionOutput(): NodeMaterialConnectionPoint {
- return this._outputs[0];
- }
- /**
- * Gets the normal output component
- */
- public get normalOutput(): NodeMaterialConnectionPoint {
- return this._outputs[1];
- }
- /**
- * Gets the tangent output component
- */
- public get tangentOutput(): NodeMaterialConnectionPoint {
- return this._outputs[2];
- }
- /**
- * Gets the tangent output component
- */
- public get uvOutput(): NodeMaterialConnectionPoint {
- return this._outputs[3];
- }
- public initialize(state: NodeMaterialBuildState) {
- state._excludeVariableName("morphTargetInfluences");
- }
- public autoConfigure() {
- if (!this.position.isConnected) {
- let positionInput = new InputBlock("position");
- positionInput.setAsAttribute("position");
- positionInput.output.connectTo(this.position);
- }
- if (!this.normal.isConnected) {
- let normalInput = new InputBlock("normal");
- normalInput.setAsAttribute("normal");
- normalInput.output.connectTo(this.normal);
- }
- if (!this.tangent.isConnected) {
- let tangentInput = new InputBlock("tangent");
- tangentInput.setAsAttribute("tangent");
- tangentInput.output.connectTo(this.tangent);
- }
- if (!this.uv.isConnected) {
- let uvInput = new InputBlock("uv");
- uvInput.setAsAttribute("uv");
- uvInput.output.connectTo(this.uv);
- }
- }
- public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
- if (!defines._areAttributesDirty) {
- return;
- }
- MaterialHelper.PrepareDefinesForMorphTargets(mesh, defines);
- }
- public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
- if (mesh && this._repeatebleContentGenerated) {
- MaterialHelper.BindMorphTargetParameters(mesh, effect);
- }
- }
- public replaceRepeatableContent(vertexShaderState: NodeMaterialBuildState, fragmentShaderState: NodeMaterialBuildState, mesh: AbstractMesh, defines: NodeMaterialDefines) {
- let position = this.position;
- let normal = this.normal;
- let tangent = this.tangent;
- let uv = this.uv;
- let positionOutput = this.positionOutput;
- let normalOutput = this.normalOutput;
- let tangentOutput = this.tangentOutput;
- let uvOutput = this.uvOutput;
- let state = vertexShaderState;
- let repeatCount = defines.NUM_MORPH_INFLUENCERS as number;
- this._repeatebleContentGenerated = repeatCount;
- var manager = (<Mesh>mesh).morphTargetManager;
- var hasNormals = manager && manager.supportsNormals && defines["NORMAL"];
- var hasTangents = manager && manager.supportsTangents && defines["TANGENT"];
- var hasUVs = manager && manager.supportsUVs && defines["UV1"];
- let injectionCode = "";
- for (var index = 0; index < repeatCount; index++) {
- injectionCode += `#ifdef MORPHTARGETS\r\n`;
- injectionCode += `${positionOutput.associatedVariableName} += (position${index} - ${position.associatedVariableName}) * morphTargetInfluences[${index}];\r\n`;
- if (hasNormals) {
- injectionCode += `#ifdef MORPHTARGETS_NORMAL\r\n`;
- injectionCode += `${normalOutput.associatedVariableName} += (normal${index} - ${normal.associatedVariableName}) * morphTargetInfluences[${index}];\r\n`;
- injectionCode += `#endif\r\n`;
- }
- if (hasTangents) {
- injectionCode += `#ifdef MORPHTARGETS_TANGENT\r\n`;
- injectionCode += `${tangentOutput.associatedVariableName}.xyz += (tangent${index} - ${tangent.associatedVariableName}.xyz) * morphTargetInfluences[${index}];\r\n`;
- injectionCode += `#endif\r\n`;
- }
- if (hasUVs) {
- injectionCode += `#ifdef MORPHTARGETS_UV\r\n`;
- injectionCode += `${uvOutput.associatedVariableName}.xyz += (uv_${index} - ${uv.associatedVariableName}.xyz) * morphTargetInfluences[${index}];\r\n`;
- injectionCode += `#endif\r\n`;
- }
- injectionCode += `#endif\r\n`;
- }
- state.compilationString = state.compilationString.replace(this._repeatableContentAnchor, injectionCode);
- if (repeatCount > 0) {
- for (var index = 0; index < repeatCount; index++) {
- state.attributes.push(VertexBuffer.PositionKind + index);
- if (hasNormals) {
- state.attributes.push(VertexBuffer.NormalKind + index);
- }
- if (hasTangents) {
- state.attributes.push(VertexBuffer.TangentKind + index);
- }
- }
- }
- }
- protected _buildBlock(state: NodeMaterialBuildState) {
- 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
- let position = this.position;
- let normal = this.normal;
- let tangent = this.tangent;
- let positionOutput = this.positionOutput;
- let normalOutput = this.normalOutput;
- let tangentOutput = this.tangentOutput;
- let comments = `//${this.name}`;
- state.uniforms.push("morphTargetInfluences");
- state._emitFunctionFromInclude("morphTargetsVertexGlobalDeclaration", comments);
- state._emitFunctionFromInclude("morphTargetsVertexDeclaration", comments, {
- repeatKey: "maxSimultaneousMorphTargets"
- });
- state.compilationString += `${this._declareOutput(positionOutput, state)} = ${position.associatedVariableName};\r\n`;
- state.compilationString += `#ifdef NORMAL\r\n`;
- state.compilationString += `${this._declareOutput(normalOutput, state)} = ${normal.associatedVariableName};\r\n`;
- state.compilationString += `#endif\r\n`;
- state.compilationString += `#ifdef TANGENT\r\n`;
- state.compilationString += `${this._declareOutput(tangentOutput, state)} = ${tangent.associatedVariableName};\r\n`;
- state.compilationString += `#endif\r\n`;
- // Repeatable content
- this._repeatableContentAnchor = state._repeatableContentAnchor;
- state.compilationString += this._repeatableContentAnchor;
- return this;
- }
- }
|