Enhance collision detection with precise ray casting in Three.js

I am currently utilizing Three.js, specifically version 68. Employing a collision detection method similar to the one demonstrated in this resource has proven to be quite effective (A huge "thank you" to the original author!):

If interested in accessing the source code for download via Github, search for Collision-Detection.html: https://github.com/stemkoski/stemkoski.github.com

Below is the essential code snippet pertaining to collision detection:

var MovingCube;
var collidableMeshList = [];

var wall = new THREE.Mesh(wallGeometry, wallMaterial);
wall.position.set(100, 50, -100);
scene.add(wall);
collidableMeshList.push(wall);
var wall = new THREE.Mesh(wallGeometry, wireMaterial);
wall.position.set(100, 50, -100);
scene.add(wall);

var wall2 = new THREE.Mesh(wallGeometry, wallMaterial);
wall2.position.set(-150, 50, 0);
wall2.rotation.y = 3.14159 / 2;
scene.add(wall2);
collidableMeshList.push(wall2);
var wall2 = new THREE.Mesh(wallGeometry, wireMaterial);
wall2.position.set(-150, 50, 0);
wall2.rotation.y = 3.14159 / 2;
scene.add(wall2);

var cubeGeometry = new THREE.CubeGeometry(50,50,50,1,1,1);
var wireMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe:true } );
MovingCube = new THREE.Mesh( cubeGeometry, wireMaterial );
MovingCube.position.set(0, 25.1, 0);


// collision detection:
//   determines if any of the rays from the cube's origin to each vertex
//      intersects any face of a mesh in the array of target meshes
//   for increased collision accuracy, add more vertices to the cube;
//      for example, new THREE.CubeGeometry( 64, 64, 64, 8, 8, 8, wireMaterial )
//   HOWEVER: when the origin of the ray is within the target mesh, collisions do not occur
var originPoint = MovingCube.position.clone();

for (var vertexIndex = 0; vertexIndex < MovingCube.geometry.vertices.length; vertexIndex++)
{       
    var localVertex = MovingCube.geometry.vertices[vertexIndex].clone();
    var globalVertex = localVertex.applyMatrix4( MovingCube.matrix );
    var directionVector = globalVertex.sub( MovingCube.position );

    var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
    var collisionResults = ray.intersectObjects( collidableMeshList );
    if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() ) 
        appendText(" Hit ");
}

While generally effective, there are instances where the cube can partially penetrate the wall without triggering a collision. Reference the image provided as an example:

The expectation is for it to display "Hit" in the top-left corner amidst the dots but fails to do so. NOTE: Despite attempting the suggested alteration mentioned below, minimal improvement was observed:

THREE.BoxGeometry( 64, 64, 64, 8, 8, 8, wireMaterial ) // BoxGeometry is used in version 68 instead of CubeGeometry

Do any individuals have insights on enhancing the precision of this method? Additionally: Could someone elaborate on the purpose behind the following if statement, namely why the object's distance should be less than the length of the direction vector?:

if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() )

Answer №1

Regarding your previous inquiry, let's start with the detection of collisions inside the MovingCube. The raycasting code in question casts a ray from the position of the MovingCube towards each of its vertices. If the ray intersects with any object, it returns that object along with the distance from the MovingCube's position to where the collision occurred (collisionResults[0].distance). By comparing this distance with the distance to the relevant vertex of the cube, we can determine if the collision happened within the cube itself.

Raycasting as a method of collision detection has limitations, as it only detects collisions along the specific directions the rays are cast. There are also edge cases to consider, such as situations where casting a ray from inside another object may not detect a collision. Additionally, in Three.js, raycasting uses bounding spheres or boxes for intersection calculations, which can lead to false positives when determining collisions visually.

For simpler shapes like spheres or cuboids, collision detection can be done using basic math. This is why Three.js utilizes bounding spheres and boxes, as well as many applications employing simplified collision geometries separate from visual representations. Spheres are considered colliding if the distance between their centers is less than the sum of their radii, while boxes collide if their edges overlap in both vertical and horizontal dimensions.

In certain scenarios, voxels can be used by dividing the world into cubic units and checking for overlaps to determine collisions between objects sharing the same voxel unit.

For more complex applications, utilizing libraries like Ammo.js, Cannon.js, or Physi.js is recommended for accurate collision detection and physics simulations.

The appeal of raycasting lies in its ability to work with intricate geometries without relying on external libraries. However, as you have discovered, it is not without its drawbacks. :-)

If interested, I have authored a book called "Game Development with Three.js" that delves deeper into this topic. While I won't provide a direct link here for promotion purposes, feel free to search for it online. The book includes sample code demonstrating basic collision detection and even features complete code for creating a 3D capture-the-flag game.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to incorporate arrowheads into the lines that have been sketched using canvas

I need assistance with incorporating arrowheads at the end of linear plots drawn on a coordinate grid using my custom function. You can view an example of the current setup in this JsFiddle: https://jsfiddle.net/zje14n92/1/ Below is the code snippet respo ...

update url to redirect hashbang with history.js

Upon further investigation, I have observed that history.js has the ability to automatically transform http://www.site.com/some/path#/other/path into http://www.site.com/other/path when used with a html5 enabled browser. While this feature is useful, ...

Eliminate the console.log messages from Workbox in Next.js

Does anyone know how to stop the constant stream of console.log messages from workbox in a NextJS project? I recently initiated a new repository and it's flooding me with unnecessary informationhttps://i.sstatic.net/Aikrx.jpg ...

Is there a way to nest a child within a parent in Vue.js without using a separate component?

As I navigate through Vue, I encounter a unique challenge that I can't seem to resolve. Below is the HTML code snippet and JSFiddle links: <div class="box align" id="app" onmouseover="fuchsia(id)" onmouseout=' ...

React Side Panels that Collapse and Expand

Apologies if this task seems simple, as I am new to transitioning to React. My current application is primarily built with JavaScript, CSS, and HTML, and I am now looking to migrate it to React. There is a full-length horizontal side panel that is initiall ...

VeeValidation always provides an accurate validation result

I recently integrated vee-validate into my project and encountered an issue with the validation behavior. Below is the code snippet from my component with a simple form group: <ValidationObserver ref="observer" v-slot="{ invalid }"> < ...

There appears to be no data available from the Apollo Query

I'm facing an issue with the returned data from Apollo Query, which is showing as undefined. In my code snippet in Next.js, I have a component called Image with the src value set to launch.ships[0].image. However, when running the code, I encounter a ...

What is causing my background image to move upward when I include this JavaScript code for FlashGallery?

There's an issue on my website where adding a flash gallery script is causing the background image to shift unexpectedly. You can view the affected page here: The culprit seems to be the "swfobject.js" script. I've identified this by toggling t ...

Guide on retrieving HTML content from a URL and showing it in a div

I'm trying to retrieve the content of a URL and display it within a DIV element, but I'm struggling to achieve the desired result. Below is the code I'm using: index.js fetch('https://github.com/') .then(res => res.text()) ...

Even though the request is in the json format, Rails mistakenly interprets it as html

I've been working on setting up an API using Rails. However, when attempting to send an ajax request with json in the browser like so: $.ajax({ type: "GET", url: 'http://localhost:3000', dataType: "json", contentType: "application/j ...

Can WebSocket messages be encoded?

Is there a way to encrypt or obscure the data I transmit via websockets? For example, the message looks like this: var encryptedMsg = { type: "message", data: { message: "Hello world!" } } I require the ability to send this message in ...

What is the syntax for creating a conditional statement using the ternary operator in JavaScript ES6?

I need to implement a ternary condition in the mapStateToProps function of my React code. I want to add some conditions while returning the object to ensure the data meets certain requirements. const mapStateToProps = (state) => { const { module: { mod ...

Leveraging the power of cannon.js for detecting collisions within a three.js gaming environment

Trying to figure out a way to handle collisions between objects in my three.js project. Considering using cannon.js for its support of necessary primitives, but don't always need all the physics overhead, just collision detection in many cases. Don&ap ...

Utilizing JavaScript-set cookie in PHP: A comprehensive guide

I am currently facing a situation where I am setting a cookie using a JavaScript script on my page, but I need to access this value while generating HTML on the server-side using PHP. Let me explain the scenario. When a user requests a page, PHP star ...

The scroll animation feature was not functioning properly in Next.js, however, it was working flawlessly in create react app

I recently transitioned a small project from Create React App (CRA) to Next.js. Everything is working as expected except for the scroll animations in Next.js, which are not functioning properly. There are no errors thrown; the animations simply do not occ ...

Utilizing either Maps or Objects in Typescript

I'm in the process of developing a simple Pizza Ordering App. The concept is, you select a pizza from a list and it's added to a summary that groups all the selections together. Here's how I want it to appear: Pizza Margarita 2x Pizza Sala ...

Keeping an object in a multidimensional array based on its ID in Angular 4/Ionic 3 without removing it

Exploring a complex data structure: [{ propertyoutsideid: 1, items: [ {itemId: 1, something: 'something'}. {itemId: 2, something: 'something'}. {itemId: 3, something: 'something'}. ] },{ prope ...

Preserve file sequence with jquery file upload

I recently came across an interesting upload script at the following link: This script utilizes jquery file upload to allow for uploading multiple files simultaneously. I'm curious about how to transmit the order in which the files were selected to t ...

Node Selenium for Importing Excel Files---I will help you

My current challenge involves using node selenium in Firefox to click a link that triggers the download of an excel file. I want the downloaded file to be saved in a specific directory, but when I click the link, a dialog box pops up giving me the option ...

Having difficulty replicating the sorting process in Vue.js for the second time

I need assistance with implementing sorting functionality in a Vue.js table component. Currently, the sorting mechanism is working fine on the first click of the th item, but it fails to sort the items on subsequent clicks. const columns = [{ name: &ap ...