Merge pull request #71 from victorfisac/develop
Implemented ray trace from mouse position
This commit is contained in:
commit
21229aa3f6
4 changed files with 75 additions and 56 deletions
|
@ -24,9 +24,12 @@ int main()
|
||||||
Camera camera = {{ 0.0, 10.0, 10.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }};
|
Camera camera = {{ 0.0, 10.0, 10.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }};
|
||||||
|
|
||||||
Vector3 cubePosition = { 0.0, 1.0, 0.0 };
|
Vector3 cubePosition = { 0.0, 1.0, 0.0 };
|
||||||
|
Vector3 cubeSize = { 2.0, 2.0, 2.0 };
|
||||||
|
|
||||||
Ray ray; // Picking line ray
|
Ray ray; // Picking line ray
|
||||||
|
|
||||||
|
bool collision = false;
|
||||||
|
|
||||||
SetCameraMode(CAMERA_FREE); // Set a free camera mode
|
SetCameraMode(CAMERA_FREE); // Set a free camera mode
|
||||||
SetCameraPosition(camera.position); // Set internal camera position to match our camera position
|
SetCameraPosition(camera.position); // Set internal camera position to match our camera position
|
||||||
|
|
||||||
|
@ -45,7 +48,10 @@ int main()
|
||||||
// NOTE: This function is NOT WORKING properly!
|
// NOTE: This function is NOT WORKING properly!
|
||||||
ray = GetMouseRay(GetMousePosition(), camera);
|
ray = GetMouseRay(GetMousePosition(), camera);
|
||||||
|
|
||||||
// TODO: Check collision between ray and box
|
// Check collision between ray and box
|
||||||
|
collision = CheckCollisionRayBox(ray,
|
||||||
|
(Vector3){cubePosition.x - cubeSize.x / 2,cubePosition.y - cubeSize.y / 2,cubePosition.z - cubeSize.z / 2},
|
||||||
|
(Vector3){cubePosition.x + cubeSize.x / 2,cubePosition.y + cubeSize.y / 2,cubePosition.z + cubeSize.z / 2});
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -57,8 +63,8 @@ int main()
|
||||||
|
|
||||||
Begin3dMode(camera);
|
Begin3dMode(camera);
|
||||||
|
|
||||||
DrawCube(cubePosition, 2, 2, 2, GRAY);
|
DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, GRAY);
|
||||||
DrawCubeWires(cubePosition, 2, 2, 2, DARKGRAY);
|
DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, DARKGRAY);
|
||||||
|
|
||||||
DrawGrid(10.0, 1.0);
|
DrawGrid(10.0, 1.0);
|
||||||
|
|
||||||
|
@ -67,6 +73,8 @@ int main()
|
||||||
End3dMode();
|
End3dMode();
|
||||||
|
|
||||||
DrawText("Try selecting the box with mouse!", 240, 10, 20, GRAY);
|
DrawText("Try selecting the box with mouse!", 240, 10, 20, GRAY);
|
||||||
|
|
||||||
|
if(collision) DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, screenHeight * 0.1f, 30, GREEN);
|
||||||
|
|
||||||
DrawFPS(10, 10);
|
DrawFPS(10, 10);
|
||||||
|
|
||||||
|
|
96
src/core.c
96
src/core.c
|
@ -779,78 +779,68 @@ int StorageLoadValue(int position)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gives the ray trace from mouse 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_transform.html
|
||||||
//http://www.songho.ca/opengl/gl_matrix.html
|
//http://www.songho.ca/opengl/gl_matrix.html
|
||||||
//http://www.sjbaker.org/steve/omniv/matrices_can_be_your_friends.html
|
//http://www.sjbaker.org/steve/omniv/matrices_can_be_your_friends.html
|
||||||
//https://www.opengl.org/archives/resources/faq/technical/transformations.htm
|
//https://www.opengl.org/archives/resources/faq/technical/transformations.htm
|
||||||
Ray GetMouseRay(Vector2 mousePosition, Camera camera)
|
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;
|
Ray ray;
|
||||||
|
|
||||||
// Calculate projection matrix
|
// Calculate normalized device coordinates
|
||||||
float aspect = (float)GetScreenWidth()/(float)GetScreenHeight();
|
// NOTE: y value is negative
|
||||||
double top = 0.1f*tanf(45.0f*PI/360.0f);
|
float x = (2.0f * mousePosition.x) / GetScreenWidth() - 1.0f;
|
||||||
double right = top*aspect;
|
float y = 1.0f - (2.0f * mousePosition.y) / GetScreenHeight();
|
||||||
|
float z = 1.0f;
|
||||||
// NOTE: zNear and zFar values are important for depth
|
|
||||||
Matrix matProjection = MatrixFrustum(-right, right, -top, top, 0.01f, 1000.0f);
|
|
||||||
|
|
||||||
// Calculate view matrix (camera)
|
// Store values in a vector
|
||||||
|
Vector3 deviceCoords = {x, y, z};
|
||||||
|
|
||||||
|
// Device debug message
|
||||||
|
TraceLog(INFO, "device(%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z);
|
||||||
|
|
||||||
|
// Calculate projection matrix (from perspective instead of frustum
|
||||||
|
Matrix matProj = MatrixPerspective(45.0f, (float)((float)GetScreenWidth() / (float)GetScreenHeight()), 0.01f, 1000.0f);
|
||||||
|
|
||||||
|
// Calculate view matrix from camera look at
|
||||||
Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
|
Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
|
||||||
|
|
||||||
// Tutorial used: http://antongerdelan.net/opengl/raycasting.html
|
// 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 0: We got mouse coordinates in viewport-space [0:screenWidth, 0:screenHeight]
|
// Calculate unproject matrix (multiply projection matrix and view matrix) and invert it
|
||||||
// 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
|
Matrix matProjView = MatrixMultiply(matProj, matView);
|
||||||
|
MatrixInvert(&matProjView);
|
||||||
|
|
||||||
// Step 1: 3d Normalised Device Coordinates [-1:1, -1:1, -1:1]
|
// Calculate far and near points
|
||||||
// Transform mousePosition into 3d normalised device coordinates.
|
Quaternion near = { deviceCoords.x, deviceCoords.y, 0, 1};
|
||||||
// We have an x and y already, so we scale their range, and reverse the direction of y.
|
Quaternion far = { deviceCoords.x, deviceCoords.y, 1, 1};
|
||||||
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 };
|
|
||||||
|
|
||||||
// Step 2: 4d Homogeneous Clip Coordinates [-1:1, -1:1, -1:1, -1:1]
|
// Multiply points by unproject matrix
|
||||||
// We want our ray's z to point forwards - this is usually the negative z direction in OpenGL style.
|
QuaternionTransform(&near, matProjView);
|
||||||
// We can add a w, just so that we have a 4d vector.
|
QuaternionTransform(&far, matProjView);
|
||||||
//vec4 ray_clip = vec4 (ray_nds.xy, -1.0, 1.0);
|
|
||||||
Quaternion rayClip = { rayDevice.x, rayDevice.y , -1.0f, 1.0f };
|
|
||||||
|
|
||||||
// Step 3: 4d Eye (Camera) Coordinates [-x:x, -y:y, -z:z, -w:w]
|
// Calculate normalized world points in vectors
|
||||||
// To get into clip space from eye space we multiply the vector by a projection matrix.
|
Vector3 nearPoint = {near.x / near.w, near.y / near.w, near.z / near.w};
|
||||||
// We can go backwards by multiplying by the inverse of this matrix.
|
Vector3 farPoint = {far.x / far.w, far.y / far.w, far.z / far.w};
|
||||||
//vec4 ray_eye = MatrixInverse(matProjection) * ray_clip;
|
|
||||||
Quaternion rayEye = rayClip;
|
|
||||||
MatrixInvert(&matProjection);
|
|
||||||
QuaternionTransform(&rayEye, matProjection);
|
|
||||||
|
|
||||||
// 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".
|
// Calculate normalized direction vector
|
||||||
//ray_eye = vec4(ray_eye.xy, -1.0, 0.0);
|
Vector3 direction = VectorSubtract(farPoint, nearPoint);
|
||||||
rayEye.z = -1.0f;
|
VectorNormalize(&direction);
|
||||||
rayEye.w = 0.0f;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
|
// Apply calculated vectors to ray
|
||||||
ray.position = camera.position;
|
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;
|
return ray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
src/models.c
20
src/models.c
|
@ -1336,6 +1336,26 @@ bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSph
|
||||||
return collision;
|
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?
|
// TODO: Useful function to check collision area?
|
||||||
//BoundingBox GetCollisionArea(BoundingBox box1, BoundingBox box2)
|
//BoundingBox GetCollisionArea(BoundingBox box1, BoundingBox box2)
|
||||||
|
|
||||||
|
|
|
@ -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 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 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 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
|
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
|
// NOTE: Return the normal vector of the impacted surface
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue