Example of voxel painting using THREE.js

As I delve into the world of THREE.js and explore various examples, one that caught my eye is the Voxel Painter example.

My current challenge involves ensuring that whenever a new cube is created, the roll-over mesh always moves on top of the recently placed cube rather than at the intersecting point of the current mouse position.

While the source code is accessible through the link provided, I suspect that the solution lies within the following code snippet...

Upon clicking the mouse to add a Voxel, the onMouseDown() function is triggered to determine if the current mouse position intersects with the plane and if the CTRL button has been pressed for either cube creation or deletion.

function onDocumentMouseDown( event ) {

    event.preventDefault();

    var intersects = raycaster.intersectObjects( scene.children );
    
    if ( intersects.length > 0 ) {

        intersector = getRealIntersector( intersects );

        // Delete cube
        if ( isCtrlDown ) {

            if ( intersector.object != plane ) {

                scene.remove( intersector.object );

            }
        } 
        // Create cube
        else {
            intersector = getRealIntersector( intersects);
        
            setVoxelPosition( intersector );
                    
            var voxel = new THREE.Mesh( cubeGeo, cubeMaterial );
            voxel.position.copy( voxelPosition );    
            voxel.matrixAutoUpdate = false;
            voxel.updateMatrix();
             
            scene.add( voxel );
        }
    }    
}

During the cube creation process, THREE.js captures the current point of intersection where the mouse hovers

intersector = getRealIntersector( intersects);
and then sets the new Voxel position using the function setVoxelPosition( intersector ); with the intersecting point as the input.

Here is the setVoxelPosition function...

function setVoxelPosition( intersector ) {

      normalMatrix.getNormalMatrix( intersector.object.matrixWorld );

      tmpVec.copy( intersector.face.normal );
      tmpVec.applyMatrix3( normalMatrix ).normalize();

      voxelPosition.addVectors( intersector.point, tmpVec );

      voxelPosition.x = Math.floor( voxelPosition.x / 50 ) * 50 + 25;
      voxelPosition.y = Math.floor( voxelPosition.y / 50 ) * 50 + 25;
      voxelPosition.z = Math.floor( voxelPosition.z / 50 ) * 50 + 25;
}

And here's a snippet from the render loop...

function render() {

    if ( isShiftDown )
        theta += mouse2D.x * 1.5;

    raycaster = projector.pickingRay( mouse2D.clone(), camera );
    var intersects = raycaster.intersectObjects( scene.children );
            
    if ( intersects.length > 0 ) {

        intersector = getRealIntersector( intersects );

        if ( intersector ) {

            setVoxelPosition( intersector );
            rollOverMesh.position = voxelPosition;
        }
    } 

    camera.position.x = 1400 * Math.sin( THREE.Math.degToRad( theta ) );
    camera.position.z = 1400 * Math.cos( THREE.Math.degToRad( theta ) );

    camera.lookAt( scene.position );

    renderer.render( scene, camera );
}

I have made several attempts with different values in setVoxelPosition( intersector ) but have yet to achieve the desired outcome...

If anyone could offer guidance or point me in the right direction, it would be greatly appreciated.

Thank you.

Answer №1

There are numerous approaches to tackle this issue. To be transparent, reverse engineering the code is the best way to fully grasp how it works. From my personal experience with this voxel code, it's crucial to comprehend the actions triggered when clicking the mouse to create a new voxel box.

It's accurate to note that the function captures the current mouse position to generate the box. After completing the click and constructing the box, the program reverts back to identify the mouse's location and position the Ghost box. Maintenance is required to ensure the Ghost box doesn't overlap the previously created box - manually adjusting the mouse's position upwards a bit is necessary.

Instead of directly manipulating the setVoxelPosition function, a suggestion would be to temporarily adjust the x, y, and z coordinates of the ghost in correlation to the matrix intersect mouse point on your computer. By slightly increasing the matrixIntersect.x, .y, .z properties upon a successful click, it's possible to achieve the desired 'box-on-top' effect immediately after clicking. It's essential to reset these properties once the user's mouse moves away from the object; otherwise, complications may arise if the properties continuously grow after each click.

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

Encountering an issue with html2canvas: receiving an error message stating "object

To print the div using Javascript, I encountered an issue with the generated barcode not appearing in the printed page. This led me to use the html2canvas approach to 'render' the div before printing it out. Here is the code snippet: HTML: < ...

Pass data to all routes in ExpressJS

After logging in, I am setting req.session variables as follows: req.session.loggedin = true req.session.firstname = loginDetails.firstName; I would like to streamline this process and pass this information to ALL routes without manually adding them to ea ...

Guide on how to verify if a component with a specific name is registered within the Composition API of Vue 3

