@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
161 lines (151 loc) • 6.05 kB
text/typescript
/**
* Creates a plane with a distorted reflection, to simulate an ocean surface
*
* @remarks
*
* Without any input, this node creates a very large plane.
* If you would like the ocean to be restricted to a smaller area, such as a disk,
* you can plug in an input geometry. Just make sure that this geometry should be facing the z axis,
* as it will currently be rotated internally to face the y axis. Note that this behavior may change in the future
* to be made more intuitive.
*
*/
import {TypedSopNode} from './_Base';
import {CoreGroup} from '../../../core/geometry/Group';
import {DEFAULT_PARAMS, DEFAULT_OCEAN_PARAMS} from '../../operations/sop/OceanPlane';
import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig';
import {Number3} from '../../../types/GlobalTypes';
import {Poly} from '../../Poly';
import {Object3D, Mesh} from 'three';
import {isBooleanTrue} from '../../../core/Type';
import {Water, WaterOptions} from '../../../modules/core/objects/Water';
import {replaceChild} from '../../poly/PolyOnObjectsAddRemoveHooksController';
const DEFAULT = DEFAULT_PARAMS;
class OceanPlaneSopParamsConfig extends NodeParamsConfig {
main = ParamConfig.FOLDER();
/** @param reflection direction */
direction = ParamConfig.VECTOR3(DEFAULT.direction.toArray());
/** @param sun direction */
sunDirection = ParamConfig.VECTOR3(DEFAULT.sunDirection.toArray());
/** @param sun color */
sunColor = ParamConfig.COLOR(DEFAULT.sunColor.toArray() as Number3);
/** @param water color */
waterColor = ParamConfig.COLOR(DEFAULT.waterColor.toArray() as Number3);
/** @param reflection color */
reflectionColor = ParamConfig.COLOR(DEFAULT.reflectionColor.toArray() as Number3);
/** @param reflection fresnel */
reflectionFresnel = ParamConfig.FLOAT(DEFAULT.reflectionFresnel);
/** @param waves Height */
wavesHeight = ParamConfig.FLOAT(DEFAULT.wavesHeight, {
range: [0, 10],
rangeLocked: [false, false],
});
/** @param distortion scale */
distortionScale = ParamConfig.FLOAT(DEFAULT.distortionScale, {
range: [0, 1],
rangeLocked: [true, false],
});
/** @param distortion speed */
timeScale = ParamConfig.FLOAT(DEFAULT.timeScale, {
range: [0, 2],
rangeLocked: [true, false],
});
/** @param size */
size = ParamConfig.FLOAT(DEFAULT.size, {
range: [0, 100],
rangeLocked: [true, false],
});
advanced = ParamConfig.FOLDER();
/** @param render reflection */
renderReflection = ParamConfig.BOOLEAN(DEFAULT.renderReflection);
/** @param normal Bias - adjusts this if the reflections are too grainy */
normalBias = ParamConfig.FLOAT(DEFAULT.normalBias, {
range: [0, 0.1],
rangeLocked: [false, false],
});
/** @param multisamples */
multisamples = ParamConfig.INTEGER(DEFAULT.multisamples, {
range: [0, 4],
rangeLocked: [true, false],
});
/** @param reacts to fog */
useFog = ParamConfig.BOOLEAN(DEFAULT.useFog);
}
const ParamsConfig = new OceanPlaneSopParamsConfig();
export class OceanPlaneSopNode extends TypedSopNode<OceanPlaneSopParamsConfig> {
override paramsConfig = ParamsConfig;
static override type() {
return 'oceanPlane';
}
override initializeNode() {
this.io.inputs.setCount(1);
}
override cook(inputCoreGroups: CoreGroup[]) {
const coreGroup = inputCoreGroups[0];
const objects = coreGroup.threejsObjectsWithGeo();
for (const object of objects) {
Poly.onObjectsAddRemoveHooks.assignOnAddHookHandler(object, this);
}
this.setCoreGroup(coreGroup);
}
public override updateObjectOnAdd(object: Object3D, parent: Object3D) {
const _geometry = (object as Mesh).geometry;
if (!_geometry) {
return;
}
// since the geometry is rotated in this method,
// we could end up with rotating it multiple times
// if we were to toggle the display flag between this node and another.
// The current fix is to clone the geometry before transforming it.
const clonedGeometry = _geometry.clone();
const scene = this.scene();
const renderer = scene.renderersRegister.lastRegisteredRenderer();
Water.rotateGeometry(clonedGeometry, this.pv.direction);
const waterOptions: WaterOptions = {
polyScene: this.scene(),
scene: scene.threejsScene(),
renderer,
...DEFAULT_OCEAN_PARAMS,
direction: this.pv.direction,
sunDirection: this.pv.sunDirection,
sunColor: this.pv.sunColor,
wavesHeight: this.pv.wavesHeight,
waterColor: this.pv.waterColor,
reflectionColor: this.pv.reflectionColor,
reflectionFresnel: this.pv.reflectionFresnel,
distortionScale: this.pv.distortionScale,
timeScale: this.pv.timeScale,
size: this.pv.size,
// renderReflection: params.renderReflection,
normalBias: this.pv.normalBias,
multisamples: this.pv.multisamples,
useFog: this.pv.useFog,
};
const water = new Water(clonedGeometry, waterOptions);
water.matrixAutoUpdate = false;
// make sure object attributes are up to date
object.matrix.decompose(object.position, object.quaternion, object.scale);
water.position.copy(object.position);
water.rotation.copy(object.rotation);
water.scale.copy(object.scale);
water.updateMatrix();
Water.compensateGeometryRotation(water, this.pv.direction);
//
// water.updateMatrix();
// water.matrixAutoUpdate = false;
const material = water.material;
material.uniforms.direction.value.copy(this.pv.direction);
material.uniforms.sunDirection.value.copy(this.pv.sunDirection);
material.uniforms.sunColor.value.copy(this.pv.sunColor);
material.uniforms.wavesHeight.value = this.pv.wavesHeight;
material.uniforms.waterColor.value.copy(this.pv.waterColor);
material.uniforms.reflectionColor.value.copy(this.pv.reflectionColor);
material.uniforms.reflectionFresnel.value = this.pv.reflectionFresnel;
material.uniforms.distortionScale.value = this.pv.distortionScale;
material.uniforms.timeScale.value = this.pv.timeScale;
material.uniforms.size.value = this.pv.size;
material.uniforms.normalBias.value = this.pv.normalBias;
water.setReflectionActive(isBooleanTrue(this.pv.renderReflection));
replaceChild(parent, object, water);
}
}