polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
261 lines (260 loc) • 10.6 kB
JavaScript
import {Vector2 as Vector22} from "three/src/math/Vector2";
import {Vector3 as Vector32} from "three/src/math/Vector3";
import {Vector4 as Vector42} from "three/src/math/Vector4";
import {TypedSopNode} from "./_Base";
import {CoreMath} from "../../../core/math/_Module";
import {InputCloneMode as InputCloneMode2} from "../../poly/InputCloneMode";
import {TypeAssert} from "../../poly/Assert";
import {SimplexNoise as SimplexNoise2} from "../../../modules/three/examples/jsm/math/SimplexNoise";
var Operation;
(function(Operation2) {
Operation2["ADD"] = "add";
Operation2["SET"] = "set";
Operation2["MULT"] = "mult";
Operation2["SUBSTRACT"] = "substract";
Operation2["DIVIDE"] = "divide";
})(Operation || (Operation = {}));
const Operations = [Operation.ADD, Operation.SET, Operation.MULT, Operation.SUBSTRACT, Operation.DIVIDE];
const ATTRIB_NORMAL = "normal";
import {NodeParamsConfig, ParamConfig} from "../utils/params/ParamsConfig";
import {CoreType} from "../../../core/Type";
class NoiseSopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
this.amplitude = ParamConfig.FLOAT(1);
this.tamplitudeAttrib = ParamConfig.BOOLEAN(0);
this.amplitudeAttrib = ParamConfig.STRING("amp", {visibleIf: {tamplitudeAttrib: true}});
this.freq = ParamConfig.VECTOR3([1, 1, 1]);
this.offset = ParamConfig.VECTOR3([0, 0, 0]);
this.octaves = ParamConfig.INTEGER(3, {
range: [1, 8],
rangeLocked: [true, false]
});
this.ampAttenuation = ParamConfig.FLOAT(0.5, {range: [0, 1]});
this.freqIncrease = ParamConfig.FLOAT(2, {range: [0, 10]});
this.seed = ParamConfig.INTEGER(0, {range: [0, 100]});
this.separator = ParamConfig.SEPARATOR();
this.useNormals = ParamConfig.BOOLEAN(0);
this.attribName = ParamConfig.STRING("position");
this.useRestAttributes = ParamConfig.BOOLEAN(0);
this.restP = ParamConfig.STRING("restP", {visibleIf: {useRestAttributes: true}});
this.restN = ParamConfig.STRING("restN", {visibleIf: {useRestAttributes: true}});
this.operation = ParamConfig.INTEGER(Operations.indexOf(Operation.ADD), {
menu: {
entries: Operations.map((operation) => {
return {
name: operation,
value: Operations.indexOf(operation)
};
})
}
});
this.computeNormals = ParamConfig.BOOLEAN(1);
}
}
const ParamsConfig2 = new NoiseSopParamsConfig();
export class NoiseSopNode extends TypedSopNode {
constructor() {
super(...arguments);
this.params_config = ParamsConfig2;
this._simplex_by_seed = new Map();
this._rest_pos = new Vector32();
this._rest_value2 = new Vector22();
this._noise_value_v = new Vector32();
}
static type() {
return "noise";
}
static displayedInputNames() {
return ["geometry to add noise to"];
}
initializeNode() {
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState([InputCloneMode2.FROM_NODE]);
}
async cook(input_contents) {
const core_group = input_contents[0];
const dest_points = core_group.points();
const simplex = this._get_simplex();
const useNormals = this.pv.useNormals && core_group.hasAttrib(ATTRIB_NORMAL);
const target_attrib_size = core_group.attribSize(this.pv.attribName);
const operation = Operations[this.pv.operation];
const dest_attribName = this.pv.attribName;
const useRestAttributes = this.pv.useRestAttributes;
const base_amplitude = this.pv.amplitude;
const use_amplitudeAttrib = this.pv.tamplitudeAttrib;
let restP;
let restN;
let current_attrib_value;
for (let i = 0; i < dest_points.length; i++) {
const dest_point = dest_points[i];
current_attrib_value = dest_point.attribValue(dest_attribName);
if (useRestAttributes) {
restP = dest_point.attribValue(this.pv.restP);
restN = useNormals ? dest_point.attribValue(this.pv.restN) : void 0;
current_attrib_value = restP;
} else {
restN = useNormals ? dest_point.attribValue("normal") : void 0;
}
const amplitude = use_amplitudeAttrib ? this._amplitude_from_attrib(dest_point, base_amplitude) : base_amplitude;
const noise_result = this._noise_value(useNormals, simplex, amplitude, current_attrib_value, restN);
const noise_value = this._make_noise_value_correct_size(noise_result, target_attrib_size);
if (CoreType.isNumber(current_attrib_value) && CoreType.isNumber(noise_value)) {
const new_attrib_value_f = this._new_attrib_value_from_float(operation, current_attrib_value, noise_value);
dest_point.setAttribValue(dest_attribName, new_attrib_value_f);
} else {
if (current_attrib_value instanceof Vector22 && noise_value instanceof Vector22) {
const new_attrib_value_v = this._new_attrib_value_from_vector2(operation, current_attrib_value, noise_value);
dest_point.setAttribValue(dest_attribName, new_attrib_value_v);
} else {
if (current_attrib_value instanceof Vector32 && noise_value instanceof Vector32) {
const new_attrib_value_v = this._new_attrib_value_from_vector3(operation, current_attrib_value, noise_value);
dest_point.setAttribValue(dest_attribName, new_attrib_value_v);
} else {
if (current_attrib_value instanceof Vector42 && noise_value instanceof Vector42) {
const new_attrib_value_v = this._new_attrib_value_from_vector4(operation, current_attrib_value, noise_value);
dest_point.setAttribValue(dest_attribName, new_attrib_value_v);
}
}
}
}
}
if (!this.io.inputs.clone_required(0)) {
for (let geometry of core_group.geometries()) {
geometry.getAttribute(dest_attribName).needsUpdate = true;
}
}
if (this.pv.computeNormals) {
core_group.computeVertexNormals();
}
this.setCoreGroup(core_group);
}
_noise_value(useNormals, simplex, amplitude, restP, restN) {
this._rest_pos.copy(restP).add(this.pv.offset).multiply(this.pv.freq);
if (useNormals && restN) {
const noise = amplitude * this._fbm(simplex, this._rest_pos.x, this._rest_pos.y, this._rest_pos.z);
this._noise_value_v.copy(restN);
return this._noise_value_v.multiplyScalar(noise);
} else {
this._noise_value_v.set(amplitude * this._fbm(simplex, this._rest_pos.x + 545, this._rest_pos.y + 125454, this._rest_pos.z + 2142), amplitude * this._fbm(simplex, this._rest_pos.x - 425, this._rest_pos.y - 25746, this._rest_pos.z + 95242), amplitude * this._fbm(simplex, this._rest_pos.x + 765132, this._rest_pos.y + 21, this._rest_pos.z - 9245));
return this._noise_value_v;
}
}
_make_noise_value_correct_size(noise_value, target_attrib_size) {
switch (target_attrib_size) {
case 1:
return noise_value.x;
case 2:
this._rest_value2.set(noise_value.x, noise_value.y);
return this._rest_value2;
case 3:
return noise_value;
default:
return noise_value;
}
}
_new_attrib_value_from_float(operation, current_attrib_value, noise_value) {
switch (operation) {
case Operation.ADD:
return current_attrib_value + noise_value;
case Operation.SET:
return noise_value;
case Operation.MULT:
return current_attrib_value * noise_value;
case Operation.DIVIDE:
return current_attrib_value / noise_value;
case Operation.SUBSTRACT:
return current_attrib_value - noise_value;
}
TypeAssert.unreachable(operation);
}
_new_attrib_value_from_vector2(operation, current_attrib_value, noise_value) {
switch (operation) {
case Operation.ADD:
return current_attrib_value.add(noise_value);
case Operation.SET:
return noise_value;
case Operation.MULT:
return current_attrib_value.multiply(noise_value);
case Operation.DIVIDE:
return current_attrib_value.divide(noise_value);
case Operation.SUBSTRACT:
return current_attrib_value.sub(noise_value);
}
TypeAssert.unreachable(operation);
}
_new_attrib_value_from_vector3(operation, current_attrib_value, noise_value) {
switch (operation) {
case Operation.ADD:
return current_attrib_value.add(noise_value);
case Operation.SET:
return noise_value;
case Operation.MULT:
return current_attrib_value.multiply(noise_value);
case Operation.DIVIDE:
return current_attrib_value.divide(noise_value);
case Operation.SUBSTRACT:
return current_attrib_value.sub(noise_value);
}
TypeAssert.unreachable(operation);
}
_new_attrib_value_from_vector4(operation, current_attrib_value, noise_value) {
switch (operation) {
case Operation.ADD:
return current_attrib_value.add(noise_value);
case Operation.SET:
return noise_value;
case Operation.MULT:
return current_attrib_value.multiplyScalar(noise_value.x);
case Operation.DIVIDE:
return current_attrib_value.divideScalar(noise_value.x);
case Operation.SUBSTRACT:
return current_attrib_value.sub(noise_value);
}
TypeAssert.unreachable(operation);
}
_amplitude_from_attrib(point, base_amplitude) {
const attrib_value = point.attribValue(this.pv.amplitudeAttrib);
if (CoreType.isNumber(attrib_value)) {
return attrib_value * base_amplitude;
} else {
if (attrib_value instanceof Vector22 || attrib_value instanceof Vector32 || attrib_value instanceof Vector42) {
return attrib_value.x * base_amplitude;
}
}
return 1;
}
_fbm(simplex, x, y, z) {
let value = 0;
let amplitude = 1;
for (let i = 0; i < this.pv.octaves; i++) {
value += amplitude * simplex.noise3d(x, y, z);
x *= this.pv.freqIncrease;
y *= this.pv.freqIncrease;
z *= this.pv.freqIncrease;
amplitude *= this.pv.ampAttenuation;
}
return value;
}
_get_simplex() {
const simplex = this._simplex_by_seed.get(this.pv.seed);
if (simplex) {
return simplex;
} else {
const simplex2 = this._create_simplex();
this._simplex_by_seed.set(this.pv.seed, simplex2);
return simplex2;
}
}
_create_simplex() {
const seed = this.pv.seed;
const random_generator = {
random: function() {
return CoreMath.rand_float(seed);
}
};
const simplex = new SimplexNoise2(random_generator);
this._simplex_by_seed.delete(seed);
return simplex;
}
}