Discover the locations where a mesh and a plane intersect using Three JS

After creating a three.js scene with a plane intersecting a mesh, I am trying to retrieve an array of points where the mesh's edge crosses the plane. Despite searching for solutions, I haven't found anything helpful so far.

Please refer to the image below for my current setup:

https://i.sstatic.net/f6LOZ.png

The highlighted coordinates in the image linked below are what I am attempting to collect:

https://i.sstatic.net/7RI3q.jpg

If anyone can provide guidance on how to achieve this, it would be greatly appreciated.

Thank you,

S

Answer №1

This is just the beginning, not the final solution. It provides a starting point for further exploration.

UPDATE: Here you can find an extension of this answer, explaining how to create contours from given points.

Additionally, check out this SO question for insightful responses from WestLangley and Lee Stemkoski regarding the .localToWorld() method of THREE.Object3D().

Imagine wanting to determine the intersection points of a common geometry (e.g., THREE.DodecahedronGeometry()).

https://i.sstatic.net/QbiF8.png

The concept:

  1. THREE.Plane() features the

    .intersectLine(line, optionalTarget)
    method

  2. A mesh consists of faces (THREE.Face3())

  3. Each face includes properties a, b, c, storing vertex indices

  4. Given vertex indices, we can retrieve corresponding vertices from the array

  5. Knowing the coordinates of face vertices enables constructing three THREE.Line3() objects

  6. With these lines, it's possible to verify if the plane intersects them

  7. If there's an intersection point, it can be saved in an array

  8. Repeat steps 3 - 7 for every face of the mesh

Clarification along with code snippets:

We have plane assigned as THREE.PlaneGeometry() and obj representing THREE.DodecahedronGeometry()

Hence, let's instantiate a THREE.Plane():

var planePointA = new THREE.Vector3(),
  planePointB = new THREE.Vector3(),
  planePointC = new THREE.Vector3();

var mathPlane = new THREE.Plane();
plane.localToWorld(planePointA.copy(plane.geometry.vertices[plane.geometry.faces[0].a]));
plane.localToWorld(planePointB.copy(plane.geometry.vertices[plane.geometry.faces[0].b]));
plane.localToWorld(planePointC.copy(plane.geometry.vertices[plane.geometry.faces[0].c]));
mathPlane.setFromCoplanarPoints(planePointA, planePointB, planePointC);

In this setup, any face on the plane contains three co-planar vertices, allowing us to form mathPlane using .setFromCoplanarPoints() method.

Next, iterate through faces of our obj:

var a = new THREE.Vector3(),
  b = new THREE.Vector3(),
  c = new THREE.Vector3();

  obj.geometry.faces.forEach(function(face) {
    obj.localToWorld(a.copy(obj.geometry.vertices[face.a]));
    obj.localToWorld(b.copy(obj.geometry.vertices[face.b]));
    obj.localToWorld(c.copy(obj.geometry.vertices[face.c]));
    lineAB = new THREE.Line3(a, b);
    lineBC = new THREE.Line3(b, c);
    lineCA = new THREE.Line3(c, a);
    setPointOfIntersection(lineAB, mathPlane);
    setPointOfIntersection(lineBC, mathPlane);
    setPointOfIntersection(lineCA, mathPlane);
  });

where

var pointsOfIntersection = new THREE.Geometry();
...
var pointOfIntersection = new THREE.Vector3();

as well as

function setPointOfIntersection(line, plane) {
  pointOfIntersection = plane.intersectLine(line);
  if (pointOfIntersection) {
    pointsOfIntersection.vertices.push(pointOfIntersection.clone());
  };
}

To conclude, visualize the points obtained:

var pointsMaterial = new THREE.PointsMaterial({
    size: .5,
    color: "yellow"
  });
var points = new THREE.Points(pointsOfIntersection, pointsMaterial);
scene.add(points);

Check out this jsfiddle example. Click the button to see the intersection points between the plane and the dodecahedron.

Answer №2

Latest Update: THREE.js version 146

Here is a comprehensive example using BufferGeometry instead of the deprecated Geometry starting from version r.125. This example follows the insightful contributions of @prisoner849 and the discourse thread on Plane intersects mesh with three.js r125.

The example showcases clipping the geometry based on intersection points that are utilized in generating LineSegments.

Alternatively, you can create a Plane from the PlanarGeometry utilizing Quaternion and Normal:

let localPlane = new THREE.Plane();
let normal = new THREE.Vector3();
let point = new THREE.Vector3();

normal.set(0, -1, 0).applyQuaternion(planarGeometry.quaternion);
point.copy(planarGeometry.position);
localPlane.setFromNormalAndCoplanarPoint(normal, point).normalize();**

The function updates Lines with the current intersections based on the position of the PlanarGeometry:

let lines = new THREE.LineSegments(
  new THREE.BufferGeometry(),
  new THREE.LineBasicMaterial({
    color: 0x000000,
    linewidth: 5
  })
);

function drawIntersectionLine() {
  let a = new THREE.Vector3();
  let b = new THREE.Vector3();
  let c = new THREE.Vector3();

  const isIndexed = obj.geometry.index != null;
  const pos = obj.geometry.attributes.position;
  const idx = obj.geometry.index;
  const faceCount = (isIndexed ? idx.count : pos.count) / 3;

  const clippingPlane = createPlaneFromPlanarGeometry(plane);
  obj.material.clippingPlanes = [clippingPlane];

  let positions = [];

  for (let i = 0; i < faceCount; i++) {
    let baseIdx = i * 3;
    let idxA = baseIdx + 0;
    a.fromBufferAttribute(pos, isIndexed ? idx.getX(idxA) : idxA);
    let idxB = baseIdx + 1;
    b.fromBufferAttribute(pos, isIndexed ? idx.getX(idxB) : idxB);
    let idxC = baseIdx + 2;
    c.fromBufferAttribute(pos, isIndexed ? idx.getX(idxC) : idxC);

    obj.localToWorld(a);
    obj.localToWorld(b);
    obj.localToWorld(c);

    lineAB = new THREE.Line3(a, b);
    lineBC = new THREE.Line3(b, c);
    lineCA = new THREE.Line3(c, a);

    setPointOfIntersection(lineAB, clippingPlane, positions);
    setPointOfIntersection(lineBC, clippingPlane, positions);
    setPointOfIntersection(lineCA, clippingPlane, positions);
  }

  lines.geometry.setAttribute(
    "position",
    new THREE.BufferAttribute(new Float32Array(positions), 3)
  );
}

function setPointOfIntersection(line, planarSrf, pos) {
  const intersect = planarSrf.intersectLine(line, new THREE.Vector3());
  if (intersect !== null) {
    let vec = intersect.clone();
    pos.push(vec.x);
    pos.push(vec.y);
    pos.push(vec.z);
  }
}

View the full example on CodePen

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

Error: Attempting to use Moment with Bootstrap Date Time Picker results in TypeError, as Object(...) is not recognized as

