UNPKG

@polygonjs/polygonjs

Version:

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

348 lines (347 loc) 13.3 kB
"use strict"; import { BaseJsShaderAssembler, INSERT_DEFINE_AFTER, INSERT_BODY_AFTER, INSERT_MEMBERS_AFTER, INSERT_CONSTRUCTOR_AFTER } from "../_Base"; import { JsShaderConfig } from "../../configs/ShaderConfig"; import { VariableConfig } from "../../configs/VariableConfig"; import { JsFunctionName } from "../../../../utils/shaders/ShaderName"; import { JsConnectionPointType, JsConnectionPoint } from "../../../../utils/io/connections/Js"; import { Euler, Matrix4, Quaternion, Vector3 } from "three"; import { Poly } from "../../../../../Poly"; import { PrettierController } from "../../../../../../core/code/PrettierController"; import { ObjectBuilderAssemblerConstant, ObjectVariable } from "./ObjectBuilderAssemblerCommon"; import { AttributeJsNodeInput } from "../../../Attribute"; const TEMPLATE = ` ${INSERT_DEFINE_AFTER} ${INSERT_MEMBERS_AFTER} ${INSERT_CONSTRUCTOR_AFTER} const CustomObjectBuilderEvaluator = function(){ ${INSERT_BODY_AFTER} `; const CLOSE_CLASS_DEFINITION = `}; return CustomObjectBuilderEvaluator;`; export class JsAssemblerObjectBuilder extends BaseJsShaderAssembler { // private _function: Function | undefined; // private _uniforms: IUniforms | undefined; // private _functionsByName: Map<string, Function> = new Map(); makeFunctionNodeDirtyOnChange() { return true; } templateShader() { return { main: TEMPLATE }; } spareParamsOptions(options) { const _options = { spare: true, // computeOnDirty: true, // not needed if cook option is not set // cook: false, // for SDFBuilder, the node needs to recook // important for texture nodes // that compute after being found by the nodepath param dependentOnFoundNode: true }; return _options; } functionData() { const _buildFunctionBody = () => { const bodyLines = this._shaders_by_name.get(JsFunctionName.MAIN) || TEMPLATE; const functionBodyElements = [ bodyLines, // triggerableFunctionLines.join('\n'), // triggerFunctionLines.join('\n'), CLOSE_CLASS_DEFINITION ]; const functionBody2 = PrettierController.formatJs(functionBodyElements.join("\n")); return functionBody2; }; const functionBody = _buildFunctionBody(); if (!functionBody) { return; } const variableNames = []; const functionNames = []; const variablesByName = {}; const functionsByName = {}; this.traverseRegisteredVariables((variable, varName) => { variableNames.push(varName); variablesByName[varName] = variable; }); this.traverseRegisteredFunctions((namedFunction) => { functionNames.push(namedFunction.type()); functionsByName[namedFunction.type()] = namedFunction.func.bind(namedFunction); }); const paramConfigs = this.param_configs(); return { functionBody, variableNames, variablesByName, functionNames, functionsByName, paramConfigs: [...paramConfigs] }; } // uniforms() { // return this._uniforms; // } // evalFunction(position: Vector3) { // if (this._function) { // return this._function(position); // } // } defaultObjectVariable() { return ObjectBuilderAssemblerConstant.OBJECT_3D; } defaultObject3DMaterialVariable() { return ObjectBuilderAssemblerConstant.MATERIAL; } defaultPrimitiveGraph() { return ObjectBuilderAssemblerConstant.PRIMITIVE_GRAPH; } updateFunction() { super.updateFunction(); this._lines = /* @__PURE__ */ new Map(); this._shaders_by_name = /* @__PURE__ */ new Map(); const shaderNames = this.shaderNames(); if (this._root_nodes.length > 0) { this.buildCodeFromNodes(this._root_nodes); this._buildLines(); } for (const shaderName of shaderNames) { const lines = this._lines.get(shaderName); if (lines) { this._shaders_by_name.set(shaderName, lines.join("\n")); } } } // // // CHILDREN NODES PARAMS // // add_output_inputs(outputNode) { outputNode.io.inputs.setNamedInputConnectionPoints([ new JsConnectionPoint(ObjectVariable.POSITION, JsConnectionPointType.VECTOR3), new JsConnectionPoint(ObjectVariable.ROTATION, JsConnectionPointType.EULER), new JsConnectionPoint(ObjectVariable.QUATERNION, JsConnectionPointType.QUATERNION), new JsConnectionPoint(ObjectVariable.SCALE, JsConnectionPointType.VECTOR3), new JsConnectionPoint(ObjectVariable.MATRIX, JsConnectionPointType.MATRIX4), new JsConnectionPoint(ObjectVariable.VISIBLE, JsConnectionPointType.BOOLEAN), new JsConnectionPoint(ObjectVariable.MATRIX_AUTO_UPDATE, JsConnectionPointType.BOOLEAN), new JsConnectionPoint(ObjectVariable.CAST_SHADOW, JsConnectionPointType.BOOLEAN), new JsConnectionPoint(ObjectVariable.RECEIVE_SHADOW, JsConnectionPointType.BOOLEAN), new JsConnectionPoint(ObjectVariable.FRUSTUM_CULLED, JsConnectionPointType.BOOLEAN) ]); } add_globals_outputs(globals_node) { globals_node.io.outputs.setNamedOutputConnectionPoints([ new JsConnectionPoint(ObjectVariable.OBJECT_3D, JsConnectionPointType.OBJECT_3D), new JsConnectionPoint(ObjectVariable.POSITION, JsConnectionPointType.VECTOR3), new JsConnectionPoint(ObjectVariable.ROTATION, JsConnectionPointType.EULER), new JsConnectionPoint(ObjectVariable.QUATERNION, JsConnectionPointType.QUATERNION), new JsConnectionPoint(ObjectVariable.SCALE, JsConnectionPointType.VECTOR3), new JsConnectionPoint(ObjectVariable.MATRIX, JsConnectionPointType.MATRIX4), new JsConnectionPoint(ObjectVariable.VISIBLE, JsConnectionPointType.BOOLEAN), new JsConnectionPoint(ObjectVariable.MATRIX_AUTO_UPDATE, JsConnectionPointType.BOOLEAN), new JsConnectionPoint(ObjectVariable.CAST_SHADOW, JsConnectionPointType.BOOLEAN), new JsConnectionPoint(ObjectVariable.RECEIVE_SHADOW, JsConnectionPointType.BOOLEAN), new JsConnectionPoint(ObjectVariable.FRUSTUM_CULLED, JsConnectionPointType.BOOLEAN), new JsConnectionPoint(ObjectVariable.OBJ_NUM, JsConnectionPointType.INT) ]); } // // // CONFIGS // // create_shader_configs() { return [ new JsShaderConfig( JsFunctionName.MAIN, [ ObjectVariable.POSITION, ObjectVariable.ROTATION, ObjectVariable.QUATERNION, ObjectVariable.SCALE, ObjectVariable.MATRIX, ObjectVariable.VISIBLE, // attribute AttributeJsNodeInput.EXPORT ], [] ) ]; } create_variable_configs() { return [ new VariableConfig(ObjectVariable.POSITION, { prefix: "return " }) // new VariableConfig('alpha', { // prefix: 'diffuseColor.a = ', // default: '1.0', // }), ]; } // // // TEMPLATE HOOKS // // // protected override insertDefineAfter(shader_name: ShaderName) { // return '// INSERT DEFINE'; // } // protected override insertBodyAfter(shader_name: ShaderName) { // return '// INSERT BODY'; // } // protected override linesToRemove(shader_name: ShaderName) { // return ['// INSERT DEFINE', '// INSERT BODY']; // } // private _handle_gl_FragCoord(body_lines: string[], shaderName: ShaderName, var_name: string) { // if (shaderName == ShaderName.FRAGMENT) { // body_lines.push(`vec4 ${var_name} = gl_FragCoord`); // } // } // private _handle_resolution(bodyLines: string[], shaderName: ShaderName, var_name: string) { // if (shaderName == ShaderName.FRAGMENT) { // bodyLines.push(`vec2 ${var_name} = resolution`); // } // } // private _handleUV(bodyLines: string[], shaderName: ShaderName, var_name: string) { // if (shaderName == ShaderName.FRAGMENT) { // bodyLines.push( // `vec2 ${var_name} = vec2(gl_FragCoord.x / (resolution.x-1.), gl_FragCoord.y / (resolution.y-1.))` // ); // } // } setNodeLinesOutput(outputNode, linesController) { const inputNames = this.inputNamesForShaderName(outputNode, linesController.currentShaderName()); const bodyLines = []; if (inputNames) { for (const inputName of inputNames) { const input = outputNode.io.inputs.named_input(inputName); if (input) { const varName = outputNode.variableForInput(linesController, inputName); switch (inputName) { case ObjectVariable.POSITION: case ObjectVariable.ROTATION: case ObjectVariable.QUATERNION: case ObjectVariable.SCALE: { bodyLines.push(`${ObjectBuilderAssemblerConstant.OBJECT_3D}.${inputName}.copy(${varName})`); break; } case ObjectVariable.MATRIX: { bodyLines.push(`${ObjectBuilderAssemblerConstant.OBJECT_3D}.${inputName}.copy(${varName})`); bodyLines.push(`${ObjectBuilderAssemblerConstant.OBJECT_3D}.${inputName}.decompose( ${ObjectBuilderAssemblerConstant.OBJECT_3D}.position, ${ObjectBuilderAssemblerConstant.OBJECT_3D}.quaternion, ${ObjectBuilderAssemblerConstant.OBJECT_3D}.scale )`); break; } case ObjectVariable.VISIBLE: case ObjectVariable.MATRIX_AUTO_UPDATE: case ObjectVariable.CAST_SHADOW: case ObjectVariable.RECEIVE_SHADOW: case ObjectVariable.FRUSTUM_CULLED: { bodyLines.push(`${ObjectBuilderAssemblerConstant.OBJECT_3D}.${inputName} = ${varName}`); break; } } } } } linesController._addBodyLines(outputNode, bodyLines); } setNodeLinesGlobals(globalsNode, linesController) { const shaderName = linesController.currentShaderName(); const shaderConfig = this.shader_config(shaderName); if (!shaderConfig) { return; } const bodyLines = []; const usedOutputNames = globalsNode.io.outputs.used_output_names(); for (const outputName of usedOutputNames) { const varName = globalsNode.jsVarName(outputName); switch (outputName) { case ObjectVariable.OBJECT_3D: { bodyLines.push(`${varName} = ${ObjectBuilderAssemblerConstant.OBJECT_3D}`); break; } case ObjectVariable.POSITION: case ObjectVariable.SCALE: { linesController.addVariable(globalsNode, new Vector3(), varName); bodyLines.push(`${varName}.copy(${ObjectBuilderAssemblerConstant.OBJECT_3D}.${outputName})`); break; } case ObjectVariable.ROTATION: { linesController.addVariable(globalsNode, new Euler(), varName); bodyLines.push(`${varName}.copy(${ObjectBuilderAssemblerConstant.OBJECT_3D}.${outputName})`); break; } case ObjectVariable.QUATERNION: { linesController.addVariable(globalsNode, new Quaternion(), varName); bodyLines.push(`${varName}.copy(${ObjectBuilderAssemblerConstant.OBJECT_3D}.${outputName})`); break; } case ObjectVariable.MATRIX: { linesController.addVariable(globalsNode, new Matrix4(), varName); bodyLines.push(`${varName}.copy(${ObjectBuilderAssemblerConstant.OBJECT_3D}.${outputName})`); break; } case ObjectVariable.VISIBLE: case ObjectVariable.MATRIX_AUTO_UPDATE: case ObjectVariable.CAST_SHADOW: case ObjectVariable.RECEIVE_SHADOW: case ObjectVariable.FRUSTUM_CULLED: { linesController.addVariable(globalsNode, new Vector3(), varName); bodyLines.push(`${varName} = ${ObjectBuilderAssemblerConstant.OBJECT_3D}.${outputName}`); break; } case ObjectVariable.OBJ_NUM: { bodyLines.push(`${varName} = ${ObjectBuilderAssemblerConstant.OBJ_NUM}`); break; } } } linesController._addBodyLines(globalsNode, bodyLines); } setNodeLinesAttribute(attributeNode, linesController) { const shaderName = linesController.currentShaderName(); const shaderConfig = this.shader_config(shaderName); if (!shaderConfig) { return; } const bodyLines = []; const attribName = attributeNode.attributeName(); const dataType = attributeNode.jsType(); if (attributeNode.isExporting()) { const func = Poly.namedFunctionsRegister.getFunction("setObjectAttribute", attributeNode, linesController); const exportedValue = attributeNode.variableForInput(linesController, AttributeJsNodeInput.EXPORT); const bodyLine = func.asString( ObjectBuilderAssemblerConstant.OBJECT_3D, `'${attribName}'`, `1`, exportedValue, `'${dataType}'` ); bodyLines.push(bodyLine); } const usedOutputNames = attributeNode.io.outputs.used_output_names(); for (const outputName of usedOutputNames) { const varName = attributeNode.jsVarName(outputName); const func = Poly.namedFunctionsRegister.getFunction( "getObjectAttributeAutoDefault", attributeNode, linesController ); const bodyLine = `${varName} = ` + func.asString(ObjectBuilderAssemblerConstant.OBJECT_3D, `'${attribName}'`, `'${dataType}'`); bodyLines.push(bodyLine); } linesController._addBodyLines(attributeNode, bodyLines); } }