Manipulate vertices or faces within BufferGeometry using Three.js - Extrude specific elements

After creating a

new THREE.PlaneBufferGeometry(100, 100, 100, 100);
, I successfully updated the position of vertices to alter the shape of the mesh as shown below:

https://i.sstatic.net/87BMP.png

This modification was inspired by the discussion found here: Threejs drag points

Current Objective:

I am now looking to extrude a face (by selecting 4 vertices) in order to achieve a result similar to this:

https://i.sstatic.net/DtYxI.jpg

To maintain a clean output that can be exported as a single mesh using the ColladaExporter, I aim to keep all modifications within the same mesh.

Edit:

To accomplish this, I will need to duplicate vertices and extrude them upwards. This involves adding 4 new vertices and connecting them together.

My attempt at this process included the following code snippet:

var geo = new THREE.PlaneBufferGeometry(1, 1, 1, 1);
geo.rotateX(-Math.PI * 0.5);
geo.translate(0,0.5,0);

//Now merge them
var newplane = BufferGeometryUtils.mergeBufferGeometries([plane, geo]);
newplane = BufferGeometryUtils.mergeVertices(newplane,1);

The resulting output is displayed here:

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

Although I expected all vertices to merge with the plane, leaving a flat surface, only one corner was affected in my test scenario.

In an effort to rectify this, I began constructing a "cube" with multiple components placed strategically, but applying

BufferGeometryUtils.mergeVertices
did not yield the desired vertex merging outcome:

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

Edit 2 / Progress Update:

By manually adjusting the vertices and normals, I successfully created a PlaneBufferGeometry and extruded it as explained in this documentation:

The extruded plane now has interconnected vertices, causing the dragging of one vertex to move an entire section. My current challenge lies in connecting these new vertices to the original grid to prevent unwanted outcomes like this:

https://i.sstatic.net/8s1Bp.png

The ultimate goal remains to merge all vertices, requiring a way to combine the base plane with the newly extruded piece.

Edit 3 / Completed:

Finally achieved my goal! A detailed answer will follow when time permits, after a full day of intense work and exhaustion.

https://i.sstatic.net/89IZs.png

Answer №1

Unsure if this is exactly what you are looking for, but below is a modified example based on the answer you mentioned (pay attention to the difference in mouseMove implementation). I have expanded it to cover two points only, but it should give you a good understanding:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(1.25, 7, 7);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
 antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var geometry = new THREE.PlaneBufferGeometry(10, 10, 10, 10);
geometry.rotateX(-Math.PI * 0.5);

var plane = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
 wireframe: true,
 color: "red"
}));
scene.add(plane);

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


var raycaster = new THREE.Raycaster();
raycaster.params.Points.threshold = 0.25;
var mouse = new THREE.Vector2();
var intersects = null;
var plane = new THREE.Plane();
var planeNormal = new THREE.Vector3();
var currentIndex = null;
var planePoint = new THREE.Vector3();
var dragging = false;

window.addEventListener("mousedown", mouseDown, false);
window.addEventListener("mousemove", mouseMove, false);
window.addEventListener("mouseup", mouseUp, false);

function mouseDown(event) {
 setRaycaster(event);
 getIndex();
 dragging = true;
}

function mouseMove(event) {
 if (dragging && currentIndex !== null) {
 setRaycaster(event);
 raycaster.ray.intersectPlane(plane, planePoint);
 var indicesToMoveUp = [currentIndex-1, currentIndex];
 var delta_x = geometry.attributes.position.getX(currentIndex) - planePoint.x;
 geometry.attributes.position.setXYZ(currentIndex, planePoint.x, planePoint.y, planePoint.z);
 geometry.attributes.position.needsUpdate = true;
 var old_x_neighbour = geometry.attributes.position.getX(currentIndex - 1);
 geometry.attributes.position.setY(currentIndex-1, planePoint.y);
 geometry.attributes.position.setZ(currentIndex-1, planePoint.z);
 geometry.attributes.position.setX(currentIndex-1, old_x_neighbour - delta_x);
 geometry.attributes.position.needsUpdate = true;
 }
}

function mouseUp(event) {
 dragging = false;
 currentIndex = null;
}

function getIndex() {
 intersects = raycaster.intersectObject(points);
 if (intersects.length === 0) {
 currentIndex = null;
 return;
 }
 currentIndex = intersects[0].index;
 setPlane(intersects[0].point);
}

function setPlane(point) {
 planeNormal.subVectors(camera.position, point).normalize();
 plane.setFromNormalAndCoplanarPoint(planeNormal, point);
}

function setRaycaster(event) {
 getMouse(event);
 raycaster.setFromCamera(mouse, camera);
}

function getMouse(event) {
 mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
 mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}

render();

