I’m making a sport utilizing OpenGL and want a foyer for which I’m growing with WPF, C# and OpenTK. For the foyer I want mouse selecting performance on the 3D objects and though there are a lot of many examples on the market I wish to use one particular discovered right here
Right here is my code :
public static void ScreenPosToWorldRay(
int mouseX, int mouseY, // Mouse place, in pixels, from bottom-left nook of the window
int screenWidth, int screenHeight, // Window measurement, in pixels
Matrix4 ViewMatrix, // Digicam place and orientation
Matrix4 ProjectionMatrix, // Digicam parameters (ratio, discipline of view, close to and much planes)
out Vector3 out_origin, // Ouput : Origin of the ray. /! Begins on the close to aircraft, so if you would like the ray to start out on the digital camera's place as a substitute, ignore this.
out Vector3 out_direction // Ouput : Path, in world area, of the ray that goes "by" the mouse.
)
{
// The ray Begin and Finish positions, in Normalized System Coordinates (Have you ever learn Tutorial 4 ?)
Vector4 lRayStart_NDC = new(
((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.0f, // The close to aircraft maps to Z=-1 in Normalized System Coordinates
1.0f
);
Vector4 lRayEnd_NDC = new(
((float) mouseX / (float)screenWidth - 0.5f) * 2.0f,
((float)mouseY / (float)screenHeight - 0.5f) * 2.0f,
1.0f,
1.0f
);
// Sooner means (only one inverse)
Matrix4 M = Matrix4.Invert(ProjectionMatrix * ViewMatrix);
Vector4 lRayStart_world = M * lRayStart_NDC;
lRayStart_world /= lRayStart_world.W;
Vector4 lRayEnd_world = M * lRayEnd_NDC;
lRayEnd_world /= lRayEnd_world.W;
Vector3 lRayDir_world = new(lRayEnd_world -lRayStart_world);
out_origin = new Vector3(lRayStart_world);
out_direction = Vector3.Normalize(lRayDir_world);
}
and the precise checking in opposition to the certain field occurs right here:
public static bool TestRayOBBIntersection(
Vector3 ray_origin, // Ray origin, in world area
Vector3 ray_direction, // Ray route (NOT goal place!), in world area. Should be normalize()'d.
Vector3 aabb_min, // Minimal X,Y,Z coords of the mesh when not remodeled in any respect.
Vector3 aabb_max, // Most X,Y,Z coords. Typically aabb_min*-1 in case your mesh is centered, nevertheless it's not at all times the case.
Matrix4 ModelMatrix, // Transformation utilized to the mesh (which can thus be additionally utilized to its bounding field)
out float intersection_distance // Output : distance between ray_origin and the intersection with the OBB
)
{
float tMin = 0.0f; // close to
float tMax = 100000.0f; // far
intersection_distance = tMax;
Vector3 OBBposition_worldspace = new(ModelMatrix[3,0], ModelMatrix[3,1], ModelMatrix[3,2]);
Vector3 delta = OBBposition_worldspace - ray_origin;
{
// Now, let’s compute the intersections with the two planes that delimit the OBB on the X axis
Vector3 xaxis = new(ModelMatrix[0, 0], ModelMatrix[0, 1], ModelMatrix[0, 2]);
float e = Vector3.Dot(xaxis, delta);
float f = Vector3.Dot(ray_direction, xaxis);
if (Math.Abs(f) > 0.001f)
{ // Customary case
float t1 = (e + aabb_min.X) / f; // Intersection with the "left" aircraft
float t2 = (e + aabb_max.X) / f; // Intersection with the "proper" aircraft
// t1 and t2 now include distances betwen ray origin and ray-plane intersections
// We wish t1 to signify the closest intersection,
// so if it is not the case, invert t1 and t2
if (t1 > t2)
{
(t2, t1) = (t1, t2);
}
// tMax is the closest "far" intersection (amongst the X,Y and Z planes pairs)
if (t2 < tMax)
tMax = t2;
// tMin is the farthest "close to" intersection (amongst the X,Y and Z planes pairs)
if (t1 > tMin)
tMin = t1;
// And this is the trick :
// If "far" is nearer than "close to", then there may be NO intersection.
// See the pictures within the tutorials for the visible clarification.
if (tMax < tMin)
return false;
}
else
-e + aabb_max.X < 0.0f)
return false;
}
// Take a look at intersection with the two planes perpendicular to the OBB's Y axis
// Precisely the identical factor than above.
{
Vector3 yaxis = new(ModelMatrix[1,0], ModelMatrix[1,1], ModelMatrix[1,2]);
float e = Vector3.Dot(yaxis, delta);
float f = Vector3.Dot(ray_direction, yaxis);
if (Math.Abs(f) > 0.001f)
{
float t1 = (e + aabb_min.Y) / f;
float t2 = (e + aabb_max.Y) / f;
if (t1 > t2) {
(t2, t1) = (t1, t2);
}
if (t2 < tMax)
tMax = t2;
if (t1 > tMin)
tMin = t1;
if (tMin > tMax)
return false;
}
else
}
// Take a look at intersection with the two planes perpendicular to the OBB's Z axis
// Precisely the identical factor than above.
{
Vector3 zaxis = new(ModelMatrix[2,0], ModelMatrix[2,1], ModelMatrix[2,2]);
float e = Vector3.Dot(zaxis, delta);
float f = Vector3.Dot(ray_direction, zaxis);
if (Math.Abs(f) > 0.001f)
{
float t1 = (e + aabb_min.Z) / f;
float t2 = (e + aabb_max.Z) / f;
if (t1 > t2) {
(t2, t1) = (t1, t2);
}
if (t2 < tMax)
tMax = t2;
if (t1 > tMin)
tMin = t1;
if (tMin > tMax)
return false;
}
else
}
intersection_distance = tMin;
return true;
}
right here is how I get the view and projection matrices:
inner Matrix4 GetViewMatrix(Vector3 eye, Vector3 goal, Vector3 up)
{
return Matrix4.LookAt(eye, goal, up);
}
inner Matrix4 GetProjection(float width, float peak)
{
return Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(Zoom), width / peak, Close to, Far);
}
One drawback that I’m having is that the ray origin shouldn’t be the place the digital camera is, which in flip screws every little thing up. The ray route can be unsuitable due to that and the selecting at all times succeeds, by no means fails regardless of the place I hover my mouse over. Any thought what could possibly be unsuitable?
P.S. The code below C++ and GLM works effective