@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
178 lines (177 loc) • 6.92 kB
JavaScript
;
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);
}
}