# Trouble with pick rays in OpenGL ES

This topic is 2889 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm using OpenGL ES and it looks like I need to write my own pick rays. I'm taking the pick ray and trying to intersect with the xz-plane.

I'm not sure if I'm not making the pick ray correctly or doing the intersect test correctly, or both are messed up. I'd really appreciate anyone who would look at this. Please let me know if there is any more code you need to see.

Here's my algorithm idea for making the pick ray:
1. Take picked screen coordinates and convert to normalized device coordinates (-1,-1 to 1,1)?.
2. Use the frustum right and top bounds and the camera's left and up vectors (parallel to the view plane normal) to get an actual coordinate on the near plane.
3. Draw the ray from the camera's eye through this position.
4. Multiply the ray by the inverse camera transform to convert to world coordinates.

This is the test which doesn't work correctly
ray3 pickRay = camera.makePickRay(screenX, screenY); // Try to intersect with y-plane yIntersect = pickRay.intersectPlanePoint(vec3(0,1,0),0); 

For making the pick ray
ray3 S4Camera::makePickRay(int iScreenPixelX_, int iScreenPixelY_) { // n is away from the center... // u is left vector // Y-pixels are inverted; float pw = iScreenPixelX_; float ph = m_iFilmHeight - iScreenPixelY_; // Convert to NDC? // The screen dimensions are film dimensions float x = 2 * pw / m_iFilmWidth - 1.0f; float y = 2 * ph / m_iFilmHeight - 1.0f; // Convert to world coordinates vec3 pickDirection = -m_frustum.right*x*u + m_frustum.top*y*v + -m_frustum.near*n; ray3 pickRay(m_eye, pickDirection); // Multiply by inverse camera transform pickRay.multiply(m_matrix); return pickRay; } 

Here's how I'm making the camera transform:
void S4Camera::makeMatrix() { // n = viewplane normal // v = up // u = left n = m_eye - m_center; u = m_up.cross(n); v = n.cross(u); n.normalize(); u.normalize(); v.normalize(); mat4 &M = m_matrix; M[0] = u.x; M[4] = u.y; M[8] = u.z; M[12] = 0.0f; M[1] = v.x; M[5] = v.y; M[9] = v.z; M[13] = 0.0f; M[2] = n.x; M[6] = n.y; M[10] = n.z; M[14] = 0.0f; M[3] = 0.0f; M[7] = 0.0f; M[11] = 0.0f; M[15] = 1.0f; mat4 translation = mat4::translation(-m_eye); M *= translation; } 

How I'm doing ray multiplication:
 void ray3::multiply(const mat4& transform_) { origin.multiplyAsPoint(transform_); // multiplies as (x,y,z,1) direction.multiplyAsVector(transform_); // multiplies as (x,y,z,0) }

And how I'm doing plane testing:
 vec3 intersectPlanePoint(const vec3 &planeNormal_, float planeConstant_) { assert(intersectsPlane(planeNormal_, planeConstant_)); float t = (-planeConstant_ - planeNormal_.dot(origin)) / (planeNormal_.dot(direction)); return at(t); } 

##### Share on other sites
Solved the problem. I've posted the correct code for anyone else trying to make pick rays.

Multiplying by camera inverse transform takes to eye coordinates, but the pick ray needs to stay in world coordinates. Also, I mistook u for the camera's left vector, when it was the camera's right vector.
The crucial error was that I also forgot the absolute value conversion in myintersectsPlane function:

bool intersectsPlane(const vec3 &planeNormal_, float planeConstant_) { return fabs(planeNormal_.dot(direction)) >= S4_RAY_PRECISION; }

Real algorithm:
1. Take picked screen coordinates and convert to normalized device coordinates (-1,-1 to 1,1).
2. Use the frustum right and top bounds and the camera's left and up vectors (parallel to the view plane normal) to get an actual coordinate on the near plane.
3. Draw the ray from the camera's eye through this position.

For making the pick ray:
ray3 S4Camera::makePickRay(int iScreenPixelX_, int iScreenPixelY_) { // n is away from the center... // u is right vector // Y-pixels are inverted; float pw = iScreenPixelX_; float ph = m_iFilmHeight - iScreenPixelY_; float x = 2 * pw / m_iFilmWidth - 1.0f; float y = 2 * ph / m_iFilmHeight - 1.0f; vec3 pickDirection = m_frustum.right*x*u + m_frustum.top*y*v + -m_frustum.near*n; ray3 pickRay(m_eye, pickDirection); return pickRay; } 

Here's how I'm making the camera transform:
void S4Camera::makeMatrix() { // n = viewplane normal // v = up // u = right n = m_eye - m_center; u = m_up.cross(n); v = n.cross(u); n.normalize(); u.normalize(); v.normalize(); mat4 &M = m_matrix; M[0] = u.x; M[4] = u.y; M[8] = u.z; M[12] = 0.0f; M[1] = v.x; M[5] = v.y; M[9] = v.z; M[13] = 0.0f; M[2] = n.x; M[6] = n.y; M[10] = n.z; M[14] = 0.0f; M[3] = 0.0f; M[7] = 0.0f; M[11] = 0.0f; M[15] = 1.0f; mat4 translation = mat4::translation(-m_eye); M *= translation; } 

1. 1
2. 2
3. 3
Rutin
14
4. 4
5. 5

• 9
• 9
• 11
• 11
• 23
• ### Forum Statistics

• Total Topics
633674
• Total Posts
3013275
×