1818// https://github.com/mrdoob/three.js/blob/dev/build/three.core.js
1919// ( Since the source is split up, I'm just linking to the main file )
2020//
21+ // Couldn't get the above working 100%, so made `castRay()` for Vector Ray to Triangle collision
22+ // It works with floor and interactable colliders, but slightly heavier than the other method
23+ // Looked to this PDF for Moller-Trumbore Ray-Intersect, pages 4 & 5
24+ // https://cadxfem.org/inf/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf
25+ //
2126// I implemented a per-pxlRoom hash grid for ground collision detection,
2227// As ray casting to all polygons in a scene is inefficient
2328// While also using the logic outlined in the book as used in Three.js, I've adapted it to my needs --
@@ -37,7 +42,7 @@ import {
3742 AdditiveBlending
3843} from "../../libs/three/three.module.min.js" ;
3944
40- import { VERBOSE_LEVEL , COLLIDER_TYPE } from "./Enums.js" ;
45+ import { VERBOSE_LEVEL , COLLIDER_TYPE , GEOMETRY_SIDE } from "./Enums.js" ;
4146
4247// Some assumptions are made here, as collision meshes are ussually low poly
4348// A grid size of 100 is assumed for -+500 unit bounds
@@ -518,9 +523,20 @@ export class Colliders{
518523 // -- -- --
519524
520525 // Moller-Trumbore triangle ray intersection
521- // The other ray casting methods have issues to be worked out
526+ // The other ray casting method has issues to be worked out
522527 // This is the general purpose rayCaster for now
523- castRay ( roomName , origin , direction , colliderType = COLLIDER_TYPE . FLOOR , multiHits = true ) {
528+ // Implemented to be side-non-specific, as the ray may be cast from any direction
529+ // Ray intersection for front facing or back facing triangles
530+ // ** This is assuming Three.js is using right-handed winding order **
531+ //
532+ // Using - Scalar Triple Product; Cramer's Rule - Determinant of a 3x3 matrix
533+ // u = (origin - v0) . (direction x edge1) / (edge0 . (direction x edge1))
534+ // v = (origin - v0) . (edge0 x direction) / (edge0 . (direction x edge1))
535+ // t = (v1 - origin) . (edge1 x direction) / (edge0 . (direction x edge1))
536+ // Pages 4 & 5 -
537+ // https://cadxfem.org/inf/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf
538+ //
539+ castRay ( roomName , origin , direction , colliderType = COLLIDER_TYPE . FLOOR , geoSide = GEOMETRY_SIDE . DOUBLE , multiHits = true ) {
524540
525541 if ( ! this . roomColliderData . hasOwnProperty ( roomName ) || ! this . roomColliderData [ roomName ] . hasOwnProperty ( colliderType ) ) {
526542 this . error ( "Room '" + roomName + "' does not have collider data for type: " + colliderType ) ;
@@ -534,16 +550,24 @@ export class Colliders{
534550 let gridX = Math . floor ( origin . x * gridSizeInv ) ;
535551 let gridZ = Math . floor ( origin . z * gridSizeInv ) ;
536552 let gridKey = this . getGridKey ( gridX , gridZ ) ;
537- //console.log( origin, direction, gridKey );
538553
539-
554+ // Default checks for front and back facing triangles
555+ let backFaceCheck = 1 ;
556+ let frontFaceCheck = 1 ;
557+ if ( geoSide == GEOMETRY_SIDE . FRONT ) {
558+ backFaceCheck = 0 ;
559+ } else if ( geoSide == GEOMETRY_SIDE . BACK ) {
560+ frontFaceCheck = 0 ;
561+ }
562+
540563 if ( ! roomData [ 'faceGridGroup' ] . hasOwnProperty ( gridKey ) ) return [ ] ;
541564 let faceKeys = roomData [ 'faceGridGroup' ] [ gridKey ] ;
542565 //let faceKeys = Object.keys( roomData['faceVerts'] );
543566
544567 let hits = [ ] ;
545568 let retHits = { } ;
546569
570+
547571 faceKeys . forEach ( faceKey => {
548572 let faceVerts = roomData [ 'faceVerts' ] [ faceKey ] ;
549573 let v0 = faceVerts [ 'verts' ] [ 0 ] ;
@@ -553,22 +577,29 @@ export class Colliders{
553577 let edge0 = faceVerts [ 'edge0' ] ; // v1.clone().sub(v0);
554578 let edge1 = faceVerts [ 'edge1' ] ; // v2.clone().sub(v0);
555579 let directionCross = direction . clone ( ) . cross ( edge1 ) ;
556- let isFacing = edge0 . dot ( directionCross ) ;
580+ let isFacing = edge0 . dot ( directionCross ) ; // Determinant of the matrix
557581
558- if ( isFacing > - this . epsilon && isFacing < this . epsilon ) return ; // This ray is parallel to this triangle.
582+ // Triangle is parallel to the ray
583+ // This allows negative facing triangles to be detected
584+ if ( isFacing * backFaceCheck > - this . epsilon && isFacing * frontFaceCheck < this . epsilon ) return ; // This ray is parallel to this triangle.
559585
560- let factor = 1.0 / isFacing ;
586+ // Calculate barycentric coordinates
587+
561588 let edgeOrig = origin . clone ( ) . sub ( v0 ) ;
562- let u = factor * edgeOrig . dot ( directionCross ) ;
589+ let u = edgeOrig . dot ( directionCross ) ;
563590
564- if ( u < 0.0 || u > 1.0 ) return ;
591+ if ( u < 0.0 || u > isFacing ) return ; // Invalid barcentric coordinate, outside of triangle
565592
566593 let crossOrig = edgeOrig . clone ( ) . cross ( edge0 ) ;
567- let v = factor * direction . dot ( crossOrig ) ;
594+ let v = direction . dot ( crossOrig ) ;
595+
596+ if ( v < 0.0 || u + v > isFacing ) return ; // Invalid barcentric coordinate, outside of triangle
568597
569- if ( v < 0.0 || u + v > 1.0 ) return ;
598+ let factor = 1.0 / isFacing ; // Inverted Determinant to reduce divisions, Scale factor for ray intersection
599+ u *= factor ;
600+ v *= factor ;
570601
571- let dist = factor * edge1 . dot ( crossOrig ) ;
602+ let dist = factor * edge1 . dot ( crossOrig ) ; // 'dist' is 't' in the Moller-Trumbore algorithm
572603
573604 if ( dist > this . epsilon ) { // ray intersection
574605 let intersectionPoint = origin . clone ( ) . add ( direction . clone ( ) . multiplyScalar ( dist ) ) ;
0 commit comments