aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRay <raysan5@gmail.com>2016-01-07 17:04:56 +0100
committerRay <raysan5@gmail.com>2016-01-07 17:04:56 +0100
commit21229aa3f6b5a13062563fc3950cd98fe47383b8 (patch)
tree56b24a868de2522c8ea50930f562b6a28e326ce2 /src
parent7f2e67e924ae9f3f4c1172d14d25fc6212618339 (diff)
parent1793f2c3b87f1ed487216e23f3074085753ee346 (diff)
downloadraylib-21229aa3f6b5a13062563fc3950cd98fe47383b8.tar.gz
raylib-21229aa3f6b5a13062563fc3950cd98fe47383b8.zip
Merge pull request #71 from victorfisac/develop
Implemented ray trace from mouse position
Diffstat (limited to 'src')
-rw-r--r--src/core.c94
-rw-r--r--src/models.c20
-rw-r--r--src/raylib.h1
3 files changed, 63 insertions, 52 deletions
diff --git a/src/core.c b/src/core.c
index 18d2698d..708f2d22 100644
--- a/src/core.c
+++ b/src/core.c
@@ -779,78 +779,68 @@ int StorageLoadValue(int position)
}
// Gives the ray trace from mouse position
-// TODO: DOESN'T WORK! :(
//http://www.songho.ca/opengl/gl_transform.html
//http://www.songho.ca/opengl/gl_matrix.html
//http://www.sjbaker.org/steve/omniv/matrices_can_be_your_friends.html
//https://www.opengl.org/archives/resources/faq/technical/transformations.htm
Ray GetMouseRay(Vector2 mousePosition, Camera camera)
{
+ // Tutorial used: https://mkonrad.net/2014/08/07/simple-opengl-object-picking-in-3d.html
+ // Similar to http://antongerdelan.net, the problem is maybe in MatrixPerspective vs MatrixFrustum
+ // or matrix order (transpose it or not... that's the question)
+
Ray ray;
- // Calculate projection matrix
- float aspect = (float)GetScreenWidth()/(float)GetScreenHeight();
- double top = 0.1f*tanf(45.0f*PI/360.0f);
- double right = top*aspect;
-
- // NOTE: zNear and zFar values are important for depth
- Matrix matProjection = MatrixFrustum(-right, right, -top, top, 0.01f, 1000.0f);
+ // Calculate normalized device coordinates
+ // NOTE: y value is negative
+ float x = (2.0f * mousePosition.x) / GetScreenWidth() - 1.0f;
+ float y = 1.0f - (2.0f * mousePosition.y) / GetScreenHeight();
+ float z = 1.0f;
- // Calculate view matrix (camera)
- Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
+ // Store values in a vector
+ Vector3 deviceCoords = {x, y, z};
- // Tutorial used: http://antongerdelan.net/opengl/raycasting.html
+ // Device debug message
+ TraceLog(INFO, "device(%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z);
- // Step 0: We got mouse coordinates in viewport-space [0:screenWidth, 0:screenHeight]
- // NOTE: That that 0 is at the top of the screen here, so the y-axis direction is opposed to that in other coordinate systems
+ // Calculate projection matrix (from perspective instead of frustum
+ Matrix matProj = MatrixPerspective(45.0f, (float)((float)GetScreenWidth() / (float)GetScreenHeight()), 0.01f, 1000.0f);
- // Step 1: 3d Normalised Device Coordinates [-1:1, -1:1, -1:1]
- // Transform mousePosition into 3d normalised device coordinates.
- // We have an x and y already, so we scale their range, and reverse the direction of y.
- float x = (2.0f*mousePosition.x)/(float)screenWidth - 1.0f;
- float y = 1.0f - (2.0f*mousePosition.x)/(float)screenHeight;
- float z = 1.0f;
- Vector3 rayDevice = { x, y, z };
+ // Calculate view matrix from camera look at
+ Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
- // Step 2: 4d Homogeneous Clip Coordinates [-1:1, -1:1, -1:1, -1:1]
- // We want our ray's z to point forwards - this is usually the negative z direction in OpenGL style.
- // We can add a w, just so that we have a 4d vector.
- //vec4 ray_clip = vec4 (ray_nds.xy, -1.0, 1.0);
- Quaternion rayClip = { rayDevice.x, rayDevice.y , -1.0f, 1.0f };
+ // Do I need to transpose it? It seems that yes...
+ // NOTE: matrix order is maybe incorrect... In OpenGL to get world position from
+ // camera view it just needs to get inverted, but here we need to transpose it too.
+ // For example, if you get view matrix, transpose and inverted and you transform it
+ // to a vector, you will get its 3d world position coordinates (camera.position).
+ // If you don't transpose, final position will be wrong.
+ MatrixTranspose(&matView);
- // Step 3: 4d Eye (Camera) Coordinates [-x:x, -y:y, -z:z, -w:w]
- // To get into clip space from eye space we multiply the vector by a projection matrix.
- // We can go backwards by multiplying by the inverse of this matrix.
- //vec4 ray_eye = MatrixInverse(matProjection) * ray_clip;
- Quaternion rayEye = rayClip;
- MatrixInvert(&matProjection);
- QuaternionTransform(&rayEye, matProjection);
+ // Calculate unproject matrix (multiply projection matrix and view matrix) and invert it
+ Matrix matProjView = MatrixMultiply(matProj, matView);
+ MatrixInvert(&matProjView);
- // We only needed to un-project the x,y part, so let's manually set the z,w part to mean "forwards, and not a point".
- //ray_eye = vec4(ray_eye.xy, -1.0, 0.0);
- rayEye.z = -1.0f;
- rayEye.w = 0.0f;
+ // Calculate far and near points
+ Quaternion near = { deviceCoords.x, deviceCoords.y, 0, 1};
+ Quaternion far = { deviceCoords.x, deviceCoords.y, 1, 1};
- // Step 4: 4d World Coordinates [-x:x, -y:y, -z:z, -w:w]
- // Go back another step in the transformation pipeline. Remember that we manually specified a -1 for the z component,
- // which means that our ray isn't normalised. We should do this before we use it
- //Vector3 rayWorld = (MatrixInverse(matView) * ray_eye).xyz;
- MatrixInvert(&matView);
- QuaternionTransform(&rayEye, matView);
- Vector3 rayWorld = { rayEye.x, rayEye.y, rayEye.z };
-
- VectorNormalize(&rayWorld);
+ // Multiply points by unproject matrix
+ QuaternionTransform(&near, matProjView);
+ QuaternionTransform(&far, matProjView);
- // Assuming our camera is looking directly along the -Z world axis,
- // we should get [0,0,-1] when the mouse is in the centre of the screen,
- // and less significant z values when the mouse moves around the screen.
+ // Calculate normalized world points in vectors
+ Vector3 nearPoint = {near.x / near.w, near.y / near.w, near.z / near.w};
+ Vector3 farPoint = {far.x / far.w, far.y / far.w, far.z / far.w};
+ // Calculate normalized direction vector
+ Vector3 direction = VectorSubtract(farPoint, nearPoint);
+ VectorNormalize(&direction);
+
+ // Apply calculated vectors to ray
ray.position = camera.position;
- ray.direction = rayWorld;
+ ray.direction = direction;
- TraceLog(INFO, "ray.position -> (%f, %f, %f)", ray.position.x, ray.position.y, ray.position.z);
- TraceLog(INFO, "ray.direction -> (%f, %f, %f)", ray.direction.x, ray.direction.y, ray.direction.z);
-
return ray;
}
diff --git a/src/models.c b/src/models.c
index f78be41d..dd170e0b 100644
--- a/src/models.c
+++ b/src/models.c
@@ -1336,6 +1336,26 @@ bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSph
return collision;
}
+// Detect collision between ray and box
+bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox)
+{
+ bool collision = false;
+
+ float t[8];
+ t[0] = (minBBox.x - ray.position.x) / ray.direction.x;
+ t[1] = (maxBBox.x - ray.position.x) / ray.direction.x;
+ t[2] = (minBBox.y - ray.position.y) / ray.direction.y;
+ t[3] = (maxBBox.y - ray.position.y) / ray.direction.y;
+ t[4] = (minBBox.z - ray.position.z) / ray.direction.z;
+ t[5] = (maxBBox.z - ray.position.z) / ray.direction.z;
+ t[6] = fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
+ t[7] = fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
+
+ collision = !(t[7] < 0 || t[6] > t[7]);
+
+ return collision;
+}
+
// TODO: Useful function to check collision area?
//BoundingBox GetCollisionArea(BoundingBox box1, BoundingBox box2)
diff --git a/src/raylib.h b/src/raylib.h
index 72211b59..b6900a97 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -756,6 +756,7 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec
bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres
bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, Vector3 maxBBox2); // Detect collision between two boxes
bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere
+bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox); // Detect collision between ray and box
Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius); // Detect collision of player radius with cubicmap
// NOTE: Return the normal vector of the impacted surface