Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raycaster.setFromCamera: Position the ray origin at near plane rather than camera origin #28026

Open
gkjohnson opened this issue Mar 29, 2024 · 10 comments · May be fixed by #28027
Open

Raycaster.setFromCamera: Position the ray origin at near plane rather than camera origin #28026

gkjohnson opened this issue Mar 29, 2024 · 10 comments · May be fixed by #28027
Milestone

Comments

@gkjohnson
Copy link
Collaborator

Description

Currently when calling Raycaster.setFromCamera( mouse, camera ) the origin is currently set at the camera origin (perspective camera) or plane (orthographic camera) resulting in raycasts hitting objects that are being clipped by the camera plane (or not hitting object behind the camera if an ortho camera has a negative near clip value). Is there a reason for this?

When users set the raycaster from camera and mouse settings they are expecting to interact with objects that are rendered on the screen.

Solution

Place the raycaster origin on the camera near clip plane instead of the camera plane / origin.

See the following example showing that the box displays as intersected (red) even when hovering over the center of the object that is clipped by the camera. You can uncomment line 43 to see the suggested change:

https://jsfiddle.net/bjrog3Lw/1/

Alternatives

  • User must manually set the ray origin after calling setFromCamera.
  • Provide a setting to toggle the expected behavior.

Additional context

No response

@mrdoob
Copy link
Owner

mrdoob commented Mar 29, 2024

This change makes sense to me 👌

@Sean-Bradley
Copy link
Contributor

Sean-Bradley commented Mar 30, 2024

Raycaster has its own near/far, according to the docs
https://threejs.org/docs/#api/en/core/Raycaster

Edited jsfiddle : https://jsfiddle.net/seanwasere/ourt4hev/

raycaster.near = camera.near
raycaster.far = camera.far
raycaster.setFromCamera( pointer, camera );

@WestLangley
Copy link
Collaborator

or not hitting object behind the camera if an ortho camera has a negative near clip value

A negative near clip plane is invalid according to the docs. That was a decision we made years ago. If you want to change that policy, some testing would be required to evaluate the consequences.

@WestLangley
Copy link
Collaborator

The original intent was for the Raycaster to return the 'distance' from the camera to the intersection point.

@gkjohnson
Copy link
Collaborator Author

Raycaster has its own near/far, according to the docs
https://threejs.org/docs/#api/en/core/Raycaster

I'm aware but this will not work as simply for a perspective camera since the raycaster near / far values specify a distance along the ray rather than distance along forward z (as the camera values do).

A negative near clip plane is invalid according to the docs. That was a decision we made years ago. If you want to change that policy, some testing would be required to evaluate the consequences.

I didn't realize this but either way there are still benefits for a camera with a camera.near > 0. Prohibiting a negative near clip for an orthographic camera doesn't make a lot of sense to me, though. Is there an issue where I can read up on the reasoning for this?

The original intent was for the Raycaster to return the 'distance' from the camera to the intersection point.

As with the raycaster near / far values this is not enough to filter the hits that are within the camera frustum.

The goal here is to provide a more the user with more useful and expected functionality. Again, when users are setting the raycaster based on mouse position and camera they are likely performing selection based on what's rendered on the screen. Perhaps they exist but I'm not aware of other use cases for the function.

@Sean-Bradley
Copy link
Contributor

Sean-Bradley commented Mar 31, 2024

I still struggle to understand the problem.

I fixed @gkjohnson fiddle https://jsfiddle.net/bjrog3Lw/1/
just by matching the near planes.

raycaster.near = camera.near
raycaster.setFromCamera( pointer, camera );

If the raycaster origin is moved foward to the camera near plane, picking objects around the edges of the canvas becomes inaccurate.

E.g., the origin in the example below, is offset the same as the cameras near. See Line 79

https://sbedit.net/95ccc3b52c64a14c7dce37b664b7afa3c6484590

The raycaster only appears accurate on the mesh at the center.

I feel like this fixes a problem that doesn't exist.

One day, the question will be asked,

Q. Why isn't the raycaster accurate around the edges of the canvas?

A. Reduce your cameras near plane. ✅


Side note.

I like the idea of negative near plane in the case of the orthographic camera.

E.g, When using a directional light, i find it easier to imagine it as a vector of where the light is coming from.
The problem when adding a shadow to the light, it is by default postioned at the light position. In this case negative near plane allows me to move the shadow frustum back a bit to encapsulate.

https://sbedit.net/1b4939ba8334ccc897c1b016161439492e850e17 (line 112)
image


Another thought,
picking to invisible objects, such as a hit box, is useful.
https://sbedit.net/5b0b6ecb0096dd4630b6b6c2508c8a7172580aaa

@gkjohnson
Copy link
Collaborator Author

gkjohnson commented Mar 31, 2024

I fixed @gkjohnson fiddle https://jsfiddle.net/bjrog3Lw/1/

raycaster.near = camera.near
raycaster.setFromCamera( pointer, camera );

...
The raycaster only appears accurate on the mesh at the center.

I feel like this fixes a problem that doesn't exist.

You haven't "fixed" anything if it doesn't work. It's only accurate at the center because, as I mentioned in #28026 (comment), using raycaster.near as you've proposed this isn't a valid solution. If you uncomment line 43 as recommended in the first post you'll see that the raycast is correct is across the whole canvas.

@sciecode
Copy link
Collaborator

sciecode commented Mar 31, 2024

As gkjohnson mentioned, the issue lies in the way the perspective camera clip plane works in comparison to the raycaster. We clip objects if they are not inside the perspective view frustum (near/far frustum are depth). But raycaster considers distance from origin, which has the effect of "rounding" near/far "planes" of the frustum.

We can solve this, by changing raycaster.near & raycaster.far to the distance to respective planes for that specific ray direction (for ortho, it's always the same, for pespective it is not). We then use the adjusted distance to clip points inside the corrected frustum.

@Sean-Bradley
Copy link
Contributor

Sean-Bradley commented Mar 31, 2024

Sorry, I missed the unproject bit.

It works really well. Much better than my idea.

E.g., of using your unproject with meshes around the edge of the canvas.

https://sbedit.net/8813590dcca0c209a36a2e1a90b438c870c31f30 (line77)

versus using raycaster.near = camera.near

https://sbedit.net/fb69be230d739f7becfee81aae3b9aa1db288f39

However the distance is wrong by 1, but i'm sure it will be ok in the end.

@RemusMar
Copy link
Contributor

RemusMar commented Apr 1, 2024

@WestLangley
The original intent was for the Raycaster to return the 'distance' from the camera to the intersection point.

Positioning the ray origin at near plane does not affect the distance (as long as you know the near clip value.

@gkjohnson
I'm not aware of other use cases for the function.

The hitting distance is very useful in many scenarios.
Think about the situation when you need to know if a specific target is out of range or not.

@mrdoob mrdoob modified the milestones: r164, r165 Apr 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants