Creating a dynamic line with three.js

I am aiming to create a customizable polygon with modifiable vertices represented by red circles. My goal is to dynamically construct the polygon.

When I initialize the geometry as

var geometry = new THREE.Geometry();

geometry.vertices.push(point);
geometry.vertices.push(point);

var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({}));

It functions properly until the second click, creating a straight line between points 1 and 2 but failing to add a third line when another point is pushed to the array. It appears that buffered points are necessary in WebGL.

If I predefine vertices like this, I can draw two lines (after the third click)

var geometry = new THREE.Geometry();

for (var i = 0; i < 4; i++) {
    geometry.vertices.push(point);
}

var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({}));

However, this solution is not optimal since I do not know how many vertices the user intends to add, and it would be inefficient to assign a large number of loops multiple times.

Is there a workaround for this issue?

Answer №1

To create animations on a line or increase the number of points displayed, you can utilize the BufferGeometry along with the setDrawRange() method. It's important to establish a maximum number of points for this process to work effectively.

const MAX_POINTS = 500;

// geometry
const geometry = new THREE.BufferGeometry();

// attributes
const positions = new Float32Array( MAX_POINTS * 3 ); // Each point consists of 3 vertices
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

// drawcalls
drawCount = 2; // Display only the first 2 points
geometry.setDrawRange( 0, drawCount );

// material
const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );

// line
line = new THREE.Line( geometry,  material );
scene.add( line );

If you need to adjust the number of points displayed after the initial rendering, simply update it like so:

line.geometry.setDrawRange( 0, newValue );

In case you want to modify the position data values post the initial rendering, set the needsUpdate flag as shown below:

line.geometry.attributes.position.needsUpdate = true; // Necessary after the first render

Check out this fiddle showcasing an animated line that can be adjusted to fit your requirements.

Version used: three.js r.147

Answer №2

Real-time Line Drawing

Check out this enhanced fiddle where I have improved the code originally provided by user3325025. Now, there is no longer a need to update all points of the line during rendering. Updates are only required when onMouseMove (for adjusting the end point of the line) and onMouseDown (for adding a new point):

// function to update the line
function updateLine() {
  positions[count * 3 - 3] = mouse.x;
  positions[count * 3 - 2] = mouse.y;
  positions[count * 3 - 1] = mouse.z;
  line.geometry.attributes.position.needsUpdate = true;
}

// event handler for moving the mouse
function onMouseMove(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  mouse.z = 0;
  mouse.unproject(camera);
  if( count !== 0 ){
    updateLine();
  }
}

// function to add a new point
function addPoint(event){
  positions[count * 3 + 0] = mouse.x;
  positions[count * 3 + 1] = mouse.y;
  positions[count * 3 + 2] = mouse.z;
  count++;
  line.geometry.setDrawRange(0, count);
  updateLine();
}

Answer №3

If you're interested in doodling freely, I've made some updates to the fiddle to include mouse events and a vector array.

Check out the updated fiddle here

function onMouseDown(evt) {

    if(evt.which == 3) return;


    var x = ( event.clientX / window.innerWidth ) * 2 - 1;
    var y =  - ( event.clientY / window.innerHeight ) * 2 + 1;

    // do not register if right mouse button is pressed.

    var vNow = new THREE.Vector3(x, y, 0);
    vNow.unproject(camera);
    console.log(vNow.x + " " + vNow.y+  " " + vNow.z); 
    splineArray.push(vNow);

    document.addEventListener("mousemove",onMouseMove,false);
    document.addEventListener("mouseup",onMouseUp,false);
}

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 aspects of MongoDB security am I overlooking?

Is it a secure way to connect to Mongo DB by using Node JS, Mongo DB, and Express? Could someone provide an explanation of this code in terms of security? === Many tutorials often only show... var mongoClient = new MongoClient(new Server('localhos ...

Transforming RGB Decimal Color to HEX RGB Color in Three.js

Currently, I am facing a challenge in my task involving colors while working with three.js, a JavaScript library. In this particular task, I need to convert decimal color codes (e.g. 12615680) into formats like #FF0000 or 0xFF0000. I am seeking a JavaScr ...

Variable in v-for loop is not properly declared

Currently, I am attempting to iterate through an array of objects retrieved from the backend and display these objects on the frontend. The Vue framework is throwing an error stating that "event" is not defined on the instance but referenced during render. ...

Allow undici fetch requests to use self-signed certificates

What is the correct way to execute fetch('https://localhost:8888') when dealing with a locally hosted HTTP server that uses a self-signed certificate (using fetch which is derived from undici)? ...

When extracting text using .text(), remember to include spaces between td elements

Is there a method to include space between td's when using .text()? I have searched extensively on Google but could only find information on how to trim space. The code I am currently using is as follows: for (var i = 0, len = rows.length; i < l ...

Extracting data from websites: How to gather information from dynamic HTML elements

On the website I am exploring, there is a dynamic graph with descriptions below it that keep changing. My goal is to extract all these trajectory descriptions. The HTML code snippet related to the description area looks like this: <div class="trajDesc ...

AngularJS is incapable of detaching forms from objects

Creating forms dynamically using ng-repeat and adding them to the vm.forms object is causing issues. When an item is removed from the array, the corresponding form is deleted but the key in the vm.forms object remains, leading to undefined errors. angul ...

Troubleshooting the "@material-ui/core" issue in React: Step-by-step guide

Issue with React: Unable to locate the '@material-ui/core' module in 'C:\Users\user\Downloads\inTech'22-Web Development (EDUGEN)\edu-gen\src\components' Resolution Command: To resolve, run npm in ...

Group all 3 elements with a wrapper

I'm facing a challenge in trying to enclose 3 divs inside one wrapping div. I have successfully wrapped up 2 divs, but the third one is proving to be difficult. To see my progress so far, you can check out my JSFiddle here: http://jsfiddle.net/cz9eY/ ...

Finding the source of the err.kind expression in the MERN stack: Unraveling the mystery

Recently, I've been delving into the world of MERN stack development and came across an interesting technique for Error Handling in a tutorial. The tutorial showcased various expressions that can be used to identify different types of errors being thr ...

What is the best way to convert a repetitive string into a reusable function?

I am currently retrieving data from an API and I want to display it on my website in a more user-friendly manner. The challenge I'm facing is that the number of variables I need is constantly changing, along with their corresponding values. So, I&apos ...

Transforming DayOfYear data in Javascript to utilize with Flot

Attempting to utilize the flot jQuery library for a display, but running into an issue with the X Axis showing dates. The data being received is in DayOfYear format instead: var data = [[192,6.9],[191,49.52],[190,2],[189,0], etc...] Numbers like 192, 19 ...

Using Ajax to implement Basic Authentication for securely accessing an https-protected webpage without requiring users to manually enter their username and password in a

Is there a way to access and display a website page hosted at this URL - , without encountering any authentication dialog box from my application on the same network? I have been unable to bypass the username and password entry request. I successfully imp ...

Real-time Feedback: Providing live updates to users about the current connection status

My task requires pulling data from multiple datasources which can be time-consuming. To enhance user experience, I want to provide real-time information about the progress by displaying messages like "Currently retrieving data from table1" and "Now fetchin ...

What are the steps to modify the camera type in Three.js?

I have added a dropdown list on the page for selecting between two cameras - Perspective and Orthographic. Currently, my Three Scene is using a perspective Camera. I would like to dynamically change the camera to "Orthographic" when selected in the dropdow ...

Guide to bringing in a variable from an external module

As a backend developer working on Node.JS code, I am trying to incorporate some constants from the @aws-sdk/signature-v4 module into my project. Specifically, I need to access AMZ_DATE_QUERY_PARAM as mentioned in the documentation. However, I am struggling ...

JavaScript can be used to activate the onclick event

Is there a way to disable and then re-enable all buttons that share the same class name? I attempted the following code without success: let buttons = document.getElementsByClassName("btn-st"); for (let i = 0; i < buttons.length; i++) { b ...

To insert a <div> element within a <tr> element while preserving the exact position of the <tr> tag - here's how you can do it:

I have a challenge with my table where I need to add a green progress bar in the form of a div element within a tr. The width of this progress bar should change dynamically from 0% to 100%, reflecting the current runtime of the video associated with that p ...

Using Ajax with Laravel for Beginners

After clicking a button in my Laravel app, I want to update some data in the database using ajax without reloading the page. This is a simple ajax request where only a function in a controller needs to be invoked. I tried setting up the ajax request follo ...

Enabling hover effects to scroll divs only when interacted with

I am aiming to achieve two separate scrolling divs and I'm uncertain about the exact approach. Experimenting with various overflow properties has only resulted in one scrolling independently. .profile { width: 100%; display: flex; ...