-
-
Notifications
You must be signed in to change notification settings - Fork 267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Separate cast functions #552
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
9bb2f7b
Rearrange
gkjohnson ccf327c
Separate raycast function
gkjohnson 5770287
Migrate raycast first function
gkjohnson 4c2e5a9
Separate shapecast
gkjohnson dd27b02
Migrate intersects geometry
gkjohnson 0147140
clean up shepecast file
gkjohnson 454534d
Fix unnecessary args
gkjohnson File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import { Box3, Matrix4 } from 'three'; | ||
import { OrientedBox } from '../../math/OrientedBox.js'; | ||
import { ExtendedTriangle } from '../../math/ExtendedTriangle.js'; | ||
import { setTriangle } from '../../utils/TriangleUtilities.js'; | ||
import { arrayToBox } from '../../utils/ArrayBoxUtilities.js'; | ||
import { COUNT, OFFSET, IS_LEAF, BOUNDING_DATA_INDEX } from '../utils/nodeBufferUtils.js'; | ||
import { BufferStack } from '../utils/BufferStack.js'; | ||
|
||
const boundingBox = new Box3(); | ||
const triangle = new ExtendedTriangle(); | ||
const triangle2 = new ExtendedTriangle(); | ||
const invertedMat = new Matrix4(); | ||
|
||
const obb = new OrientedBox(); | ||
const obb2 = new OrientedBox(); | ||
|
||
export function intersectsGeometry( bvh, root, otherGeometry, geometryToBvh ) { | ||
|
||
BufferStack.setBuffer( bvh._roots[ root ] ); | ||
const result = _intersectsGeometry( 0, bvh.geometry, otherGeometry, geometryToBvh ); | ||
BufferStack.clearBuffer(); | ||
|
||
return result; | ||
|
||
} | ||
|
||
function _intersectsGeometry( nodeIndex32, geometry, otherGeometry, geometryToBvh, cachedObb = null ) { | ||
|
||
const { float32Array, uint16Array, uint32Array } = BufferStack; | ||
let nodeIndex16 = nodeIndex32 * 2; | ||
|
||
if ( cachedObb === null ) { | ||
|
||
if ( ! otherGeometry.boundingBox ) { | ||
|
||
otherGeometry.computeBoundingBox(); | ||
|
||
} | ||
|
||
obb.set( otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh ); | ||
cachedObb = obb; | ||
|
||
} | ||
|
||
const isLeaf = IS_LEAF( nodeIndex16, uint16Array ); | ||
if ( isLeaf ) { | ||
|
||
const thisGeometry = geometry; | ||
const thisIndex = thisGeometry.index; | ||
const thisPos = thisGeometry.attributes.position; | ||
|
||
const index = otherGeometry.index; | ||
const pos = otherGeometry.attributes.position; | ||
|
||
const offset = OFFSET( nodeIndex32, uint32Array ); | ||
const count = COUNT( nodeIndex16, uint16Array ); | ||
|
||
// get the inverse of the geometry matrix so we can transform our triangles into the | ||
// geometry space we're trying to test. We assume there are fewer triangles being checked | ||
// here. | ||
invertedMat.copy( geometryToBvh ).invert(); | ||
|
||
if ( otherGeometry.boundsTree ) { | ||
|
||
arrayToBox( BOUNDING_DATA_INDEX( nodeIndex32 ), float32Array, obb2 ); | ||
obb2.matrix.copy( invertedMat ); | ||
obb2.needsUpdate = true; | ||
|
||
const res = otherGeometry.boundsTree.shapecast( { | ||
|
||
intersectsBounds: box => obb2.intersectsBox( box ), | ||
|
||
intersectsTriangle: tri => { | ||
|
||
tri.a.applyMatrix4( geometryToBvh ); | ||
tri.b.applyMatrix4( geometryToBvh ); | ||
tri.c.applyMatrix4( geometryToBvh ); | ||
tri.needsUpdate = true; | ||
|
||
for ( let i = offset * 3, l = ( count + offset ) * 3; i < l; i += 3 ) { | ||
|
||
// this triangle needs to be transformed into the current BVH coordinate frame | ||
setTriangle( triangle2, i, thisIndex, thisPos ); | ||
triangle2.needsUpdate = true; | ||
if ( tri.intersectsTriangle( triangle2 ) ) { | ||
|
||
return true; | ||
|
||
} | ||
|
||
} | ||
|
||
return false; | ||
|
||
} | ||
|
||
} ); | ||
|
||
return res; | ||
|
||
} else { | ||
|
||
for ( let i = offset * 3, l = ( count + offset * 3 ); i < l; i += 3 ) { | ||
|
||
// this triangle needs to be transformed into the current BVH coordinate frame | ||
setTriangle( triangle, i, thisIndex, thisPos ); | ||
triangle.a.applyMatrix4( invertedMat ); | ||
triangle.b.applyMatrix4( invertedMat ); | ||
triangle.c.applyMatrix4( invertedMat ); | ||
triangle.needsUpdate = true; | ||
|
||
for ( let i2 = 0, l2 = index.count; i2 < l2; i2 += 3 ) { | ||
|
||
setTriangle( triangle2, i2, index, pos ); | ||
triangle2.needsUpdate = true; | ||
|
||
if ( triangle.intersectsTriangle( triangle2 ) ) { | ||
|
||
return true; | ||
|
||
} | ||
|
||
} | ||
|
||
} | ||
|
||
} | ||
|
||
} else { | ||
|
||
const left = nodeIndex32 + 8; | ||
const right = uint32Array[ nodeIndex32 + 6 ]; | ||
|
||
arrayToBox( BOUNDING_DATA_INDEX( left ), float32Array, boundingBox ); | ||
const leftIntersection = | ||
cachedObb.intersectsBox( boundingBox ) && | ||
_intersectsGeometry( left, geometry, otherGeometry, geometryToBvh, cachedObb ); | ||
|
||
if ( leftIntersection ) return true; | ||
|
||
arrayToBox( BOUNDING_DATA_INDEX( right ), float32Array, boundingBox ); | ||
const rightIntersection = | ||
cachedObb.intersectsBox( boundingBox ) && | ||
_intersectsGeometry( right, geometry, otherGeometry, geometryToBvh, cachedObb ); | ||
|
||
if ( rightIntersection ) return true; | ||
|
||
return false; | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { Vector3 } from 'three'; | ||
import { intersectTris } from '../../utils/GeometryRayIntersectUtilities.js'; | ||
import { intersectRay } from '../utils/intersectUtils.js'; | ||
import { COUNT, OFFSET, LEFT_NODE, RIGHT_NODE, IS_LEAF } from '../utils/nodeBufferUtils.js'; | ||
import { BufferStack } from '../utils/BufferStack.js'; | ||
|
||
const _boxIntersection = /* @__PURE__ */ new Vector3(); | ||
export function raycast( bvh, root, side, ray, intersects ) { | ||
|
||
BufferStack.setBuffer( bvh._roots[ root ] ); | ||
_raycast( 0, bvh.geometry, side, ray, intersects ); | ||
BufferStack.clearBuffer(); | ||
|
||
} | ||
|
||
function _raycast( nodeIndex32, geometry, side, ray, intersects ) { | ||
|
||
const { float32Array, uint16Array, uint32Array } = BufferStack; | ||
const nodeIndex16 = nodeIndex32 * 2; | ||
const isLeaf = IS_LEAF( nodeIndex16, uint16Array ); | ||
if ( isLeaf ) { | ||
|
||
const offset = OFFSET( nodeIndex32, uint32Array ); | ||
const count = COUNT( nodeIndex16, uint16Array ); | ||
|
||
intersectTris( geometry, side, ray, offset, count, intersects ); | ||
|
||
} else { | ||
|
||
const leftIndex = LEFT_NODE( nodeIndex32 ); | ||
if ( intersectRay( leftIndex, float32Array, ray, _boxIntersection ) ) { | ||
|
||
_raycast( leftIndex, geometry, side, ray, intersects ); | ||
|
||
} | ||
|
||
const rightIndex = RIGHT_NODE( nodeIndex32, uint32Array ); | ||
if ( intersectRay( rightIndex, float32Array, ray, _boxIntersection ) ) { | ||
|
||
_raycast( rightIndex, geometry, side, ray, intersects ); | ||
|
||
} | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { Vector3 } from 'three'; | ||
import { COUNT, OFFSET, LEFT_NODE, RIGHT_NODE, IS_LEAF, SPLIT_AXIS } from '../utils/nodeBufferUtils.js'; | ||
import { BufferStack } from '../utils/BufferStack.js'; | ||
import { intersectClosestTri } from '../../utils/GeometryRayIntersectUtilities.js'; | ||
import { intersectRay } from '../utils/intersectUtils.js'; | ||
|
||
const _boxIntersection = /* @__PURE__ */ new Vector3(); | ||
const _xyzFields = [ 'x', 'y', 'z' ]; | ||
export function raycastFirst( bvh, root, side, ray ) { | ||
|
||
BufferStack.setBuffer( bvh._roots[ root ] ); | ||
const result = _raycastFirst( 0, bvh.geometry, side, ray ); | ||
BufferStack.clearBuffer(); | ||
|
||
return result; | ||
|
||
} | ||
|
||
function _raycastFirst( nodeIndex32, geometry, side, ray ) { | ||
|
||
const { float32Array, uint16Array, uint32Array } = BufferStack; | ||
let nodeIndex16 = nodeIndex32 * 2; | ||
|
||
const isLeaf = IS_LEAF( nodeIndex16, uint16Array ); | ||
if ( isLeaf ) { | ||
|
||
const offset = OFFSET( nodeIndex32, uint32Array ); | ||
const count = COUNT( nodeIndex16, uint16Array ); | ||
return intersectClosestTri( geometry, side, ray, offset, count ); | ||
|
||
} else { | ||
|
||
// consider the position of the split plane with respect to the oncoming ray; whichever direction | ||
// the ray is coming from, look for an intersection among that side of the tree first | ||
const splitAxis = SPLIT_AXIS( nodeIndex32, uint32Array ); | ||
const xyzAxis = _xyzFields[ splitAxis ]; | ||
const rayDir = ray.direction[ xyzAxis ]; | ||
const leftToRight = rayDir >= 0; | ||
|
||
// c1 is the child to check first | ||
let c1, c2; | ||
if ( leftToRight ) { | ||
|
||
c1 = LEFT_NODE( nodeIndex32 ); | ||
c2 = RIGHT_NODE( nodeIndex32, uint32Array ); | ||
|
||
} else { | ||
|
||
c1 = RIGHT_NODE( nodeIndex32, uint32Array ); | ||
c2 = LEFT_NODE( nodeIndex32 ); | ||
|
||
} | ||
|
||
const c1Intersection = intersectRay( c1, float32Array, ray, _boxIntersection ); | ||
const c1Result = c1Intersection ? _raycastFirst( c1, geometry, side, ray ) : null; | ||
|
||
// if we got an intersection in the first node and it's closer than the second node's bounding | ||
// box, we don't need to consider the second node because it couldn't possibly be a better result | ||
if ( c1Result ) { | ||
|
||
// check if the point is within the second bounds | ||
// "point" is in the local frame of the bvh | ||
const point = c1Result.point[ xyzAxis ]; | ||
const isOutside = leftToRight ? | ||
point <= float32Array[ c2 + splitAxis ] : // min bounding data | ||
point >= float32Array[ c2 + splitAxis + 3 ]; // max bounding data | ||
|
||
if ( isOutside ) { | ||
|
||
return c1Result; | ||
|
||
} | ||
|
||
} | ||
|
||
// either there was no intersection in the first node, or there could still be a closer | ||
// intersection in the second, so check the second node and then take the better of the two | ||
const c2Intersection = intersectRay( c2, float32Array, ray, _boxIntersection ); | ||
const c2Result = c2Intersection ? _raycastFirst( c2, geometry, side, ray ) : null; | ||
|
||
if ( c1Result && c2Result ) { | ||
|
||
return c1Result.distance <= c2Result.distance ? c1Result : c2Result; | ||
|
||
} else { | ||
|
||
return c1Result || c2Result || null; | ||
|
||
} | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note