@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
155 lines (154 loc) • 5.57 kB
JavaScript
;
import { TypedSopNode } from "./_Base";
import { InputCloneMode } from "../../poly/InputCloneMode";
import { Attribute } from "../../../core/geometry/Attribute";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { isBooleanTrue } from "../../../core/BooleanValue";
import { SopType } from "../../poly/registers/nodes/types/Sop";
import { pointsFromObject } from "../../../core/geometry/entities/point/CorePointUtils";
import { corePointClassFactory } from "../../../core/geometry/CoreObjectFactory";
class NormalsSopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param toggle on if normals can be updated via expressions */
this.edit = ParamConfig.BOOLEAN(0);
/** @param toggle on to update the x component */
this.updateX = ParamConfig.BOOLEAN(0, {
visibleIf: { edit: 1 }
});
/** @param expression or value for the x component */
this.x = ParamConfig.FLOAT("@N.x", {
visibleIf: { updateX: 1, edit: 1 },
expression: { forEntities: true }
});
/** @param toggle on to update the y component */
this.updateY = ParamConfig.BOOLEAN(0, {
visibleIf: { edit: 1 }
});
/** @param expression or value for the y component */
this.y = ParamConfig.FLOAT("@N.y", {
visibleIf: { updateY: 1, edit: 1 },
expression: { forEntities: true }
});
/** @param toggle on to update the z component */
this.updateZ = ParamConfig.BOOLEAN(0, {
visibleIf: { edit: 1 }
});
/** @param expression or value for the z component */
this.z = ParamConfig.FLOAT("@N.z", {
visibleIf: { updateZ: 1, edit: 1 },
expression: { forEntities: true }
});
/** @param recompute the normals based on the position */
this.recompute = ParamConfig.BOOLEAN(1, {
visibleIf: { edit: 0 }
});
/** @param invert normals */
this.invert = ParamConfig.BOOLEAN(0);
}
}
const ParamsConfig = new NormalsSopParamsConfig();
export class NormalsSopNode extends TypedSopNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
}
static type() {
return SopType.NORMALS;
}
initializeNode() {
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE);
}
async cook(inputCoreGroups) {
const coreGroup = inputCoreGroups[0];
if (isBooleanTrue(this.pv.edit)) {
await this._evalExpressionsForCoreGroup(coreGroup);
} else {
if (this.pv.recompute) {
const objects = coreGroup.threejsObjectsWithGeo();
for (const object of objects) {
object.geometry.computeVertexNormals();
}
}
}
if (isBooleanTrue(this.pv.invert)) {
this._invertNormals(coreGroup);
}
this.setCoreGroup(coreGroup);
}
async _evalExpressionsForCoreGroup(coreGroup) {
const coreObjects = coreGroup.threejsCoreObjects();
for (const coreObject of coreObjects) {
await this._evalExpressionsForCoreObject(coreObject);
}
}
async _evalExpressionsForCoreObject(coreObject) {
const object = coreObject.object();
const geometry = object.geometry;
const points = [];
pointsFromObject(object, points);
const corePointClass = corePointClassFactory(object);
let attrib = geometry.getAttribute(Attribute.NORMAL);
if (!attrib) {
corePointClass.addNumericAttribute(object, Attribute.NORMAL, 3, 0);
attrib = geometry.getAttribute(Attribute.NORMAL);
}
const array = attrib.array;
if (isBooleanTrue(this.pv.updateX)) {
const param = this.p.x;
if (param.hasExpression() && param.expressionController && param.expressionController.entitiesDependent()) {
await param.expressionController.computeExpressionForPoints(points, (point, value) => {
array[point.index() * 3 + 0] = value;
});
} else {
let point;
for (let i = 0; i < points.length; i++) {
point = points[i];
array[point.index() * 3 + 0] = param.value;
}
}
}
if (isBooleanTrue(this.pv.updateY)) {
const param = this.p.y;
if (param.hasExpression() && param.expressionController && param.expressionController.entitiesDependent()) {
await param.expressionController.computeExpressionForPoints(points, (point, value) => {
array[point.index() * 3 + 1] = value;
});
} else {
let point;
for (let i = 0; i < points.length; i++) {
point = points[i];
array[point.index() * 3 + 1] = param.value;
}
}
}
if (isBooleanTrue(this.pv.updateZ)) {
const param = this.p.z;
if (param.hasExpression() && param.expressionController && param.expressionController.entitiesDependent()) {
await param.expressionController.computeExpressionForPoints(points, (point, value) => {
array[point.index() * 3 + 2] = value;
});
} else {
let point;
for (let i = 0; i < points.length; i++) {
point = points[i];
array[point.index() * 3 + 2] = param.value;
}
}
}
}
_invertNormals(coreGroup) {
const objects = coreGroup.allObjects();
for (const object of objects) {
const corePointClass = corePointClassFactory(object);
const normalAttrib = corePointClass.attribute(object, Attribute.NORMAL);
if (normalAttrib) {
const array = normalAttrib.array;
for (let i = 0; i < array.length; i++) {
array[i] *= -1;
}
}
}
}
}