UNPKG

@polygonjs/polygonjs

Version:

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

178 lines (177 loc) 6.92 kB
"use strict"; import { TypedSubnetGlNode, TypedSubnetGlParamsConfigMixin } from "./Subnet"; import { GlConnectionPointType, GL_CONNECTION_POINT_TYPES } from "../utils/io/connections/Gl"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { ThreeToGl } from "../../../core/ThreeToGl"; import { FunctionGLDefinition } from "./utils/GLDefinition"; import { LineType } from "./code/utils/LineType"; import { GlType } from "../../poly/registers/nodes/types/Gl"; const POSITION_INPUT_NAME = "position"; const GRADIENT_OUTPUT_NAME = "gradient"; const SDF_OUTPUT_NAME = "sdf"; const GRADIENT_FUNCTION_NAME = "gradientFunction"; const SDF_FUNCTION_NAME = "sdfFunction"; function gradientFunction(options) { const { sdfFunctionName, gradientFunctionName, epsilon, additionalArguments } = options; additionalArguments.shift(); const otherArgsDefinition = additionalArguments.length > 0 ? `, ${additionalArguments.join(", ")}` : ""; const otherArgsWithoutGlType = additionalArguments.map((arg) => { const elements = arg.split(" "); return elements[elements.length - 1]; }); const otherArgsCall = otherArgsWithoutGlType.length > 0 ? `, ${otherArgsWithoutGlType.join(", ")}` : ""; const functionDefinition = ` vec3 ${gradientFunctionName}( in vec3 p${otherArgsDefinition} ) { const float eps = ${epsilon}; const vec2 h = vec2(eps,0); return normalize( vec3( ${sdfFunctionName}(p+h.xyy${otherArgsCall}) - ${sdfFunctionName}(p-h.xyy${otherArgsCall}), ${sdfFunctionName}(p+h.yxy${otherArgsCall}) - ${sdfFunctionName}(p-h.yxy${otherArgsCall}), ${sdfFunctionName}(p+h.yyx${otherArgsCall}) - ${sdfFunctionName}(p-h.yyx${otherArgsCall}) ) ); } `; return functionDefinition; } class SDFGradientGlParamsConfig extends TypedSubnetGlParamsConfigMixin(NodeParamsConfig) { constructor() { super(...arguments); this.epsilon = ParamConfig.FLOAT(1e-4, { range: [1e-9, 1], rangeLocked: [false, false] }); } } const ParamsConfig = new SDFGradientGlParamsConfig(); export class SDFGradientGlNode extends TypedSubnetGlNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; } static type() { return GlType.SDF_GRADIENT; } _expectedInputsCount() { return super._expectedInputsCount() + 1; } _expectedInputTypes() { return [GlConnectionPointType.VEC3].concat(super._expectedInputTypes()); } _expectedOutputTypes() { return [GlConnectionPointType.FLOAT, GlConnectionPointType.VEC3]; } _expectedInputName(index) { if (index == 0) { return POSITION_INPUT_NAME; } else { return super._expectedInputName(index - 1); } } _expectedOutputName(index) { return [SDF_OUTPUT_NAME, GRADIENT_OUTPUT_NAME][index]; } childExpectedOutputConnectionPointTypes() { return [GlConnectionPointType.FLOAT]; } childExpectedOutputConnectionPointName(index) { return SDF_OUTPUT_NAME; } // // // set_lines // // setSubnetInputLines(shadersCollectionController, childNode) { const bodyLines = []; const position = childNode.glVarName(POSITION_INPUT_NAME); bodyLines.push(` vec3 ${position} = ${POSITION_INPUT_NAME}`); const otherInputsCount = this.pv.inputsCount; for (let i = 0; i < otherInputsCount; i++) { const inputName = this._inputNameParams()[i].value; const varName = childNode.glVarName(inputName); const glType = GL_CONNECTION_POINT_TYPES[this._inputTypeParams()[i].value]; bodyLines.push(` ${glType} ${varName} = ${inputName}`); } shadersCollectionController.addBodyLines(childNode, bodyLines); } setSubnetOutputLines(shadersCollectionController, childNode) { const connections = childNode.io.connections.inputConnections(); const connection = connections ? connections[0] : null; if (!connection) { shadersCollectionController.addBodyLines(childNode, [`return 0.0`]); return; } const connectionPoint = connection.destConnectionPoint(); if (!connectionPoint) { return; } const inValue = ThreeToGl.any(childNode.variableForInput(connectionPoint.name())); const bodyLine = `return ${inValue}`; shadersCollectionController.addBodyLines(childNode, [bodyLine]); } setLines(shadersCollectionController) { const functionArguments = { definition: [], call: [] }; const position = ThreeToGl.any(this.variableForInput(POSITION_INPUT_NAME)); functionArguments.definition.push(`vec3 ${POSITION_INPUT_NAME}`); functionArguments.call.push(position); const otherInputsCount = this.pv.inputsCount; for (let i = 0; i < otherInputsCount; i++) { const inputName = this._inputNameParams()[i].value; const glType = GL_CONNECTION_POINT_TYPES[this._inputTypeParams()[i].value]; const inputVal = ThreeToGl.any(this.variableForInput(inputName)); functionArguments.definition.push(`${glType} ${inputName}`); functionArguments.call.push(inputVal); } const options = { name: { sdf: this.glVarName(SDF_FUNCTION_NAME), gradient: this.glVarName(GRADIENT_FUNCTION_NAME) }, arguments: functionArguments }; this._declareFunctions(shadersCollectionController, options); this._callFunctions(shadersCollectionController, options); } _declareFunctions(shadersCollectionController, options) { const codeBuilder = this._runCodeBuilder(shadersCollectionController); if (!codeBuilder) { return; } const shadername = shadersCollectionController.currentShaderName(); const bodyLines = codeBuilder.lines(shadername, LineType.BODY); const sdfFunctionLines = [ `float ${options.name.sdf}(${options.arguments.definition.join(", ")}){`, ...this._sanitizeBodyLines(bodyLines), `}` ].join("\n"); const gradientFunctionLines = gradientFunction({ epsilon: this.pv.epsilon, sdfFunctionName: options.name.sdf, gradientFunctionName: options.name.gradient, additionalArguments: options.arguments.definition }); shadersCollectionController.addDefinitions(this, [ new FunctionGLDefinition(this, sdfFunctionLines), new FunctionGLDefinition(this, gradientFunctionLines) ]); } _callFunctions(shadersCollectionController, options) { const used_output_names = this.io.outputs.used_output_names(); const bodyLines = []; if (used_output_names.indexOf(SDF_OUTPUT_NAME) >= 0) { const varName = this.glVarName(SDF_OUTPUT_NAME); bodyLines.push(`float ${varName} = ${options.name.sdf}(${options.arguments.call.join(", ")})`); } if (used_output_names.indexOf(GRADIENT_OUTPUT_NAME) >= 0) { const varName = this.glVarName(GRADIENT_OUTPUT_NAME); bodyLines.push(`vec3 ${varName} = ${options.name.gradient}(${options.arguments.call.join(", ")})`); } shadersCollectionController.addBodyLines(this, bodyLines); } }