void OBBRayPicking::screenPosToWorldRay( int mouseX, int mouseY, // Mouse position, in pixels, from bottom-left corner of the window int screenWidth, int screenHeight, // Window size, in pixels const glm::mat4 &ViewMatrix, // Camera position and orientation const glm::mat4 &ProjectionMatrix, // Camera parameters (ratio, field of view, near and far planes) glm::vec3 &out_origin, // Ouput : Origin of the ray. /!\ Starts at the near plane, so if you want the ray to start at the camera's position instead, ignore this. glm::vec3 &out_direction // Ouput : Direction, in world space, of the ray that goes "through" the mouse. ) { // The ray Start and End positions, in Normalized Device Coordinates glm::vec4 lRayStart_NDC( ((float)mouseX / (float)screenWidth - 0.5f) * 2.0f, // [0,1024] -> [-1,1] ((float)mouseY / (float)screenHeight - 0.5f) * 2.0f, // [0, 768] -> [-1,1] -1.0, // The near plane maps to Z=-1 in Normalized Device Coordinates 1.0f ); glm::vec4 lRayEnd_NDC( ((float)mouseX / (float)screenWidth - 0.5f) * 2.0f, ((float)mouseY / (float)screenHeight - 0.5f) * 2.0f, 0.0, 1.0f ); // The Projection matrix goes from Camera Space to NDC. // So inverse(ProjectionMatrix) goes from NDC to Camera Space. glm::mat4 InverseProjectionMatrix = glm::inverse(ProjectionMatrix); // The View Matrix goes from World Space to Camera Space. // So inverse(ViewMatrix) goes from Camera Space to World Space. glm::mat4 InverseViewMatrix = glm::inverse(ViewMatrix); glm::vec4 lRayStart_camera = InverseProjectionMatrix * lRayStart_NDC; lRayStart_camera /= lRayStart_camera.w; glm::vec4 lRayStart_world = InverseViewMatrix * lRayStart_camera; lRayStart_world /= lRayStart_world.w; glm::vec4 lRayEnd_camera = InverseProjectionMatrix * lRayEnd_NDC; lRayEnd_camera /= lRayEnd_camera.w; glm::vec4 lRayEnd_world = InverseViewMatrix * lRayEnd_camera; lRayEnd_world /= lRayEnd_world.w; // Faster way (just one inverse) //glm::mat4 M = glm::inverse(ProjectionMatrix * ViewMatrix); //glm::vec4 lRayStart_world = M * lRayStart_NDC; lRayStart_world/=lRayStart_world.w; //glm::vec4 lRayEnd_world = M * lRayEnd_NDC ; lRayEnd_world /=lRayEnd_world.w; glm::vec3 lRayDir_world(lRayEnd_world - lRayStart_world); lRayDir_world = glm::normalize(lRayDir_world); out_origin = glm::vec3(lRayStart_world); out_direction = glm::normalize(lRayDir_world); }
void screenPosToWorldRay( int mouseX, int mouseY, int screenWidth, int screenHeight, const glm::mat4 &viewMatrix, const glm::mat4 &projectionMatrix, glm::vec3& out_origin, glm::vec3& out_direction) { glm::vec4 lRayStart_NDC( ((float)mouseX/(float)screenWidth - 0.5f) * 2.0f, ((float)mouseY/(float)screenHeight - 0.5f) * 2.0f, -1.0, 1.0f ); glm::vec4 lRayEnd_NDC( ((float)mouseX/(float)screenWidth - 0.5f) * 2.0f, ((float)mouseY/(float)screenHeight - 0.5f) * 2.0f, 0.0, 1.0f ); glm::mat4 InverseProjectionMatrix = glm::inverse(projectionMatrix); glm::mat4 InverseViewMatrix = glm::inverse(viewMatrix); glm::vec4 lRayStart_camera = InverseProjectionMatrix * lRayStart_NDC; lRayStart_camera/=lRayStart_camera.w; glm::vec4 lRayStart_world = InverseViewMatrix * lRayStart_camera; lRayStart_world /=lRayStart_world.w; glm::vec4 lRayEnd_camera = InverseProjectionMatrix * lRayEnd_NDC; lRayEnd_camera /=lRayEnd_camera.w; glm::vec4 lRayEnd_world = InverseViewMatrix * lRayEnd_camera; lRayEnd_world /=lRayEnd_world.w; glm::vec3 lRayDir_world(lRayEnd_world - lRayStart_world); lRayDir_world = glm::normalize(lRayDir_world); out_origin = glm::vec3(lRayStart_world); out_direction = glm::normalize(lRayDir_world); }