0
votes

I'm quite new if it comes to 3d programming and THREE.js and needs some help with proper collision detection.

I'm using the following method to detect collision between sourceElements and targetElements

detect(): void {
    if (!this.sourceElements.length || !this.targetElements.length) {
       return;
    }

    for (let i = 0; i < this.sourceElements.length; i+= 1) {
        const originPoint = this.sourceElements[i].position.clone();

        for (let vertexIndex = 0; vertexIndex < (<Geometry>this.sourceElements[i].geometry).vertices.length; vertexIndex++) {
            let localVertex = (<Geometry>this.sourceElements[i].geometry).vertices[vertexIndex].clone();
            let globalVertex = localVertex.applyMatrix4(this.sourceElements[i].matrix);
            let directionVector = globalVertex.sub(this.sourceElements[i].position);
            let ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize());
            let collisionResults = ray.intersectObjects(this.targetElements, false); // @TODO create method
            if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) {
                console.log('<<<<HIT>>>>>', collisionResults[0].object.name);

                // if hit was detected there's no need to analyze more
                return;
            }
        }
    }
  }

This code works well if source elements have Geometry. The problem is that recently I started to import larger Gltf models that have BufferGeometry for performance reasons. BufferGeometry has no vertices but instead of this has attributes.position.array with coordicates.

So I tried to generate vertices based on this data

let v: Vector3 = new THREE.Vector3();
// iterate over source elements        
for (let i = 0; i < sourceElements.length; i += 1) {
    let geometry = sourceElements[i].geometry;
    // if there's any with BufferGeometry generate vertices based on 
    if ( geometry instanceof THREE.BufferGeometry ) {
        const vertices: Array<Vector3> = [];
        const positions = geometry.attributes.position.array;
                
        console.log('CollisionDetector BufferGeometry detected', geometry);

        for ( let k = 0; k < positions.length; k += 3 ) {
            v.set(positions[ k ],positions[ k + 1 ], positions[ k + 2 ]);
            vertices.push(v);
        }
    }
}

The above code don't fail and generates an array of Vector3 objects that I then use for raycasting but unfortunately, collision is never detected.

What should I change in my code to have a universal method for collision detection no matter which kind of Geometry has objects?

Thanks in advance

1
With loaded models, try to use .intersectObjects() like this .intersectObjects(this.targetElements, true).prisoner849
Thanks for fast response. I've tried also with true but also there's no collision detectedTheCrow

1 Answers

0
votes

In your code, when populating your vertices array, you are pushing references to v into the array. This means when you update v elsewhere, all of those references are updated as well. You essentially aren't comparing against any other vertices but the last one for the shape(s).

Ensuring you have unique Vector3s is easy enough with Vector3.clone().

let v: Vector3 = new THREE.Vector3();
// iterate over source elements        
for (let i = 0; i < sourceElements.length; i += 1) {
    let geometry = sourceElements[i].geometry;
    // if there's any with BufferGeometry generate vertices based on 
    if ( geometry instanceof THREE.BufferGeometry ) {
        const vertices: Array<Vector3> = [];
        const positions = geometry.attributes.position.array;
                
        console.log('CollisionDetector BufferGeometry detected', geometry);

        for ( let k = 0; k < positions.length; k += 3 ) {
            v.set(positions[ k ],positions[ k + 1 ], positions[ k + 2 ]);
            vertices.push(v.clone()); // <---- Creates a copy!
        }
    }
}

Note that on the line where the vertex is pushed in, I call v.clone(). This creates a copy of v with the values you've set.