My current situation involves a template that loads dynamic components based on their names: <template> <div> <div> <div> <component :is="getFormRenderer" &g ...

Arrays data being retrieved and set by Chrome Extension are visible in the console but not appearing in the HTML

Having trouble displaying my arrays in HTML. I'm attempting to do this within a Chrome Extension. While I can view the array perfectly in console.log, I'm encountering issues when trying to add it to the HTML DOM: /* Generating the array f ...

Choose an item from a list that does not have a particular class

Here is a list of items: <ul id='myList'> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <li class='item-selected'>Item 4</li> <li>Item 5</li> & ...

I'm looking for a way to create a Redux thunk action creator that will return a promise. How

In my code, I have a primary thunk that is triggered by a button click. Within this thunk, I need to invoke another thunk and ensure it completes before proceeding. The second thunk returns a promise. Below is an excerpt of the code in question: export f ...

Switching React components with const

Having some difficulties with the React Switch feature. Attempting to create a layout within another layout, and so far, everything seems to be functioning correctly. import React from "react"; import {Redirect, Route, Switch} from "react-router-dom"; imp ...

"Wordpress Pluto theme: A stellar choice for your

I'm trying to add a link in my main template.index file that will redirect to one of my pages when clicked on the JavaScript button at the top in Pluto theme. Currently, the text is there but clicking on it opens something I don't want. Here&apo ...

What is the correct way to utilize ng-if/ng-show/ng-hide to hide or show HTML elements within the app.run function

I am currently working on developing an app that loads views correctly. HTML: <body> <loading outerWidth='1000' outerHeight='1000' display='isReady'></loading> <div class='wrapper' ng-sho ...

Problem with jQueryUI Sortable cancel property preventing input editing

Currently, I am utilizing jquery-3.2.1.min.js and jquery-ui.min.js version 1.12.1 The task at hand is to create a sortable list where certain elements are not sortable (specifically, other sortable lists). It is crucial that the input elements remain edit ...

retrieve: add elements to an array

I'm having trouble identifying the issue here. I am fetching some json data (using a text file) and trying to push it into an array in the global scope. Even though I iterate over the json and push entries to the array, when I log it out, it appears e ...

Encountering an issue with ReactJS + Redux where the error message states: "Error in prop type: The Right-hand side of 'instanceof' cannot be called"

Currently working on a web app project in React with Redux for global state management. A puzzling issue has arisen - we're receiving warnings in the browser console. How can we resolve this? It seems related to prop types declaration, but the soluti ...

Unexpected null value returned upon form submission with Mongoose and ExpressJS

I am encountering an issue with sending data from a basic HTML form to MongoDB using Express. When I try to post it, I am getting null as the result. The Schema I used is: commentname: String. Below is the snippet of the HTML code: <form id="form ...

How can I resolve the vertical adjustment issue of Bootstrap 5 input group on mobile devices?

My current issue involves using Bootstrap 5.2.3 to create an input group that displays a set of spans with the ".input-group-text" class alongside inputs with the ".form-control" class. While this setup works well on a computer screen, it does not adjust c ...

Tips for managing nested objects within React state and keeping them updated

Could someone kindly point out where I might be going wrong with this code? Upon checking the console.log, it seems like the date function is functioning correctly. However, despite using this.setState, the timestamp remains unchanged. Any help would be gr ...

Retrieve information from a JSON file according to the provided input

Can someone help me fetch data based on user input in JavaScript? When the input is 'Royal Python', I'm supposed to retrieve details about it. However, the code provided gives an error stating 'The file you asked for does not exist&apo ...

Replacing JS/CSS include sections, the distinction between Debug and Release versions

Can you share how you manage conditional markup in your masterpages for release and debug builds? I am currently using the .Net version of YUI compress to combine multiple css and js files into a single site.css and site.js. One idea I had was to use a u ...

Clicking the set button in Jquery mobile datebox resets the time

I am experimenting with the jquery mobile datebox (courtesy of Jtsage) to select time and date. Unfortunately, every time I reset the time by clicking the set button, I am unable to retrieve the correct time. Below are my code snippets: $.extend($.jtsag ...

Selecting and Uploading Multiple Files in Internet Explorer (less than version 9)

I have been struggling with selecting and uploading multiple files at once to the server. Here is the code I am currently using: <html> <body> <form action="upload.php" method="post" enctype="multipart/form-data" name="myForm"> <l ...

Handling exceptions in the event that the backend URL resource cannot be accessed

I'm facing an issue with my Vue.js single file component where I am trying to catch exceptions when the URL requested by axios.post is unreachable. I have encapsulated the entire code in a try block, but for some reason, the alert in the catch block i ...