function render() {
 requestAnimationFrame(render);
 renderer.render(scene, camera);
}
body {
 overflow: hidden;
 margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>

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

The JavaScript replace function using regex eliminates additional content

There is a content string that includes full YouTube URLs and video IDs. I need to replace the URLs with just the video IDs. The example of the "content" variable: var content = '{GENERICO:type="youtube",id="DluFA_AUjV8"}{GENERICO:type="youtube",id ...

How can I effectively transfer parameters to the onSuccess callback function?

In my react-admin project, I'm utilizing an Edit component and I wish to trigger a function upon successful completion. <Edit onSuccess= {onSuccess } {...props}> // properties </Edit> Here's the TypeScript code for the onSuccess fun ...

Need a jQuery function that updates the 'id' after clicking on a specific div? Here's how to do it!

I need help simplifying my current situation. Step 1: I want to increment the variable "count" by 1 every time a specific div is clicked. Step 2: After updating "count", I want to utilize it in another function. This function involves copying the value f ...

Tips and Tricks for Managing an Extensive Array of AJAX Requests (Exceeding 1000)

My application is retrieving a User's Google Contacts from the Google Contacts API on the front end, resulting in a variable number of JSON objects, usually ranging between 1 to 2000. Upon receiving these objects, the app goes through each one, reform ...

Excluding null values when using Mongoose populate query: A simple guide

I'm currently working on an app where I've defined 2 models. const UserSchema = new Schema({ _id: Schema.Types.ObjectId, account:{ type: String, unique: true }, email: String, first_name: String, last_name ...

Display the desired labels on the x-axis using the labels formatter function

Having a set of plotLines, I am looking to display corresponding labels on my xAxis. The data consists of random values around 100 (yAxis) and dates that increment by 10 days (xAxis). var getDaysArray = function(start, end) { for (var arr = [], dt = st ...

In what ways can two identical-looking arrays actually be distinct from each other?

Explore this JavaScript snippet: var st, ary, ary1, ary2; ary = [["a","b","c"], ["d","e","f"]]; // 2D array ary1 = ary[1]; st = "d,e,f"; ary2 = st.split(','); st = typeof(ary1) + " " + ary1.length + " " + ary1 + '\n'; // A ...

Construct a new array by combining elements from two existing arrays

There are two arrays, details and options, each originating from different sources such as web API requests. details: [ { id: 'groups', option: true }, { id: 'category', option: false } ] options: { groups: [ ...

Steps for refreshing a JavaScript function responsible for generating a table

Within the code snippet provided, there is a click event attached to a table row. Upon clicking a row, the script extracts the id value from the first column and triggers a REST call. Subsequently, a new table is constructed using a third-party function ca ...

Converting database data into an array of objects using JavaScript

In my App.js file, I have the following code: const getPlayers = async()=>{ const players = await API.getPlayers(); setPlayers(players) } getPlayers() The following code is from my API.js file: const getPlayers = async() => { return getJson( ...

I am seeking assistance with my code. It is passing most of the test cases, but is failing only two without any error messages. What could

I recently started teaching myself programming, so please excuse me if my question seems a bit basic. One of the challenges on CodeCamp requires defining a function that takes an array with 2 values as input and returns the Least Common Multiple (LCM) of ...

The JSSProvider is not creating a class prefix when using the classNamePrefix option

Currently, I am facing an issue with material-react in my React project. Both the shell and micro-frontend are using material-react, resulting in identical class names such as .jss1 and .jss2. This is causing a clash in styles. I have attempted to generat ...

Converting HTML table text to JSON data using vanilla JavaScript (without any external libraries like Selenium)

As a newcomer to programming and Javascript, my goal is to use Selenium Webdriver in Visual Code to extract HTML table content from a webpage and convert it into JSON data. I've managed to retrieve the table data, but I'm struggling with the conv ...

Tips for sending two values to a PHP file using JavaScript Ajax

I have created a code for two dropdown menus. The goal is to select values from both menus and send them to a php file using the GET method. The values should be sent to the php file only when both menus have selections made. Below is the code snippet: ...

What other ways can websockets be utilized besides comet?

Websockets offer a more efficient solution for comet (reverse Ajax, often achieved through long-polling). However, are there other ways we can utilize websockets? For instance: - Can websockets be used to facilitate communication between different bro ...

Tips for eliminating Blank Attributes from a multi-level JavaScript Object

Here is a JavaScript object example: var test = {"code_operateur":[""],"cp_cult":["",""],"annee":["2011"],"ca_cult":[""]} After running a function on it: for (i in test) { if ( test[i] == "" || test[i] === null ) { delete test[i]; } ...

Managing the creation of a fresh VueJs object with checkboxes enabled for CRUD operations

Hello fellow developers! I am currently working on a shop card project and I'm looking to add a new product to the collection of sale elements. Let's consider the JSON structure retrieved from the backend: "products": [ { "product_prov ...

Is there a method to ascertain the relative position of a point on a polygon?

Apologies in advance as I might have a hard time wording this question properly, so I'll start by explaining my objective. I'm currently working with JavaScript and Raphael. My goal is to save the position of a point in relation to the four cor ...

With Vite, Vue.js can generate 400 requests from a single function invocation

Is it possible that there is a bug with Vite.js or is this behavior normal? I noticed that when using date-fns in Vite.js, it's making 400 requests. It seems like just one function call is resulting in 400 ajax requests being triggered by date-fns. A ...

What is the best way to trigger an action in response to changes in state within Vuex

Are there more sophisticated methods to trigger actions in vuex when a state changes, rather than using a watcher on that state? I want to ensure the most efficient approach is being utilized. ...