UNPKG

@polygonjs/polygonjs

Version:

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

171 lines (170 loc) 7 kB
"use strict"; import { BaseSopOperation } from "./_Base"; import { InputCloneMode } from "../../../engine/poly/InputCloneMode"; import { Matrix4, Triangle, Vector2, Vector3 } from "three"; import { isBooleanTrue } from "../../../core/BooleanValue"; import { MatDoubleSideTmpSetter } from "../../../core/render/MatDoubleSideTmpSetter"; import { TypeAssert } from "../../poly/Assert"; import { ThreeMeshBVHHelper } from "../../../core/geometry/bvh/ThreeMeshBVHHelper"; import { createRaycaster } from "../../../core/RaycastHelper"; import { corePointClassFactory } from "../../../core/geometry/CoreObjectFactory"; export var RaySopMode = /* @__PURE__ */ ((RaySopMode2) => { RaySopMode2["PROJECT_RAY"] = "project rays"; RaySopMode2["MIN_DIST"] = "minimum distance"; return RaySopMode2; })(RaySopMode || {}); export const RAY_SOP_MODES = ["project rays" /* PROJECT_RAY */, "minimum distance" /* MIN_DIST */]; const DIST_ATTRIB_NAME = "dist"; const objectWorldMat = new Matrix4(); const objectWorldMatInverse = new Matrix4(); const _points = []; const _uv0 = new Vector2(); const _uv1 = new Vector2(); const _uv2 = new Vector2(); const _uv = new Vector2(); export class RaySopOperation extends BaseSopOperation { constructor() { super(...arguments); this._matDoubleSideTmpSetter = new MatDoubleSideTmpSetter(); this._raycaster = createRaycaster(); this._pointPos = new Vector3(); this._pointNormal = new Vector3(); this._hitPointInfo = { point: new Vector3(), distance: -1, faceIndex: -1 }; this._triangle = new Triangle(); this._faceNormal = new Vector3(); } static type() { return "ray"; } cook(inputCoreGroups, params) { const coreGroupToRay = inputCoreGroups[0]; const coreGroupToRayOnto = inputCoreGroups[1]; const coreGroup = this._ray(coreGroupToRay, coreGroupToRayOnto, params); return coreGroup; } _ray(coreGroup, coreGroupCollision, params) { const mode = RAY_SOP_MODES[params.mode]; switch (mode) { case "project rays" /* PROJECT_RAY */: { return this._computeWithProjectRay(coreGroup, coreGroupCollision, params); } case "minimum distance" /* MIN_DIST */: { return this._computeWithMinDist(coreGroup, coreGroupCollision, params); } } TypeAssert.unreachable(mode); } _computeWithProjectRay(coreGroup, coreGroupCollision, params) { this._matDoubleSideTmpSetter.setCoreGroupMaterialDoubleSided(coreGroupCollision); this._addDistAttribute(coreGroup, params); let direction, firstIntersect; coreGroup.points(_points); for (const point of _points) { point.position(this._pointPos); direction = params.direction; if (isBooleanTrue(params.useNormals)) { point.normal(this._pointNormal); direction = this._pointNormal; } this._raycaster.set(this._pointPos, direction); firstIntersect = this._raycaster.intersectObjects(coreGroupCollision.threejsObjects(), true)[0]; if (firstIntersect) { if (isBooleanTrue(params.transformPoints)) { point.setPosition(firstIntersect.point); } if (isBooleanTrue(params.addDistAttribute)) { const dist = this._pointPos.distanceTo(firstIntersect.point); point.setAttribValue(DIST_ATTRIB_NAME, dist); } if (isBooleanTrue(params.transferFaceNormals) && firstIntersect.face) { point.setNormal(firstIntersect.face.normal); } } } this._matDoubleSideTmpSetter.restoreMaterialSideProperty(coreGroupCollision); return coreGroup; } _computeWithMinDist(coreGroup, coreGroupCollision, params) { var _a, _b; this._addDistAttribute(coreGroup, params); const coreGroupCollisionObject = coreGroupCollision.threejsObjectsWithGeo()[0]; const collisionGeometry = coreGroupCollisionObject.geometry; const indexArray = (_a = collisionGeometry.getIndex()) == null ? void 0 : _a.array; if (!indexArray) { (_b = this.states) == null ? void 0 : _b.error.set("the collision geo requires an index"); return coreGroup; } let bvh = collisionGeometry.boundsTree; if (!bvh) { ThreeMeshBVHHelper.assignDefaultBVHIfNone(coreGroupCollisionObject); bvh = collisionGeometry.boundsTree; } coreGroupCollisionObject.updateMatrixWorld(true); objectWorldMat.copy(coreGroupCollisionObject.matrixWorld); objectWorldMatInverse.copy(objectWorldMat).invert(); const position = collisionGeometry.getAttribute("position"); const uv = collisionGeometry.getAttribute("uv"); coreGroup.points(_points); const pointsCount = _points.length; for (let i = 0; i < pointsCount; i++) { const point = _points[i]; point.position(this._pointPos); this._pointPos.applyMatrix4(objectWorldMatInverse); bvh.closestPointToPoint(this._pointPos, this._hitPointInfo); if (isBooleanTrue(params.transformPoints)) { this._hitPointInfo.point.applyMatrix4(objectWorldMat); point.setPosition(this._hitPointInfo.point); } if (isBooleanTrue(params.addDistAttribute)) { point.setAttribValue(DIST_ATTRIB_NAME, this._hitPointInfo.distance); } if (isBooleanTrue(params.transferFaceNormals) || isBooleanTrue(params.transferUVs)) { this._triangle.setFromAttributeAndIndices( position, indexArray[3 * this._hitPointInfo.faceIndex], indexArray[3 * this._hitPointInfo.faceIndex + 1], indexArray[3 * this._hitPointInfo.faceIndex + 2] ); if (isBooleanTrue(params.transferFaceNormals)) { this._triangle.getNormal(this._faceNormal); point.setNormal(this._faceNormal); } if (isBooleanTrue(params.transferUVs) && uv) { _uv0.fromBufferAttribute(uv, indexArray[3 * this._hitPointInfo.faceIndex]); _uv1.fromBufferAttribute(uv, indexArray[3 * this._hitPointInfo.faceIndex + 1]); _uv2.fromBufferAttribute(uv, indexArray[3 * this._hitPointInfo.faceIndex + 2]); this._triangle.getInterpolation(this._hitPointInfo.point, _uv0, _uv1, _uv2, _uv); point.setAttribValue("uv", _uv); } } } return coreGroup; } _addDistAttribute(coreGroup, params) { if (isBooleanTrue(params.addDistAttribute) == false) { return; } if (coreGroup.hasPointAttrib(DIST_ATTRIB_NAME) == true) { return; } const allObjects = coreGroup.allObjects(); for (const object of allObjects) { const corePointClass = corePointClassFactory(object); corePointClass.addNumericAttribute(object, DIST_ATTRIB_NAME, 1, -1); } } } RaySopOperation.DEFAULT_PARAMS = { mode: RAY_SOP_MODES.indexOf("project rays" /* PROJECT_RAY */), useNormals: true, direction: new Vector3(0, -1, 0), transformPoints: true, transferFaceNormals: true, transferUVs: false, addDistAttribute: false }; RaySopOperation.INPUT_CLONED_STATE = [InputCloneMode.FROM_NODE, InputCloneMode.NEVER];