stemkoski / stemkoski.github.com

http://stemkoski.github.io/
1.8k stars 714 forks source link

Get coordinates on floor when clicked in canvas #15

Closed mxgross closed 9 years ago

mxgross commented 11 years ago

Hey,

can explain please, how I receive the coordinates of a point on the floor when the canvas is clicked? I want to clone models and set the position from the cloned one by doubleclicking into the canvas. But because the camera view can dynamically be changed, I need to find out the coordinates of the clicked point in the floor.

I trried it simiular to your example "http://stemkoski.github.io/Three.js/Mouse-Click.html" and changed the content of the targetlist to my floor, but the intersect values are not how i expected.

The point values are always something between 0 and 1, no matter how far I click away from the origin point of the floor (0, 0, 0)

erichlof commented 11 years ago

Hi mexx91,

Check out this Three.js example: http://threejs.org/examples/#canvas_interactive_cubes

Notice how they place the black circles exactly where you click. This uses the Three.js Raycaster which casts a ray from your camera out into the world (along the -z axis, or in other words, into your computer screen).
While the demo is still running, click the "View Source" button in the upper-right corner and scroll down to the code lines 117-137. This is where the magic happens.

Above this code they created a 'projector' by: projector = new THREE.Projector();

Then you can call projector.unprojectVector( vector, camera ); like they did on line 122. I'm not so sure of the math behind all of this but if you just copy and paste and change some variable names, it should work.

On line 133 it gives you the world coordinates that you are wanting by: particle.position = intersects[ 0 ].point;

When you call var intersects = raycaster.intersectObjects( objects ); it returns intersects[array].point if it hits something out in the world. This point is in x,y,and z coordinates that you are wanting.

@stemkoski If there is an easier example, please let us know. Otherwise, this is the easiest 'picking' example that I have yet found.

@mexx91 Hope this helps and good luck! Erich

mxgross commented 11 years ago

Thank you so much for your fast response. I am a bit further now but there is still a problem with the position coordinates of the new object. I uploaded the project on github, maybe you can have a look: https://github.com/mexx91/ThreeJSExamples

I think the problem may come from the calculation of the vector with the "event.ClientX ...." stuff.

Thanks

erichlof commented 11 years ago

Hi again, I had a chance to look through some of your code and I spotted a small discrepancy that might be the source of the position problem.

In your addModel.js file on Line 12, here's what you have: var vector = new THREE.Vector3( (event.clientX / window.innerWidth ), - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );

and here's what the Three.js creators have for the same code in their example: var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );

You seemed to have left out the " * 2 - 1 " part for the X value of THREE.Vector3.

See if this returns the right coordinates first, then if it is still not working, I will look again to spot any other issues.

Hope this does the trick! Erich

mxgross commented 11 years ago

Hm Problem still exists, I tried several changes with the clientX and clientY mouse positions but i dont get closer to the clicked point.

But I found out: the nearer I zoomed into the floor, the closer the clickpoint is in at the coordinates i want.

erichlof commented 11 years ago

Hi @mexx91 ,

I'm happy to report that I have located the problem! It all has to do with renderer.setSize() On line 54 of your basic.js file, you have: renderer.setSize(960, 540); Change it to this instead: renderer.setSize(window.innerWidth, window.innerHeight);

On my computer, all new Windmill models are now placed exactly where I double-click. Yey!

There is a small remaining issue that your black text on white background that was on the right-hand side of your webpage is now gone. It's still there, but the renderer is now taking up the whole window's dimensions.

You should have the following routine somewhere in your index.js file to handle the user resizing their browser's window, which directly affects your Three.js camera:

window.addEventListener('resize', onWindowResize, false);

function onWindowResize(){ camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight );
}

You can also use this to make a custom size for your render output (if you still want your text/white background to appear on the right side). Then you would type something like camera.aspect = (window.innerWidth - myTextAreaWidth) / (window.innerHeight - myTextAreaHeight ); camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth - myTextAreaWidth, window.innerHeight - myTextAreaHeight );

You may want to consider just having the original code that I put above, that uses the whole window's dimensions. This is a lot easier to think about. Then just overlay your black text on the right-hand side of your webpage with some 'div' elements inside your index.html file. It will draw the text right over the graphics which is kind of cool.

Hope this all works now! Sorry @stemkoski if we kind of cluttered up your issue tracker. But this is possibly related to learning how to use Three.js . I sure learned a lot from debugging mexx91's code! :-)

-Erich

mxgross commented 11 years ago

Thank you so much Erich! :) Yes I will stay with the "renderer.setSize(window.innerWidth, window.innerHeight);" and place the menus into the canvas. like e.g. in anno online.