javascript - Three.js Draw where mouse clicks, but entirely parallel to camera orientation - Stack Overflow

I"m not exactly sure how I can do this. I read a lot about raycasting and that seems to be good fo

I"m not exactly sure how I can do this. I read a lot about raycasting and that seems to be good for finding points that intersect with something, but in this case I just want it to interpolate the 2d mouse coordinates to the 3d point exactly where the mouse clicks, regardless of scale, rotation, whether or not there's an object there, etc.

One method I've thought of but not approached would be making an invisible plane that is parallel to the camera, always oriented upright and always intersecting the y axis. Then use a raycaster to hit the plane, draw as needed, then delete the plane. Seems like a silly way to do this though.

At the moment I have a method that works pretty well but it has some issues when the line gets further away from the origin, or the camera gets zoomed

In this photo I drew two lines from two different perspectives. The vertical line what it looks like when the camera is level with the x and z axis, and I draw a straight line down the y axis, while the horizontal line is what happens when i scribble with the camera facing down. .png

As you can see, it seems to use the distance to the camera to make this calculation, so the further the distance from the camera, the more distortion is in the calculation. How can get rid of this distortion?

source: live demo: /

Here is the relevant code:

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;
}

I used information from two stackoverflow posts to e up with this, and it has the issues I've described.

firstly, this post shows how to draw and convert it to the z axis. It is flat. But I had a lot of trouble trying to make that work in three dimensions.

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

and then i used information in the below post to at least get it parallel to the camera on the x-z axis like such: .png

Moving objects parallel to projection plane in three.js

I"m not exactly sure how I can do this. I read a lot about raycasting and that seems to be good for finding points that intersect with something, but in this case I just want it to interpolate the 2d mouse coordinates to the 3d point exactly where the mouse clicks, regardless of scale, rotation, whether or not there's an object there, etc.

One method I've thought of but not approached would be making an invisible plane that is parallel to the camera, always oriented upright and always intersecting the y axis. Then use a raycaster to hit the plane, draw as needed, then delete the plane. Seems like a silly way to do this though.

At the moment I have a method that works pretty well but it has some issues when the line gets further away from the origin, or the camera gets zoomed

In this photo I drew two lines from two different perspectives. The vertical line what it looks like when the camera is level with the x and z axis, and I draw a straight line down the y axis, while the horizontal line is what happens when i scribble with the camera facing down. https://i.sstatic/MBuhf.png

As you can see, it seems to use the distance to the camera to make this calculation, so the further the distance from the camera, the more distortion is in the calculation. How can get rid of this distortion?

source: https://github./AskAlice/mandala-3d-threejs live demo: https://askalice.me/mandala/

Here is the relevant code:

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;
}

I used information from two stackoverflow posts to e up with this, and it has the issues I've described.

firstly, this post shows how to draw and convert it to the z axis. It is flat. But I had a lot of trouble trying to make that work in three dimensions.

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

and then i used information in the below post to at least get it parallel to the camera on the x-z axis like such: https://i.sstatic/5mSmb.png

Moving objects parallel to projection plane in three.js

Share Improve this question edited Dec 6, 2017 at 20:36 Alice asked Dec 6, 2017 at 19:42 AliceAlice 4241 gold badge9 silver badges29 bronze badges 9
  • Instead of invisible plane mesh, you can use THREE.Plane() and .intersectPlane() method of your THREE.Raycaster()'s .ray object. – prisoner849 Commented Dec 6, 2017 at 20:49
  • Can you try to clarify this a bit more, i'm having a hard time understanding what you need. – pailhead Commented Dec 6, 2017 at 22:27
  • Go into the demo. Hold SHIFT and drag until the camera is facing down. scribble a lot of stuff, face the camera upright. The drawing was not parallel to the orientation of the camera, rather the further away the point is from the camera, the more distorted it is, making a semisphere. Ideally it would make flat lines that do not go up in the y direction, because that is just distortion. I'll try messing with the raycaster and planes more when I'm off work – Alice Commented Dec 6, 2017 at 22:49
  • So you don't want to draw inside a sphere (radius === distanceToCamera) but rather a plane? You can also dot the vector you use for distance with the camera direction. Divide the desired distance with the dot product, and multiplyScalar the original vector. – pailhead Commented Dec 6, 2017 at 23:46
  • It seems I really ought to learn more college math before I try anything crazy. This didn't seem crazy. It's my first three.js project. I figured a library would help me rid of all the ridiculous math. This seems like a pretty simple concept, having the mouse click where you point, but there's a lot that goes into it, and a lot of possibilities! I've e a long way in the past 8 years of my programming experience. I now understand now why calculus is required for my CS major. I know that's a lot to say. Is there any chance you could elaborate on this math? The first time i read it was like 零零 – Alice Commented Dec 8, 2017 at 4:40
 |  Show 4 more ments

1 Answer 1

Reset to default 7

That option with THREE.Plane() and THREE.Raycaster().ray.intersectPlane():

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);
}

Run the code snippet, click the "draw" checkbox to set it as checked, move your mouse randomly (without mouse down), click the checkbox again, rotate the scene with mousedown. All points are 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/build/three.min.js"></script>
<script src="https://threejs/examples/js/controls/OrbitControls.js"></script>
<div style="position:absolute;">
  <input id="draw" type="checkbox">
  <label for="draw" style="color: white;">draw</label>
</div>

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745063196a4609090.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信