Create artwork in Three.js by clicking the mouse, with the drawings remaining in line with the orientation of

I am struggling to figure out the best way to achieve this. While raycasting seems effective in finding points that intersect with objects, I simply want to translate 2D mouse coordinates to a 3D point where the mouse clicks, regardless of scale, rotation, or any objects present.

One idea I considered but have not yet implemented involves creating an invisible plane parallel to the camera, always upright and intersecting the y axis. Then, using a raycaster to hit the plane, draw accordingly, and then remove the plane. However, this method feels inefficient.

Currently, I have a method that works relatively well but encounters issues when the line moves away from the origin or the camera is zoomed.

In the image provided, two lines are drawn from different perspectives. The vertical line shows what happens when the camera aligns with the x and z axes, while the horizontal line demonstrates the result when the camera faces downward. https://i.sstatic.net/MBuhf.png

It appears that the calculation relies on the distance to the camera, resulting in distortion as the line moves farther away. How can this distortion be eliminated?

Source: https://github.com/AskAlice/mandala-3d-threejs Live demo:

Below is the relevant code snippet:

js/content.js@112

function get3dPointZAxis(event)
{
    camPos = camera.position;
    var mv = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY/window.innerHeight) * 2 + 1, 1).unproject(camera);
    var m2 = new THREE.Vector3(0,0,0);
    var pos = camPos.clone(); 
    pos.add(mv.sub(camPos).normalize().multiplyScalar(m2.distanceTo(camPos)));
    return pos;
}

This function was developed based on information from two Stack Overflow posts, but it still has the mentioned issues.

Initially, I referred to this post for drawing and converting to the z-axis in a flat manner, though implementing it in three dimensions proved challenging:

How to draw a line segment at run time using three.js

Subsequently, I utilized details from another post to align the object parallel to the camera on the x-z axis like so: https://i.sstatic.net/5mSmb.png

Moving objects parallel to projection plane in three.js

Answer №1

When using both THREE.Plane() and

THREE.Raycaster().ray.intersectPlane()
, this option allows you to:

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var plane = new THREE.Plane();
var planeNormal = new THREE.Vector3();
var point = new THREE.Vector3();

function getPoint(event){
  mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
  mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
  planeNormal.copy(camera.position).normalize();
  plane.setFromNormalAndCoplanarPoint(planeNormal, scene.position);
  raycaster.setFromCamera(mouse, camera);
  raycaster.ray.intersectPlane(plane, point);
}

To see this in action, run the code snippet, check the "draw" checkbox, move your mouse without clicking, uncheck the checkbox, then rotate the scene while holding down the mouse. All points will lie on the same plane.

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var plane = new THREE.Plane();
var planeNormal = new THREE.Vector3();
var point = new THREE.Vector3();

document.addEventListener("mousedown", onMouseDown, false);
document.addEventListener("mousemove", onMouseMove, false);

function getPoint(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  planeNormal.copy(camera.position).normalize();
  plane.setFromNormalAndCoplanarPoint(planeNormal, scene.position);
  raycaster.setFromCamera(mouse, camera);
  raycaster.ray.intersectPlane(plane, point);
}

function setPoint() {
  var sphere = new THREE.Mesh(new THREE.SphereBufferGeometry(.125, 4, 2), new THREE.MeshBasicMaterial({
    color: "yellow",
    wireframe: true
  }));
  sphere.position.copy(point);
  scene.add(sphere);
}

function onMouseDown(event) {
  getPoint(event);
  if (draw.checked) setPoint();
}

function onMouseMove(event) {
  getPoint(event);
  if (draw.checked) setPoint();
}

render();

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div style="position:absolute;">
  <input id="draw" type="checkbox">
  <label for="draw" style="color: white;">draw</label>
</div>

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

scrolling through a list using .slice choosing an excessive amount of items

Is it possible to create a dynamic pager that can be customized using parameters from the URL? I have noticed that when I hardcode the perTime variable, everything works fine. However, as soon as I try to use a parameter from the URL, the page starts behav ...

I want the navigation bar to appear only upon scrolling, but when I refresh the page it is already visible, and then vanishes as I start scrolling

I'm working on a project where I want the navigation bar to only appear after scrolling a certain distance down the page. However, I've noticed that when I refresh the browser, the navigation bar appears immediately and then disappears once I sta ...

Exploring an unusual HTML structure using Python's Beautiful Soup and urllib for web scraping

