UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

128 lines (118 loc) 4.84 kB
/** * applies skinning * * * */ import SKINNING from './gl/skinning.glsl'; import {TypedGlNode} from './_Base'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; import {GlConnectionPointType, GlConnectionPoint} from '../utils/io/connections/Gl'; import {ShadersCollectionController} from './code/utils/ShadersCollectionController'; import {ShaderName} from '../utils/shaders/ShaderName'; import {ThreeToGl} from '../../../core/ThreeToGl'; import {expandShader} from './code/utils/ExpandShader'; import {FunctionGLDefinition} from './utils/GLDefinition'; const TEMPLATE = expandShader(SKINNING); const TO_REPLACE_INPUT_POS = `vec4( transformed, 1.0 )`; const TO_REPLACE_INPUT_NORMAL = `vec4( objectNormal, 0.0 )`; const TO_REPLACE_OUTPUT_POS = `transformed = `; const TO_REPLACE_OUTPUT_NORMAL = `objectNormal = `; const TO_REPLACE_OUTPUT_TANGENT = `objectTangent = `; // const TO_REMOVE = [`#ifdef USE_SKINNING`, '#endif']; interface CreateFunctionOptions { functionName: string; structDefinitionName: string; // input: string; // outValue: string; } const ARGS = { inputPos: {type: 'vec3', name: 'inputPos'}, inputNormal: {type: 'vec3', name: 'inputNormal'}, skinIndex: {type: 'vec4', name: 'skinIndex'}, }; function createFunction(options: CreateFunctionOptions) { const skinningStructName = `skinningOut`; let withReplaced = TEMPLATE.replace(TO_REPLACE_INPUT_POS, `vec4(${ARGS.inputPos.name}, 1.0)`) .replace(TO_REPLACE_INPUT_NORMAL, `vec4(${ARGS.inputNormal.name}, 0.0)`) // CAREFUL: the vec4 w is 0.0, NOT 1.0 .replace(TO_REPLACE_OUTPUT_POS, `${skinningStructName}.position = `) .replace(TO_REPLACE_OUTPUT_NORMAL, `${skinningStructName}.normal = `) .replace(TO_REPLACE_OUTPUT_TANGENT, `${skinningStructName}.tangent = `); // remove #ifdef USE_SKINNING / #endif // for (let toRemove of TO_REMOVE) { // while (withReplaced.includes(toRemove)) { // withReplaced = withReplaced.replace(toRemove, ''); // } // } // add struc const structDefinition = `struct ${options.structDefinitionName} { vec3 position; vec3 normal; vec3 tangent; };`; // wrap in a function const argsInDefinition = Object.values(ARGS) .map((arg) => `${arg.type} ${arg.name}`) .join(', '); const functionDeclaration = ` ${structDefinition} ${options.structDefinitionName} ${options.functionName}(${argsInDefinition}){ ${options.structDefinitionName} ${skinningStructName}; ${withReplaced} return ${skinningStructName}; }`; return {functionDeclaration}; } enum SkinningOutput { POSITION = 'position', NORMAL = 'normal', TANGENT = 'tangent', } class SkinningGlParamsConfig extends NodeParamsConfig { position = ParamConfig.VECTOR3([0, 0, 0]); normal = ParamConfig.VECTOR3([0, 1, 0]); } const ParamsConfig = new SkinningGlParamsConfig(); export class SkinningGlNode extends TypedGlNode<SkinningGlParamsConfig> { override paramsConfig = ParamsConfig; static override type(): Readonly<'skinning'> { return 'skinning'; } override initializeNode() { super.initializeNode(); this.io.outputs.setNamedOutputConnectionPoints([ new GlConnectionPoint(SkinningOutput.POSITION, GlConnectionPointType.VEC3), new GlConnectionPoint(SkinningOutput.NORMAL, GlConnectionPointType.VEC3), new GlConnectionPoint(SkinningOutput.TANGENT, GlConnectionPointType.VEC3), ]); } override setLines(linesController: ShadersCollectionController) { if (linesController.currentShaderName() == ShaderName.VERTEX) { const inputPosition = ThreeToGl.vector3(this.variableForInputParam(this.p.position)); const inputNormal = ThreeToGl.vector3(this.variableForInputParam(this.p.normal)); const outPosition = this.glVarName(SkinningOutput.POSITION); const outNormal = this.glVarName(SkinningOutput.NORMAL); const outTangent = this.glVarName(SkinningOutput.TANGENT); const outValue = this.glVarName('out'); const functionName = `computeSkinningData_${this.graphNodeId()}`; const structDefinitionName = `SkinningData_${this.graphNodeId()}`; const {functionDeclaration} = createFunction({functionName, structDefinitionName}); const bodyLines: string[] = [ `#ifdef USE_SKINNING`, `${structDefinitionName} ${outValue} = ${functionName}(${inputPosition}, ${inputNormal}, ${ARGS.skinIndex.name})`, `vec3 ${outPosition} = ${outValue}.position;`, `vec3 ${outNormal} = ${outValue}.normal;`, `vec3 ${outTangent} = ${outValue}.tangent;`, `#else`, `vec3 ${outPosition} = ${inputPosition}`, `vec3 ${outNormal} = ${inputNormal}`, `vec3 ${outTangent} = vec3(0.)`, `#endif`, ]; const definitionLines: FunctionGLDefinition[] = []; definitionLines.push(new FunctionGLDefinition(this, functionDeclaration)); linesController.addBodyLines(this, bodyLines, ShaderName.VERTEX); linesController.addDefinitions(this, definitionLines); } } }