@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
213 lines (212 loc) • 7.49 kB
JavaScript
"use strict";
import { BaseSDFGlNode } from "./_BaseSDF";
import { ThreeToGl } from "../../../../src/core/ThreeToGl";
import SDFRepeatMethods from "./gl/raymarching/sdfRepeat.glsl";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { GlConnectionPointType, GlConnectionPoint } from "../utils/io/connections/Gl";
import { FunctionGLDefinition } from "./utils/GLDefinition";
import { isBooleanTrue } from "../../../core/Type";
const OUTPUT_NAME = "p";
const clampVisibility = [{ repeatX: 1 }, { repeatY: 1 }, { repeatZ: 1 }];
const clampAxisVisibility = clampVisibility.map((option) => ({ ...option, clamped: 1 }));
const clampAxisBoundVisibilityX = clampAxisVisibility.map((option) => ({
...option,
clampedX: 1
}));
const clampAxisBoundVisibilityY = clampAxisVisibility.map((option) => ({
...option,
clampedY: 1
}));
const clampAxisBoundVisibilityZ = clampAxisVisibility.map((option) => ({
...option,
clampedZ: 1
}));
class SDFRepeatGlParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
this.position = ParamConfig.VECTOR3([0, 0, 0], { hidden: true });
this.center = ParamConfig.VECTOR3([0, 0, 0]);
this.period = ParamConfig.VECTOR3([1, 1, 1]);
this.repeatX = ParamConfig.BOOLEAN(1);
this.repeatY = ParamConfig.BOOLEAN(1);
this.repeatZ = ParamConfig.BOOLEAN(1);
this.clamped = ParamConfig.BOOLEAN(0, { visibleIf: clampVisibility });
this.clampedX = ParamConfig.BOOLEAN(0, { visibleIf: clampAxisVisibility });
this.boundX = ParamConfig.VECTOR2([-1, 1], { visibleIf: clampAxisBoundVisibilityX });
this.clampedY = ParamConfig.BOOLEAN(0, { visibleIf: clampAxisVisibility });
this.boundY = ParamConfig.VECTOR2([-1, 1], { visibleIf: clampAxisBoundVisibilityY });
this.clampedZ = ParamConfig.BOOLEAN(0, { visibleIf: clampAxisVisibility });
this.boundZ = ParamConfig.VECTOR2([-1, 1], { visibleIf: clampAxisBoundVisibilityZ });
}
}
const ParamsConfig = new SDFRepeatGlParamsConfig();
export class SDFRepeatGlNode extends BaseSDFGlNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
}
static type() {
return "SDFRepeat";
}
initializeNode() {
super.initializeNode();
this.io.connection_points.spare_params.setInputlessParamNames([
"repeatX",
"repeatY",
"repeatZ",
"clamped",
"clampedX",
"clampedY",
"clampedZ"
]);
this.io.outputs.setNamedOutputConnectionPoints([
new GlConnectionPoint(OUTPUT_NAME, GlConnectionPointType.VEC3)
]);
}
setLines(shadersCollectionController) {
const position = this.position();
const center = ThreeToGl.vector3(this.variableForInputParam(this.p.center));
const period = ThreeToGl.vector3(this.variableForInputParam(this.p.period));
const float = this.glVarName(OUTPUT_NAME);
const functionName = `SDFRepeat${this._functionSuffixUnclamped()}`;
const bodyLines = [];
if (this.clamped()) {
const boundMin = this.glVarName("boundMin");
const boundMax = this.glVarName("boundMax");
const boundX = ThreeToGl.vector3(this.variableForInputParam(this.p.boundX));
const boundY = ThreeToGl.vector3(this.variableForInputParam(this.p.boundY));
const boundZ = ThreeToGl.vector3(this.variableForInputParam(this.p.boundZ));
const clampedAxisesCount = this._clampedAxisesCount();
switch (clampedAxisesCount) {
case 1: {
let bounds = boundX;
if (this.clampedX()) {
bounds = boundX;
} else {
if (this.clampedY()) {
bounds = boundY;
} else {
bounds = boundZ;
}
}
bodyLines.push(`float ${boundMin} = ${bounds}.x`, `float ${boundMax} = ${bounds}.y`);
break;
}
case 2: {
let bounds1 = boundX;
let bounds2 = boundY;
if (this.clampedX()) {
bounds1 = boundX;
if (this.clampedY()) {
bounds2 = boundY;
} else {
bounds2 = boundZ;
}
} else {
bounds1 = boundY;
bounds2 = boundZ;
}
bodyLines.push(
`vec2 ${boundMin} = vec2(${bounds1}.x, ${bounds2}.x)`,
`vec2 ${boundMax} = vec2(${bounds1}.y, ${bounds2}.y)`
);
break;
}
case 3: {
bodyLines.push(
`vec3 ${boundMin} = vec3(${boundX}.x,${boundY}.x,${boundZ}.x)`,
`vec3 ${boundMax} = vec3(${boundX}.y,${boundY}.y,${boundZ}.y)`
);
break;
}
}
bodyLines.push(
`vec3 ${float} = ${functionName}(${position} - ${center}, ${period}, ${boundMin}, ${boundMax})`
);
} else {
bodyLines.push(`vec3 ${float} = ${functionName}(${position} - ${center}, ${period})`);
}
shadersCollectionController.addBodyLines(this, bodyLines);
shadersCollectionController.addDefinitions(this, [new FunctionGLDefinition(this, SDFRepeatMethods)]);
}
_clampedAxisesCount() {
let count = 0;
if (this.clampedX()) {
count++;
}
if (this.clampedY()) {
count++;
}
if (this.clampedZ()) {
count++;
}
return count;
}
repeatAll() {
const x = isBooleanTrue(this.pv.repeatX);
const y = isBooleanTrue(this.pv.repeatY);
const z = isBooleanTrue(this.pv.repeatZ);
return x && y && z || !(x || y || z);
}
clamped() {
const x = isBooleanTrue(this.pv.repeatX);
const y = isBooleanTrue(this.pv.repeatY);
const z = isBooleanTrue(this.pv.repeatZ);
const clamped = isBooleanTrue(this.pv.clamped);
const clampedX = isBooleanTrue(this.pv.clampedX);
const clampedY = isBooleanTrue(this.pv.clampedY);
const clampedZ = isBooleanTrue(this.pv.clampedZ);
return clamped && (x && clampedX || y && clampedY || z && clampedZ);
}
clampedX() {
const x = isBooleanTrue(this.pv.repeatX);
const clamped = isBooleanTrue(this.pv.clamped);
const clampedX = isBooleanTrue(this.pv.clampedX);
return clamped && x && clampedX;
}
clampedY() {
const y = isBooleanTrue(this.pv.repeatY);
const clamped = isBooleanTrue(this.pv.clamped);
const clampedY = isBooleanTrue(this.pv.clampedY);
return clamped && y && clampedY;
}
clampedZ() {
const z = isBooleanTrue(this.pv.repeatZ);
const clamped = isBooleanTrue(this.pv.clamped);
const clampedZ = isBooleanTrue(this.pv.clampedZ);
return clamped && z && clampedZ;
}
clampedAll() {
return this.clampedX() && this.clampedY() && this.clampedZ();
}
_functionSuffixUnclamped() {
const x = isBooleanTrue(this.pv.repeatX);
const y = isBooleanTrue(this.pv.repeatY);
const z = isBooleanTrue(this.pv.repeatZ);
const repeatAll = this.repeatAll();
const args = [];
if (!repeatAll) {
if (x)
args.push("X");
if (y)
args.push("Y");
if (z)
args.push("Z");
}
const clampedX = isBooleanTrue(this.pv.clampedX);
const clampedY = isBooleanTrue(this.pv.clampedY);
const clampedZ = isBooleanTrue(this.pv.clampedZ);
if (this.clamped()) {
args.push("Clamped");
if (!this.clampedAll()) {
if ((repeatAll || x) && clampedX)
args.push("X");
if ((repeatAll || y) && clampedY)
args.push("Y");
if ((repeatAll || z) && clampedZ)
args.push("Z");
}
}
return args.join("");
}
}