While extracting data may not be a challenge, the real issue lies in locating it. My focus is on scraping football data from a website that presents statistics either for all years or for specific seasons. However, despite selecting a particular season, ...

Tips for making an input field that overlays text

I am currently working on a project that involves creating multiple cards using Bootstrap. Each card consists of a header, body, and footer. When a card is clicked on, I want an input field to appear in the header, footer, and body sections, overlaying the ...

Incorporating a JSON file through a script element

A customized I18n plugin has been developed to accept various languages through json files. The goal is to simplify usage for users by allowing them to easily insert their json package directly into a page along with the script: <script id="pop-languag ...

Is it possible to detect the source of a digest cycle in AngularJS?

I've found myself knee-deep in a legacy AngularJS project lately. The codebase is quite intricate and expansive, making it difficult to showcase here. However, I've come across an issue where functions triggered during digest changes are firing h ...

Next.js experiencing development server compile errors and broken page routing in production builds

Howdy everyone! I'm currently working on an app using Next.js. Every time I make a change, the server automatically compiles with the updates, but unfortunately, the pages often fail to render properly. Sometimes it takes several minutes for them to l ...

Unable to execute node in vscode terminal

Can anyone help me figure out why I'm unable to run Node in my vscode terminal? I'm a newbie and currently using POP OS 22.04. https://i.stack.imgur.com/WqHWM.pnghttps://i.stack.imgur.com/GEHeA.png Your assistance would be greatly appreciated. ...

Why does the browser keep converting my single quotation marks to double, causing issues with my JSON in the data attribute?

This task should be straightforward, but I seem to be facing a roadblock. I am trying to insert some JSON data into an input's data attribute, but the quotes in the first key are causing issues by prematurely closing the attribute. Here is the code ...

Dispatching actions in `componentDidMount` is restricted in Redux

Update at the bottom of post I've created a React container component called AppContainer, which checks if the user is authenticated. If the user is authenticated, it renders the app's routes, header, and content. If not, it displays a Login com ...

Why is the `node-config` configuration undefined within a TypeScript Jest environment?

I have a TypeScript module that is functional in both development and production environments. It utilizes https://github.com/lorenwest/node-config. When I attempt to import it into Jest for testing purposes, I encounter an error suggesting that the config ...

Escaping double quotes in dynamic string content in Javascript can prevent unexpected identifier errors

Need help with binding the login user's name from a portal to a JavaScript variable. The user's name sometimes contains either single or double quotes. I am facing an issue where my JavaScript code is unable to read strings with double quotes. ...

Creating a JSON object from text using JavaScript is a straightforward process

Looking to generate an object using the provided variable string. var text ='{"Origin":"Hybris","country":"Germany","Email":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfem ...

"Capturing the essence of the web: Explore the

Hi there! Recently, I came across this fascinating short video at and I can't stop thinking about how to replicate that cool scanning effect. From what I gathered, it seems like you need two groups: one with solid cubes and the other with wireframed ...

What is the best way to ensure a consistent time interval between invoking two functions in JavaScript?

Is there a way to create a code that will call one function, let's say toStart(), and then immediately call another function, toStop(), exactly two seconds after the first function is initiated? I want this process to continue until a specific button, ...

Identifying the class name of SVGAnimatedString

While working on creating an SVG map, I encountered an issue where the functions triggered by hovering over 'g' elements were not functioning as expected. In order to troubleshoot this problem, I decided to check for any issues with the class nam ...

Take action once the Promise outside of the then block has been successfully completed

Presented below is the code snippet: function getPromise():Promise<any> { let p = new Promise<any>((resolve, reject) => { //some logical resolve(data); }); p.finally(()=>{ //I want do something when ou ...

I'm struggling to make the jquery parentsUntil function work properly

Would appreciate some help with using the jquery parentsUntil method to hide a button until a radio box is selected. I've been struggling with this for a few days now and can't seem to figure out what I'm doing wrong. Any insights would be g ...

Retrieve the specific data from the database when the <tr> element is hovered over

Hey everyone, I've been struggling with a problem for some time now. I have a loop that retrieves values from a database and I want each value to display onmouseover using JavaScript. However, it's only showing the value of the first row for all ...

maintain ajax history during jquery redirection

Currently, I am designing a compact application using php, jquery, and ajax. The purpose of this app is to enable users to conduct customer searches, view customer details, and easily navigate back to the search page without losing any data. To enhance use ...