Let me show you the code for my picker in a simple way: import {moment} from 'moment'; const datePicker = () => { $('.datetimepicker').datetimepicker({ format: 'LT', locale: 'PT-BR', icons: { ...

Combining the Powers of Express.js and Kue.js

Currently, I am working on a personal project that involves processing tasks in the background. To achieve this, I need to establish communication between my Express and Kue frameworks. Here is a brief overview of my setup: My Express.js application forks ...

When attempting to trigger a function by clicking a button in Angular 8 using HTTP POST, nothing is happening as

I've been struggling to send a POST request to the server with form data using Observables, promises, and xmlhttprequest in the latest Angular with Ionic. It's driving me crazy because either I call the function right at the start and the POST wo ...

What is the best way to display a specific object prop on a page after triggering the onChange() method from a selected

Looking to simplify some code that's become a bit overwhelming. My pizza order consists of arrays for size and price. I'm trying to update the price when a user selects a size, but I've been stuck on an issue with mapping pizzas from the ca ...

What is the best way to consistently apply parent transforms to child elements in the same sequence?

Within my software, users have the ability to select 3D objects on a workplane and then scale, move, or rotate these elements collectively using a "transformation" container. This container, represented by an Object3D, groups all transformations and applie ...

When the model is replaced, the Vue.js directive v-html may fail to update

Upon running the code below (a Vue.js component), my expectation is that both the v-html directive and the console.log() will display the same value after the AJAX call returns. To my surprise, while v-html remains stuck at "loading...(1)", the value of o ...

What is the best way to retrieve my chosen GridView rows and store them in a JavaScript variable?

Using ASP.NET C# MVC3 with razor templates, I have a question: In my DevExpress GridView, I can select rows. How can I pass the selected rows into a JavaScript variable? Also, if I select multiple rows simultaneously, is there a way to get them in an arra ...

Transferring information from a modal popup to a controller

I am attempting to pass parameters from a Bootstrap modal popup to my controller using Javascript and Ajax. However, when I click the button, it does not seem to work on the controller. How can I successfully send these parameters? Below is the HTML code ...

The Ajax validation form mistakenly redirects the echoes to a different page instead of the intended page for displaying the output

I am currently working on creating an ajax-form to validate the client-side server of my sign-up form. My goal is to have error messages displayed on the same page where they are triggered, without loading a separate page. Below is the code from my (sign ...

If the user confirms it with a bootstrap dialog box, they will be redirected to the corresponding links

Firstly, I am not interested in using javascript confirm for this purpose. Please read on. For example, adding an onClick attribute to each link with a function that triggers a system dialog box is not what I want. Instead of the standard system dialog bo ...

How to locate an ObjectId within an array of ObjectIds using Mongoose (MongoDB)

Currently, my setup involves using nodejs, mongoose (with mongodb as the database), and javascript. Within my database, I have a collection named A which contains the following examples: { "item": "Kitchen", "location": ...

MongoDB Stitch retrieves all data fields

Can anyone help me with my MongoDB query issue? I've recently started working with mongoDB and I'm having trouble getting just one field back for all my documents. var docs = db.collection("articles").find({}, { _id: 0, title:1}).asArray(); De ...

Working with Javascript objects and arrays

Need assistance with manipulating/updating a JavaScript array. Hoping for some help. The initial array looks like this: array('saved_designs'=array()); In Javascript JSON format: {"saved_design":{}} I plan on adding a label and its associa ...

Instructions for displaying a React component in the <main> element when employing react-burger-menu

Check out my code here. Utilizing react-burger-menu has allowed me to successfully implement the sidebar feature. The sidebar functionality is working as expected. My current challenge involves figuring out how to open the content for Home or GG within ...

Struggling to utilize the filter technique in JavaScript?

Hey there, I'm facing a challenge in my JavaScript course. The exercise requires the creation of a function that filters an array to only keep strings with less than 10 characters. I've made several attempts at solving this problem, but haven&ap ...

The issue of button onclick textfield validation malfunctioning

Within this container, there is a text field identified as 'codeCityId' along with a button that triggers an onclick method. When the button is clicked, the function will verify the input. function click()={ var valid = $('#codeCityId' ...

Conceal elements that don't match from an array using Angular

There is a search box containing an ng-model: <input type="text" class="form-control" placeholder="Search" ng-model="searchLibrary.text"> Additionally, there is an ng-repeat utilizing a filter searchLibrary.text <div ng-repeat="w in items | fil ...

Learn how Angular 2 allows you to easily add multiple classes using the [class.className] binding

One way to add a single class is by using this syntax: [class.loading-state]="loading" But what if you want to add multiple classes? For example, if loading is true, you want to add the classes "loading-state" and "my-class". Is there a way to achieve t ...

The EventDispatcher function has been refined and enhanced in version r58

There has been a recent change in r58 related to the EventDispatcher, causing an issue where I am unable to add any custom events to Objects. Previously, following the instructions from this Stack Overflow post, I used to have: var spinner_obj = new THREE ...

Invoking PHP function within a specific class using Ajax

I am currently utilizing Zend Framework. My PHP class is structured as follows: FileName : AdminController.php Path : /admin/AdminController.php Ajax Function : function exportToExcel() { $.ajax({ url: "/admin/AdminController/testFunction", ty ...