@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
146 lines (125 loc) • 4.27 kB
text/typescript
import {ParamConfig} from '../../engine/nodes/utils/params/ParamsConfig';
import {Constructor, Number3} from '../../types/GlobalTypes';
// import {ColorConversion} from '../Color';
import {DefaultOperationParams} from '../operations/_Base';
import {
Color,
Group,
BackSide,
BufferGeometry,
Float32BufferAttribute,
Line,
LineBasicMaterial,
Mesh,
MeshBasicMaterial,
RectAreaLight,
} from 'three';
export interface AreaLightParams extends DefaultOperationParams {
color: Color;
intensity: number;
width: number;
height: number;
showHelper: boolean;
name: string;
}
export const DEFAULT_AREA_LIGHT_PARAMS: AreaLightParams = {
color: new Color(1, 1, 1),
intensity: 1,
width: 1,
height: 1,
showHelper: false,
name: 'areaLight',
};
const DEFAULT = DEFAULT_AREA_LIGHT_PARAMS;
export function AreaLightParamConfig<TBase extends Constructor>(Base: TBase) {
return class Mixin extends Base {
light = ParamConfig.FOLDER();
/** @param light color */
color = ParamConfig.COLOR(DEFAULT.color.toArray() as Number3, {
// conversion: ColorConversion.SRGB_TO_LINEAR,
});
/** @param light intensity */
intensity = ParamConfig.FLOAT(DEFAULT.intensity, {
range: [0, 10],
rangeLocked: [true, false],
});
/** @param grid width */
width = ParamConfig.FLOAT(DEFAULT.width, {
range: [0, 10],
rangeLocked: [true, false],
});
/** @param grid height */
height = ParamConfig.FLOAT(DEFAULT.height, {
range: [0, 10],
rangeLocked: [true, false],
});
// helper
/** @param toggle on to show helper */
showHelper = ParamConfig.BOOLEAN(DEFAULT.showHelper);
/** @param light name */
name = ParamConfig.STRING('`$OS`');
};
}
/**
* This helper must be added as a child of the light
*/
function createLineGeo() {
const geometry = new BufferGeometry();
const positions = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0, 1, 1, 0].map((i) => i * 0.5);
geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
geometry.computeBoundingSphere();
return geometry;
}
function createMeshGeo() {
const positions = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0].map((i) => i * 0.5);
const geometry = new BufferGeometry();
geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
geometry.computeBoundingSphere();
return geometry;
}
// inherits from Group and not Line, to ensure that .copy can pass the recursive argument
export class CoreRectAreaLightHelper extends Group {
public _childMesh = new Mesh(createMeshGeo(), new MeshBasicMaterial({side: BackSide, fog: false}));
public _childLine = new Line(createLineGeo(), new LineBasicMaterial());
constructor(public light: RectAreaLight, public readonly nodeName: string) {
super();
this.matrixAutoUpdate = false;
this._childMesh.matrixAutoUpdate = false;
this._childLine.matrixAutoUpdate = false;
this.name = `CoreRectAreaLightHelper_${this.nodeName}`;
this._childMesh.name = `CoreRectAreaLightHelperChildMesh_${this.nodeName}`;
this._childLine.name = `CoreRectAreaLightHelperChildLine_${this.nodeName}`;
this.add(this._childMesh);
this.add(this._childLine);
}
update() {
this.scale.set(1 * this.light.width, 1 * this.light.height, 1);
this.updateMatrix();
this._childLine.material.color.copy(this.light.color).multiplyScalar(this.light.intensity);
// prevent hue shift
const c = this._childLine.material.color;
const max = Math.max(c.r, c.g, c.b);
if (max > 1) c.multiplyScalar(1 / max);
this._childMesh.material.color.copy(this._childLine.material.color);
// ignore world scale on light
this.matrixWorld.extractRotation(this.light.matrixWorld).scale(this.scale).copyPosition(this.light.matrixWorld);
this._childMesh.matrixWorld.copy(this.matrixWorld);
}
override copy(source: this, recursive?: boolean): this {
super.copy(source, false);
return this as this;
}
dispose() {
this._childLine.geometry.dispose();
this._childLine.material.dispose();
this._childMesh.geometry.dispose();
this._childMesh.material.dispose();
}
override clone(recursive?: boolean): this {
const cloned = new CoreRectAreaLightHelper(this.light, this.nodeName) as this;
cloned.updateMatrixWorld();
cloned.copy(this, false);
cloned.update();
return cloned;
}
}