@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
103 lines (91 loc) • 3.33 kB
text/typescript
/**
* Creates or update uv attribute.
*
*
*/
import {Camera, Vector3, Object3D, Matrix4} from 'three';
import {TypedSopNode} from './_Base';
import {CoreGroup} from '../../../core/geometry/Group';
import {CameraController} from '../../../core/CameraController';
import {BaseCameraObjNodeType} from '../obj/_BaseCamera';
import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig';
import {InputCloneMode} from '../../poly/InputCloneMode';
import {CAMERA_TYPES, NodeContext} from '../../poly/NodeContext';
import {BaseObjNodeType} from '../obj/_Base';
import {CorePoint} from '../../../core/geometry/entities/point/CorePoint';
import {CoreObjectType} from '../../../core/geometry/ObjectContent';
const UV_NAME = 'uv';
const _position = new Vector3();
const _points: CorePoint<CoreObjectType>[] = [];
class UvProjectSopParamsConfig extends NodeParamsConfig {
/** @param camera node to use as projection */
camera = ParamConfig.NODE_PATH('', {
nodeSelection: {
context: NodeContext.OBJ,
types: CAMERA_TYPES,
},
});
// force_aspect = ParamConfig.BOOLEAN(0)
// aspect = ParamConfig.FLOAT(1, {
// range: [0, 2],
// visibleIf: {force_aspect: 1},
// })
}
const ParamsConfig = new UvProjectSopParamsConfig();
export class UvProjectSopNode extends TypedSopNode<UvProjectSopParamsConfig> {
override paramsConfig = ParamsConfig;
static override type() {
return 'uvProject';
}
private _cameraController: CameraController = new CameraController(this._updateUVsFromCamera.bind(this));
private _processed_core_group: CoreGroup | undefined;
private _camera_object: Camera | undefined;
override initializeNode() {
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE);
}
override cook(core_groups: CoreGroup[]) {
this._processed_core_group = core_groups[0];
const cameraNode = this.pv.camera.nodeWithContext(NodeContext.OBJ, this.states.error);
if (cameraNode != null && (CAMERA_TYPES as string[]).includes(cameraNode.type())) {
this._camera_object = (cameraNode as BaseCameraObjNodeType).object;
this._cameraController.setTarget(this._camera_object);
} else {
this._camera_object = undefined;
this._cameraController.removeTarget();
}
this.setCoreGroup(this._processed_core_group);
}
_updateUVsFromCamera(look_at_target: Object3D) {
// let old_aspect;
// if (this.pv.force_aspect) {
// old_aspect = this._camera_object.aspect;
// this._camera_node.setup_for_aspect_ratio(this.pv.aspect);
// }
const parent = this.parent();
if (this._processed_core_group && parent) {
this._processed_core_group.points(_points);
const obj_world_matrix = (parent as BaseObjNodeType).object.matrixWorld;
for (const point of _points) {
point.position(_position);
const uvw = this._vectorInCameraSpace(_position, obj_world_matrix);
if (uvw) {
const uv = {
x: 1 - (uvw[0] * 0.5 + 0.5),
y: uvw[1] * 0.5 + 0.5,
};
point.setAttribValue(UV_NAME, uv);
}
}
// if (this.pv.force_aspect) {
// this._camera_node.setup_for_aspect_ratio(old_aspect);
// }
}
}
private _vectorInCameraSpace(vector: Vector3, obj_world_matrix: Matrix4) {
if (this._camera_object) {
vector.applyMatrix4(obj_world_matrix);
return vector.project(this._camera_object).toArray();
}
}
}