@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
185 lines (184 loc) • 6.51 kB
JavaScript
"use strict";
import { TargetType, TARGET_TYPES } from "../../Raycast";
import { NodeContext } from "../../../../poly/NodeContext";
import { TypeAssert } from "../../../../poly/Assert";
import { Plane } from "three";
import { Vector3 } from "three";
import { ParamType } from "../../../../poly/ParamType";
import { AttribType, ATTRIBUTE_TYPES } from "../../../../../core/geometry/Constant";
import { RaycastCPUVelocityController } from "./VelocityController";
import { isString } from "../../../../../core/Type";
import { CPUIntersectWith, CPU_INTERSECT_WITH_OPTIONS } from "./CpuConstants";
import { isBooleanTrue } from "../../../../../core/BooleanValue";
import { IntersectDataEventNode } from "../../IntersectData";
import { BaseRaycastController } from "./BaseRaycastController";
import { resolveIntersectGeometryAttribute } from "../../../../../core/geometry/intersect/CoreIntersect";
export class RaycastCPUController extends BaseRaycastController {
constructor(_node) {
super();
this._node = _node;
this._cursorArray = [0, 0];
this._plane = new Plane();
this._plane_intersect_target = new Vector3();
this._intersections = [];
this._hitPositionArray = [0, 0, 0];
this.velocityController = new RaycastCPUVelocityController(this._node);
}
updateMouse(eventContext) {
const viewer = eventContext.viewer;
if (!viewer) {
return;
}
const camera = viewer.camera();
if (!camera) {
return;
}
this._cursorHelper.setCursorForCPU(eventContext, this._cursor);
if (isBooleanTrue(this._node.pv.tmouse)) {
this._cursor.toArray(this._cursorArray);
this._node.p.mouse.set(this._cursorArray);
}
viewer.raycastersController.raycaster0().setFromCamera(this._cursor, camera);
}
processEvent(context) {
this._prepareRaycaster(context);
const type = CPU_INTERSECT_WITH_OPTIONS[this._node.pv.intersectWith];
switch (type) {
case CPUIntersectWith.GEOMETRY: {
return this._intersectGeometry(context);
}
case CPUIntersectWith.PLANE: {
return this._intersectPlane(context);
}
}
TypeAssert.unreachable(type);
}
_intersectPlane(eventContext) {
const viewer = eventContext.viewer;
if (!viewer) {
return;
}
this._plane.normal.copy(this._node.pv.planeDirection);
this._plane.constant = this._node.pv.planeOffset;
viewer.raycastersController.raycaster0().ray.intersectPlane(this._plane, this._plane_intersect_target);
this._setPositionParam(this._plane_intersect_target);
this._node.triggerHit(eventContext);
}
_intersectGeometry(eventContext) {
const viewer = eventContext.viewer;
if (!viewer) {
return;
}
if (!this._resolvedTargets) {
this.updateTarget();
}
if (this._resolvedTargets) {
this._intersections.length = 0;
const intersections = viewer.raycastersController.raycaster0().intersectObjects(
this._resolvedTargets,
isBooleanTrue(this._node.pv.traverseChildren),
this._intersections
);
const intersection = intersections[0];
if (intersection) {
this._node.scene().batchUpdates(() => {
if (isBooleanTrue(this._node.pv.tposition)) {
this._setPositionParam(intersection.point);
}
if (isBooleanTrue(this._node.pv.geoAttribute)) {
this._resolveIntersectAttribute(intersection);
}
});
eventContext.value = { intersect: intersection };
this._node.triggerHit(eventContext);
} else {
this._node.triggerMiss(eventContext);
}
}
}
_resolveIntersectAttribute(intersection) {
const attribType = ATTRIBUTE_TYPES[this._node.pv.geoAttributeType];
let attribValue = IntersectDataEventNode.resolveObjectAttribute(
intersection,
this._node.pv.geoAttributeName
);
if (attribValue == null) {
attribValue = resolveIntersectGeometryAttribute(intersection, this._node.pv.geoAttributeName, attribType);
}
if (attribValue != null) {
switch (attribType) {
case AttribType.NUMERIC: {
this._node.p.geoAttributeValue1.set(attribValue);
return;
}
case AttribType.STRING: {
if (isString(attribValue)) {
this._node.p.geoAttributeValues.set(attribValue);
}
return;
}
}
TypeAssert.unreachable(attribType);
}
}
_setPositionParam(hitPosition) {
var _a;
hitPosition.toArray(this._hitPositionArray);
if (isBooleanTrue(this._node.pv.tpositionTarget)) {
const targetParam = this._node.pv.positionTarget;
if (this._foundPositionTargetParam == null || isBooleanTrue(this._foundPositionTargetParam.disposed())) {
this._foundPositionTargetParam = targetParam.paramWithType(ParamType.VECTOR3);
}
(_a = this._foundPositionTargetParam) == null ? void 0 : _a.set(this._hitPositionArray);
} else {
this._node.p.position.set(this._hitPositionArray);
}
this.velocityController.process(hitPosition);
}
_prepareRaycaster(eventContext) {
const viewer = eventContext.viewer;
if (!viewer) {
return;
}
const pointsParam = viewer.raycastersController.raycaster0().params.Points;
if (pointsParam) {
pointsParam.threshold = this._node.pv.pointsThreshold;
}
}
updateTarget() {
const targetType = TARGET_TYPES[this._node.pv.targetType];
switch (targetType) {
case TargetType.NODE: {
return this._updateTargetFromNode();
}
case TargetType.SCENE_GRAPH: {
return this._updateTargetFromSceneGraph();
}
}
TypeAssert.unreachable(targetType);
}
_updateTargetFromNode() {
const node = this._node.p.targetNode.value.nodeWithContext(NodeContext.OBJ);
if (node) {
const found_obj = isBooleanTrue(this._node.pv.traverseChildren) ? node.object : node.childrenDisplayController.sopGroup();
if (found_obj) {
this._resolvedTargets = [found_obj];
} else {
this._resolvedTargets = void 0;
}
} else {
this._node.states.error.set("node is not an object");
}
}
_updateTargetFromSceneGraph() {
const objects = this._node.scene().objectsByMask(this._node.pv.objectMask);
if (objects.length > 0) {
this._resolvedTargets = objects;
} else {
this._resolvedTargets = void 0;
}
}
static PARAM_CALLBACK_updateTarget(node) {
node.cpuController.updateTarget();
}
}