UNPKG

polygonjs-engine

Version:

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

261 lines (260 loc) 10.6 kB
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; } }