/* * @Author: Xu.Wang * @Date: 2020-04-15 22:13:18 * @Last Modified by: Xu.Wang * @Last Modified time: 2020-04-16 00:22:02 */ import { Surface, SurfaceRayIntersection3 } from './surface' import { Vector3, clampV3 } from '../math' import { Transform } from './transform' import { Ray } from '.' import { BoundingBox } from './bounding_box' import { PhysicsPlane } from './physics_plane' export class PhysicsBox extends Surface { private _bound: BoundingBox constructor( lower: Vector3 = new Vector3(), upper: Vector3 = new Vector3(1.0, 1.0, 1.0), transform: Transform = new Transform(), isNormalFlipped: boolean = false ) { super(transform, isNormalFlipped) this._bound = new BoundingBox(lower, upper) } setWithBbox(bbox: BoundingBox) { this._bound = bbox } bound(): BoundingBox { return this._bound } closestPointLocal(otherPoint: Vector3): Vector3 { if (this._bound.contains(otherPoint)) { let planes = new Array( new PhysicsPlane(new Vector3(1, 0, 0), this._bound.upper()), new PhysicsPlane(new Vector3(0, 1, 0), this._bound.upper()), new PhysicsPlane(new Vector3(0, 0, 1), this._bound.upper()), new PhysicsPlane(new Vector3(-1, 0, 0), this._bound.lower()), new PhysicsPlane(new Vector3(0, -1, 0), this._bound.lower()), new PhysicsPlane(new Vector3(0, 0, -1), this._bound.lower()) ) let result = planes[0].closestPoint(otherPoint) let distanceSquared = result.distanceSquaredTo(otherPoint) for (let i = 1; i < 6; ++i) { let localResult = planes[i].closestPoint(otherPoint) let localDistanceSquared = localResult.distanceSquaredTo(otherPoint) if (localDistanceSquared < distanceSquared) { result = localResult distanceSquared = localDistanceSquared } } return result } else { return clampV3(otherPoint, this._bound.lower(), this._bound.upper()) } } closestNormalLocal(otherPoint: Vector3): Vector3 { let planes = new Array( new PhysicsPlane(new Vector3(1, 0, 0), this._bound.upper()), new PhysicsPlane(new Vector3(0, 1, 0), this._bound.upper()), new PhysicsPlane(new Vector3(0, 0, 1), this._bound.upper()), new PhysicsPlane(new Vector3(-1, 0, 0), this._bound.lower()), new PhysicsPlane(new Vector3(0, -1, 0), this._bound.lower()), new PhysicsPlane(new Vector3(0, 0, -1), this._bound.lower()) ) if (this._bound.contains(otherPoint)) { let closestNormal = planes[0].normal() let closestPoint = planes[0].closestPoint(otherPoint) let minDistanceSquared = closestPoint.sub(otherPoint).lengthSquared() for (let i = 1; i < 6; ++i) { let localClosestPoint = planes[i].closestPoint(otherPoint) let localDistanceSquared = localClosestPoint .sub(otherPoint) .lengthSquared() if (localDistanceSquared < minDistanceSquared) { closestNormal = planes[i].normal() minDistanceSquared = localDistanceSquared } } return closestNormal } else { let closestPoint = clampV3( otherPoint, this._bound.lower(), this._bound.upper() ) let closestPointToInputPoint = otherPoint.sub(closestPoint) let closestNormal = planes[0].normal() let maxCosineAngle = closestNormal.dot(closestPointToInputPoint) for (let i = 1; i < 6; ++i) { let cosineAngle = planes[i].normal().dot(closestPointToInputPoint) if (cosineAngle > maxCosineAngle) { closestNormal = planes[i].normal() maxCosineAngle = cosineAngle } } return closestNormal } } intersectsLocal(ray: Ray): boolean { return this._bound.intersects(ray) } closestIntersectionLocal(ray: Ray): SurfaceRayIntersection3 { let intersection = new SurfaceRayIntersection3() let bbRayIntersection = this._bound.closestIntersection(ray) intersection.isIntersecting = bbRayIntersection.isIntersecting if (intersection.isIntersecting) { intersection.distance = bbRayIntersection.Near intersection.point = ray.pointAt(bbRayIntersection.Near) intersection.normal = this.closestNormal(intersection.point) } return intersection } boundingBoxLocal(): BoundingBox { return this._bound } }