From 251917ab1f574de2e51b981f367e12edbe8b7833 Mon Sep 17 00:00:00 2001 From: John Ludlow Date: Tue, 8 Jul 2025 21:57:16 +0100 Subject: [PATCH 1/3] Mesh picking example --- .../Program.cs | 237 ++++++++++++++++++ ...s.Community.Core.Models.MeshPicking.csproj | 20 ++ .../Program.cs | 188 +++++++++++--- RaylibCsExamples.slnx | 1 + 4 files changed, 415 insertions(+), 31 deletions(-) create mode 100644 Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/Program.cs create mode 100644 Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/RaylibCsExamples.Community.Core.Models.MeshPicking.csproj diff --git a/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/Program.cs b/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/Program.cs new file mode 100644 index 0000000..fdfbccb --- /dev/null +++ b/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/Program.cs @@ -0,0 +1,237 @@ +using System.Numerics; +using Raylib_cs; + +namespace RaylibCsExamples.Community.Models.AnimationDemo; + +public class MeshPicking +{ + public unsafe static int Main() + { + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800*2; + const int screenHeight = 450*2; + + Raylib.InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh picking"); + + // Define the camera to look into our 3d world + var camera = new Camera3D + { + Position = new Vector3(20.0f, 20.0f, 20.0f), + Target = new Vector3(0.0f, 8.0f, 0.0f), + Up = new Vector3(0.0f, 1.6f, 0.0f), + FovY = 45.0f, + Projection = CameraProjection.Perspective + }; + + // Picking ray + Ray ray = new(); + + var tower = Raylib.LoadModel("Resources/Models/turret.obj"); + var texture = Raylib.LoadTexture("Resources/Models/turret_diffuse.png"); + Raylib.SetMaterialTexture(ref tower, 0, MaterialMapIndex.Albedo, ref texture); + + Vector3 towerPos = new(5.0f, 0.0f, 5.0f); + var towerBBox = Raylib.GetMeshBoundingBox(tower.Meshes[0]); + + // Ground quad + Vector3 g0 = new(-50.0f, 0.0f, -50.0f); + Vector3 g1 = new(-50.0f, 0.0f, 50.0f); + Vector3 g2 = new(50.0f, 0.0f, 50.0f); + Vector3 g3 = new(50.0f, 0.0f, -50.0f); + + // Test triangle + Vector3 ta = new(-25.0f, 0.5f, 0.0f); + Vector3 tb = new(-4.0f, 2.5f, 1.0f); + Vector3 tc = new(-8.0f, 6.5f, 0.0f); + + Vector3 bary = new(0.0f, 0.0f, 0.0f); + + // Test sphere + Vector3 sp = new(-30.0f, 5.0f, 5.0f); + var sr = 4.0f; + + Raylib.SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + //---------------------------------------------------------------------------------- + // Main game loop + //-------------------------------------------------------------------------------------- + while (!Raylib.WindowShouldClose()) + { + //---------------------------------------------------------------------------------- + // Update + //---------------------------------------------------------------------------------- + if (Raylib.IsCursorHidden()) + { + Raylib.UpdateCamera(ref camera, CameraMode.FirstPerson); + } + + // Toggle camera controls + if (Raylib.IsMouseButtonPressed(MouseButton.Right)) + { + if (Raylib.IsCursorHidden()) + { + Raylib.EnableCursor(); + } + else + { + Raylib.DisableCursor(); + } + } + + // Display information about closest hit + RayCollision collision = new(); + var hitObjectName = "None"; + collision.Distance = float.MaxValue; + collision.Hit = false; + var cursorColor = Color.White; + + // Get ray and test against objects + ray = Raylib.GetScreenToWorldRay(Raylib.GetMousePosition(), camera); + + // Check ray collision aginst ground quad + var groundHitInfo = Raylib.GetRayCollisionQuad(ray, g0, g1, g2, g3); + if (groundHitInfo.Hit && (groundHitInfo.Distance < collision.Distance)) + { + collision = groundHitInfo; + cursorColor = Color.Green; + hitObjectName = "Ground"; + } + + // Check ray collision against test triangle + var triHitInfo = Raylib.GetRayCollisionTriangle(ray, ta, tb, tc); + if (triHitInfo.Hit && (triHitInfo.Distance < collision.Distance)) + { + collision = triHitInfo; + cursorColor = Color.Purple; + hitObjectName = "Triangle"; + + bary = Raymath.Vector3Barycenter(collision.Point, ta, tb, tc); + } + + // Check ray collision against test sphere + var sphereHitInfo = Raylib.GetRayCollisionSphere(ray, sp, sr); + if ((sphereHitInfo.Hit) && (sphereHitInfo.Distance < collision.Distance)) + { + collision = sphereHitInfo; + cursorColor = Color.Orange; + hitObjectName = "Sphere"; + } + + // Check ray collision against bounding box first, before trying the full ray-mesh test + var boxHitInfo = Raylib.GetRayCollisionBox(ray, towerBBox); + if (boxHitInfo.Hit && boxHitInfo.Distance < collision.Distance) + { + collision = boxHitInfo; + cursorColor = Color.Orange; + hitObjectName = "Box"; + + // Check ray collision against model meshes + RayCollision meshHitInfo = new(); + for (var m = 0; m < tower.MeshCount; m++) + { + // NOTE: We consider the model.Transform for the collision check but + // it can be checked against any transform matrix, used when checking against same + // model drawn multiple times with multiple transforms + meshHitInfo = Raylib.GetRayCollisionMesh(ray, tower.Meshes[m], tower.Transform); + if (meshHitInfo.Hit) + { + // Save the closest hit mesh + if ((!collision.Hit) || (collision.Distance > meshHitInfo.Distance)) + { + collision = meshHitInfo; + } + break; + } + } + + if (meshHitInfo.Hit) + { + collision = meshHitInfo; + cursorColor = Color.Orange; + hitObjectName = "Mesh"; + } + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + Raylib.BeginDrawing(); + Raylib.ClearBackground(Color.RayWhite); + + Raylib.BeginMode3D(camera); + + // Draw the tower + Raylib.DrawModel(tower, towerPos, 1.0f, Color.White); + + // Draw the test triangle + Raylib.DrawLine3D(ta, tb, Color.Purple); + Raylib.DrawLine3D(tb, tc, Color.Purple); + Raylib.DrawLine3D(tc, ta, Color.Purple); + + // Draw the test sphere + Raylib.DrawSphereWires(sp, sr, 8, 8, Color.Purple); + + // Draw the mesh bbox if we hit it + if (boxHitInfo.Hit) + { + Raylib.DrawBoundingBox(towerBBox, Color.Lime); + } + + // If we hit something, draw the cursor at the hit point + if (collision.Hit) + { + Raylib.DrawCube(collision.Point, 0.3f, 0.3f, 0.3f, cursorColor); + Raylib.DrawCubeWires(collision.Point, 0.3f, 0.3f, 0.3f, Color.Red); + + var normalEnd = collision.Point + collision.Normal; + Raylib.DrawLine3D(collision.Point, normalEnd, Color.Red); + } + + Raylib.DrawRay(ray, Color.Maroon); + + Raylib.DrawGrid(10, 10.0f); + + Raylib.EndMode3D(); + + // Draw some debug GUI text + Raylib.DrawText($"Hit Object: {hitObjectName}", 10, 50, 10, Color.Black); + + if (collision.Hit) + { + var ypos = 70; + + Raylib.DrawText($"Distance: {collision.Distance}", 10, ypos, 10, Color.Black); + + Raylib.DrawText($"Hit Pos: {collision.Point}", 10, ypos + 15, 10, Color.Black); + + Raylib.DrawText($"Hit Norm: {collision.Normal}", 10, ypos + 30, 10, Color.Black); + + if (triHitInfo.Hit) + { + Raylib.DrawText($"Barycenter: {bary}", 10, ypos + 45, 10, Color.Black); + } + } + + Raylib.DrawText("Right click mouse to toggle camera controls", 10, 430, 10, Color.Gray); + + Raylib.DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray); + + Raylib.DrawFPS(10, 10); + + Raylib.EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + Raylib.UnloadModel(tower); + Raylib.UnloadTexture(texture); + + Raylib.CloseWindow(); + //-------------------------------------------------------------------------------------- + + return 0; + } +} diff --git a/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/RaylibCsExamples.Community.Core.Models.MeshPicking.csproj b/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/RaylibCsExamples.Community.Core.Models.MeshPicking.csproj new file mode 100644 index 0000000..72d6be0 --- /dev/null +++ b/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/RaylibCsExamples.Community.Core.Models.MeshPicking.csproj @@ -0,0 +1,20 @@ + + + + Exe + net9.0 + enable + enable + true + + + + + Always + + + + Always + + + diff --git a/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs b/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs index a5fbe0d..df58532 100644 --- a/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs +++ b/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs @@ -9,12 +9,105 @@ private static void Main(string[] args) const int screenWidth = 800 * 2; const int screenHeight = 450 * 2; - - Raylib.SetConfigFlags(ConfigFlags.Msaa4xHint); Raylib.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting"); Raylib.SetTargetFPS(30); - + var cameraPositions = new Vector2[] { + new (0 , 0 ), + new (screenWidth , 0 ), + new (0 , screenHeight), + new (screenWidth , screenHeight), + + new (screenWidth * .1f , screenHeight * .1f ), + new (screenWidth * .1f , screenHeight * .2f ), + new (screenWidth * .1f , screenHeight * .3f ), + new (screenWidth * .1f , screenHeight * .4f ), + new (screenWidth * .1f , screenHeight * .5f ), + new (screenWidth * .1f , screenHeight * .6f ), + new (screenWidth * .1f , screenHeight * .7f ), + new (screenWidth * .1f , screenHeight * .8f ), + new (screenWidth * .1f , screenHeight * .9f ), + + new (screenWidth * .2f , screenHeight * .1f ), + new (screenWidth * .2f , screenHeight * .2f ), + new (screenWidth * .2f , screenHeight * .3f ), + new (screenWidth * .2f , screenHeight * .4f ), + new (screenWidth * .2f , screenHeight * .5f ), + new (screenWidth * .2f , screenHeight * .6f ), + new (screenWidth * .2f , screenHeight * .7f ), + new (screenWidth * .2f , screenHeight * .8f ), + new (screenWidth * .2f , screenHeight * .9f ), + + new (screenWidth * .3f , screenHeight * .1f ), + new (screenWidth * .3f , screenHeight * .2f ), + new (screenWidth * .3f , screenHeight * .3f ), + new (screenWidth * .3f , screenHeight * .4f ), + new (screenWidth * .3f , screenHeight * .5f ), + new (screenWidth * .3f , screenHeight * .6f ), + new (screenWidth * .3f , screenHeight * .7f ), + new (screenWidth * .3f , screenHeight * .8f ), + new (screenWidth * .3f , screenHeight * .9f ), + + new (screenWidth * .4f , screenHeight * .1f ), + new (screenWidth * .4f , screenHeight * .2f ), + new (screenWidth * .4f , screenHeight * .3f ), + new (screenWidth * .4f , screenHeight * .4f ), + new (screenWidth * .4f , screenHeight * .5f ), + new (screenWidth * .4f , screenHeight * .6f ), + new (screenWidth * .4f , screenHeight * .7f ), + new (screenWidth * .4f , screenHeight * .8f ), + new (screenWidth * .4f , screenHeight * .9f ), + + new (screenWidth * .5f , screenHeight * .1f ), + new (screenWidth * .5f , screenHeight * .2f ), + new (screenWidth * .5f , screenHeight * .3f ), + new (screenWidth * .5f , screenHeight * .4f ), + new (screenWidth * .5f , screenHeight * .5f ), + new (screenWidth * .5f , screenHeight * .6f ), + new (screenWidth * .5f , screenHeight * .7f ), + new (screenWidth * .5f , screenHeight * .8f ), + new (screenWidth * .5f , screenHeight * .9f ), + + new (screenWidth * .6f , screenHeight * .1f ), + new (screenWidth * .6f , screenHeight * .2f ), + new (screenWidth * .6f , screenHeight * .3f ), + new (screenWidth * .6f , screenHeight * .4f ), + new (screenWidth * .6f , screenHeight * .5f ), + new (screenWidth * .6f , screenHeight * .6f ), + new (screenWidth * .6f , screenHeight * .7f ), + new (screenWidth * .6f , screenHeight * .8f ), + new (screenWidth * .6f , screenHeight * .9f ), + + new (screenWidth * .7f , screenHeight * .1f ), + new (screenWidth * .7f , screenHeight * .2f ), + new (screenWidth * .7f , screenHeight * .3f ), + new (screenWidth * .7f , screenHeight * .4f ), + new (screenWidth * .7f , screenHeight * .5f ), + new (screenWidth * .7f , screenHeight * .6f ), + new (screenWidth * .7f , screenHeight * .7f ), + new (screenWidth * .7f , screenHeight * .8f ), + new (screenWidth * .7f , screenHeight * .9f ), + + new (screenWidth * .8f , screenHeight * .1f ), + new (screenWidth * .8f , screenHeight * .2f ), + new (screenWidth * .8f , screenHeight * .3f ), + new (screenWidth * .8f , screenHeight * .4f ), + new (screenWidth * .8f , screenHeight * .5f ), + new (screenWidth * .8f , screenHeight * .6f ), + new (screenWidth * .8f , screenHeight * .7f ), + new (screenWidth * .8f , screenHeight * .8f ), + new (screenWidth * .8f , screenHeight * .9f ), + + new (screenWidth * .9f , screenHeight * .1f ), + new (screenWidth * .9f , screenHeight * .2f ), + new (screenWidth * .9f , screenHeight * .3f ), + new (screenWidth * .9f , screenHeight * .4f ), + new (screenWidth * .9f , screenHeight * .5f ), + new (screenWidth * .9f , screenHeight * .6f ), + new (screenWidth * .9f , screenHeight * .7f ), + new (screenWidth * .9f , screenHeight * .8f ), + new (screenWidth * .9f , screenHeight * .9f ), + }; var camera = new Camera3D() { @@ -29,25 +122,15 @@ private static void Main(string[] args) var greenCubeModel = Raylib.LoadModelFromMesh(Raylib.GenMeshCube(3, 3, 3)); var greenCubePosition = new Vector3(-5, 2, 0); - var greenCubeSize = new Vector3(3, 3, 3); - var greenCubeBoundingBox = new BoundingBox( - greenCubePosition - greenCubeSize / 2, - greenCubePosition + greenCubeSize / 2 - ); var blueCubeModel = Raylib.LoadModelFromMesh(Raylib.GenMeshCube(3, 3, 3)); var blueCubePosition = new Vector3(5, 2, 0); - var blueCubeSize = new Vector3(3, 3, 3); - var blueCubeBoundingBox = new BoundingBox( - blueCubePosition - blueCubeSize / 2, - blueCubePosition + blueCubeSize / 2 - ); + blueCubeModel.Transform.Translation = blueCubePosition; + + Raylib.SetMousePosition(screenWidth / 2, screenHeight / 2); while (!Raylib.WindowShouldClose()) { - var greenCubeVisible = true; - var blueCubeVisible = true; - Raylib.UpdateCamera(ref camera, CameraMode.Orbital); Raylib.BeginDrawing(); { @@ -58,41 +141,47 @@ private static void Main(string[] args) Raylib.DrawModelWires(planeModel, Vector3.Zero, 1, Color.LightGray); Raylib.DrawModel(greenCubeModel, greenCubePosition, 1, Color.Green); - Raylib.DrawModelWires(greenCubeModel, greenCubePosition, 1, Color.Green); + Raylib.DrawModelWires(greenCubeModel, greenCubePosition, 1, Color.Black); Raylib.DrawModel(blueCubeModel, blueCubePosition, 1, Color.Blue); - Raylib.DrawModelWires(blueCubeModel, blueCubePosition, 1, Color.Blue); - - greenCubeVisible = IsModelVisible(camera, screenWidth, screenHeight, greenCubeModel); - blueCubeVisible = IsModelVisible(camera, screenWidth, screenHeight, blueCubeModel); + Raylib.DrawModelWires(blueCubeModel, blueCubePosition, 1, Color.Black); } Raylib.EndMode3D(); - - if (greenCubeVisible) + if (IsBoundingBoxVisible(camera, cameraPositions, [greenCubeModel, blueCubeModel], greenCubeModel, "green cube")) { Raylib.DrawText("Green cube is visible", 10, 30, 30, Color.Green); Raylib.TraceLog(TraceLogLevel.All, "Green cube is visible"); - Debug.Write("Green cube is visible"); } else { Raylib.DrawText("Green cube is NOT visible", 10, 30, 30, Color.DarkGreen); Raylib.TraceLog(TraceLogLevel.All, "Green cube is NOT visible"); - Debug.Write("Green cube is NOT visible"); } - if (blueCubeVisible) + if (IsBoundingBoxHovered(camera, greenCubeModel)) + { + Raylib.DrawText("Green cube is hovered", 10, 60, 30, Color.DarkGreen); + Raylib.TraceLog(TraceLogLevel.All, "Green cube is hovered"); + } + + if (IsBoundingBoxVisible(camera, cameraPositions, [greenCubeModel, blueCubeModel], blueCubeModel, "blue cube")) { - Raylib.DrawText("Blue cube is visible", 10, 90, 30, Color.Blue); + Raylib.DrawText("Blue cube is visible", 10, 120, 30, Color.Blue); Raylib.TraceLog(TraceLogLevel.All, "Blue cube is visible"); } else { - Raylib.DrawText("Blue cube is NOT visible", 10, 90, 30, Color.DarkBlue); + Raylib.DrawText("Blue cube is NOT visible", 10, 120, 30, Color.DarkBlue); Raylib.TraceLog(TraceLogLevel.All, "Blue cube is NOT visible"); } + if (IsBoundingBoxHovered(camera, blueCubeModel)) + { + Raylib.DrawText("Blue cube is hovered", 10, 150, 30, Color.DarkBlue); + Raylib.TraceLog(TraceLogLevel.All, "Blue cube is hovered"); + } + Raylib.DrawFPS(10, 1); } Raylib.EndDrawing(); @@ -105,12 +194,49 @@ private static void Main(string[] args) Raylib.CloseWindow(); } - private static bool IsModelVisible(Camera3D camera, int screenWidth, int screenHeight, Model model) + private static bool IsBoundingBoxVisible(Camera3D camera, Vector2[] cameraPositions, Model[] allModels, Model targetModel, string id) + { + foreach (var cameraPosition in cameraPositions) + { + var ray = Raylib.GetScreenToWorldRay(cameraPosition, camera); + var closestModel = default(Model); + var closestCollision = (RayCollision?)null; + + foreach (var model in allModels) + { + var boundingBox = Raylib.GetModelBoundingBox(model); + var collision = Raylib.GetRayCollisionBox(ray, Raylib.GetModelBoundingBox(model)); + + if (collision.Hit && (collision.Distance < closestCollision?.Distance || closestCollision is null)) + { + Raylib.DrawBoundingBox(boundingBox, Color.Purple); + closestCollision = collision; + closestModel = model; + } + } + + if (closestCollision is not null && closestModel.Equals(targetModel)) + { + Raylib.TraceLog(TraceLogLevel.All, $"{id} is visible at position {ray.Position} ({closestCollision})"); + return true; + } + else + { + Raylib.DrawText("X", (int)cameraPosition.X, (int)cameraPosition.Y, 10, Color.Red); + } + } + + return false; + } + + private static bool IsBoundingBoxHovered(Camera3D camera, Model model) { - var ray = Raylib.GetScreenToWorldRay(new Vector2 (screenWidth / 2, screenHeight / 2), camera); - var rayCollision = Raylib.GetRayCollisionMesh(ray, model.Meshes[0], model.Transform); + var ray = Raylib.GetScreenToWorldRay(Raylib.GetMousePosition(), camera); + var boundingBox = Raylib.GetModelBoundingBox(model); + var rayCollision = Raylib.GetRayCollisionBox(ray, boundingBox); if (rayCollision.Hit) { + Raylib.DrawBoundingBox(boundingBox, Color.Purple); return true; } return false; diff --git a/RaylibCsExamples.slnx b/RaylibCsExamples.slnx index 997983c..d13bae5 100644 --- a/RaylibCsExamples.slnx +++ b/RaylibCsExamples.slnx @@ -16,6 +16,7 @@ + From f2b4fc17bcc9e4cea517383c1dbe508884c4b26e Mon Sep 17 00:00:00 2001 From: John Ludlow Date: Sat, 19 Jul 2025 16:01:46 +0100 Subject: [PATCH 2/3] OcclusionTest (kinda) works! --- .../Program.cs | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs b/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs index df58532..a3ed4db 100644 --- a/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs +++ b/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs @@ -2,7 +2,7 @@ using System.Numerics; using Raylib_cs; -internal sealed unsafe class Program +internal sealed class Program { private static void Main(string[] args) { @@ -125,7 +125,6 @@ private static void Main(string[] args) var blueCubeModel = Raylib.LoadModelFromMesh(Raylib.GenMeshCube(3, 3, 3)); var blueCubePosition = new Vector3(5, 2, 0); - blueCubeModel.Transform.Translation = blueCubePosition; Raylib.SetMousePosition(screenWidth / 2, screenHeight / 2); @@ -148,7 +147,7 @@ private static void Main(string[] args) } Raylib.EndMode3D(); - if (IsBoundingBoxVisible(camera, cameraPositions, [greenCubeModel, blueCubeModel], greenCubeModel, "green cube")) + if (IsBoundingBoxVisible(camera, cameraPositions, [(greenCubeModel, greenCubePosition), (blueCubeModel, blueCubePosition)], (greenCubeModel, greenCubePosition), "green cube")) { Raylib.DrawText("Green cube is visible", 10, 30, 30, Color.Green); Raylib.TraceLog(TraceLogLevel.All, "Green cube is visible"); @@ -159,13 +158,13 @@ private static void Main(string[] args) Raylib.TraceLog(TraceLogLevel.All, "Green cube is NOT visible"); } - if (IsBoundingBoxHovered(camera, greenCubeModel)) + if (IsBoundingBoxHovered(camera, greenCubeModel, greenCubePosition)) { Raylib.DrawText("Green cube is hovered", 10, 60, 30, Color.DarkGreen); Raylib.TraceLog(TraceLogLevel.All, "Green cube is hovered"); } - if (IsBoundingBoxVisible(camera, cameraPositions, [greenCubeModel, blueCubeModel], blueCubeModel, "blue cube")) + if (IsBoundingBoxVisible(camera, cameraPositions, [(greenCubeModel, greenCubePosition), (blueCubeModel, blueCubePosition)], (blueCubeModel, blueCubePosition), "blue cube")) { Raylib.DrawText("Blue cube is visible", 10, 120, 30, Color.Blue); Raylib.TraceLog(TraceLogLevel.All, "Blue cube is visible"); @@ -176,7 +175,7 @@ private static void Main(string[] args) Raylib.TraceLog(TraceLogLevel.All, "Blue cube is NOT visible"); } - if (IsBoundingBoxHovered(camera, blueCubeModel)) + if (IsBoundingBoxHovered(camera, blueCubeModel, blueCubePosition)) { Raylib.DrawText("Blue cube is hovered", 10, 150, 30, Color.DarkBlue); Raylib.TraceLog(TraceLogLevel.All, "Blue cube is hovered"); @@ -194,7 +193,7 @@ private static void Main(string[] args) Raylib.CloseWindow(); } - private static bool IsBoundingBoxVisible(Camera3D camera, Vector2[] cameraPositions, Model[] allModels, Model targetModel, string id) + private static bool IsBoundingBoxVisible(Camera3D camera, Vector2[] cameraPositions, (Model model, Vector3 position)[] allModels, (Model model, Vector3 position) targetModel, string id) { foreach (var cameraPosition in cameraPositions) { @@ -204,20 +203,25 @@ private static bool IsBoundingBoxVisible(Camera3D camera, Vector2[] cameraPositi foreach (var model in allModels) { - var boundingBox = Raylib.GetModelBoundingBox(model); - var collision = Raylib.GetRayCollisionBox(ray, Raylib.GetModelBoundingBox(model)); + var boundingBox = Raylib.GetModelBoundingBox(model.model); + boundingBox.Min += model.position; + boundingBox.Max += model.position; + + var collision = Raylib.GetRayCollisionBox(ray, boundingBox); if (collision.Hit && (collision.Distance < closestCollision?.Distance || closestCollision is null)) { Raylib.DrawBoundingBox(boundingBox, Color.Purple); closestCollision = collision; - closestModel = model; + closestModel = model.model; } } - if (closestCollision is not null && closestModel.Equals(targetModel)) + if (closestCollision is not null && closestModel.Equals(targetModel.model)) { Raylib.TraceLog(TraceLogLevel.All, $"{id} is visible at position {ray.Position} ({closestCollision})"); + Raylib.DrawText("X", (int)cameraPosition.X, (int)cameraPosition.Y, 10, Color.DarkGreen); + return true; } else @@ -229,10 +233,13 @@ private static bool IsBoundingBoxVisible(Camera3D camera, Vector2[] cameraPositi return false; } - private static bool IsBoundingBoxHovered(Camera3D camera, Model model) + private static bool IsBoundingBoxHovered(Camera3D camera, Model model, Vector3 position) { var ray = Raylib.GetScreenToWorldRay(Raylib.GetMousePosition(), camera); var boundingBox = Raylib.GetModelBoundingBox(model); + boundingBox.Min += position; + boundingBox.Max += position; + var rayCollision = Raylib.GetRayCollisionBox(ray, boundingBox); if (rayCollision.Hit) { From 87b0004b24e492b3735b8273b136a8c13297d5c8 Mon Sep 17 00:00:00 2001 From: John Ludlow Date: Sat, 19 Jul 2025 16:19:17 +0100 Subject: [PATCH 3/3] Set Transform to make models remember their positions --- .../Program.cs | 5 ++- .../Program.cs | 37 ++++++++----------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/Program.cs b/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/Program.cs index fdfbccb..48f632d 100644 --- a/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/Program.cs +++ b/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/Program.cs @@ -31,8 +31,9 @@ public unsafe static int Main() var texture = Raylib.LoadTexture("Resources/Models/turret_diffuse.png"); Raylib.SetMaterialTexture(ref tower, 0, MaterialMapIndex.Albedo, ref texture); - Vector3 towerPos = new(5.0f, 0.0f, 5.0f); - var towerBBox = Raylib.GetMeshBoundingBox(tower.Meshes[0]); + tower.Transform = Raymath.MatrixTranslate(5.0f, 0.0f, 5.0f); + Vector3 towerPos = Vector3.Zero; + var towerBBox = Raylib.GetModelBoundingBox(tower); // Ground quad Vector3 g0 = new(-50.0f, 0.0f, -50.0f); diff --git a/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs b/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs index a3ed4db..f485d63 100644 --- a/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs +++ b/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs @@ -118,13 +118,13 @@ private static void Main(string[] args) Projection = CameraProjection.Perspective }; - var planeModel = Raylib.LoadModelFromMesh(Raylib.GenMeshPlane(20, 20, 3, 3)); + var planeModel = Raylib.LoadModelFromMesh(Raylib.GenMeshPlane(20, 20, 3, 3)); var greenCubeModel = Raylib.LoadModelFromMesh(Raylib.GenMeshCube(3, 3, 3)); - var greenCubePosition = new Vector3(-5, 2, 0); + greenCubeModel.Transform = Raymath.MatrixTranslate(-5, 2, 0); var blueCubeModel = Raylib.LoadModelFromMesh(Raylib.GenMeshCube(3, 3, 3)); - var blueCubePosition = new Vector3(5, 2, 0); + blueCubeModel.Transform = Raymath.MatrixTranslate(5, 2, 0); Raylib.SetMousePosition(screenWidth / 2, screenHeight / 2); @@ -139,15 +139,15 @@ private static void Main(string[] args) Raylib.DrawModel(planeModel, Vector3.Zero, 1, Color.Gray); Raylib.DrawModelWires(planeModel, Vector3.Zero, 1, Color.LightGray); - Raylib.DrawModel(greenCubeModel, greenCubePosition, 1, Color.Green); - Raylib.DrawModelWires(greenCubeModel, greenCubePosition, 1, Color.Black); + Raylib.DrawModel(greenCubeModel, Vector3.Zero, 1, Color.Green); + Raylib.DrawModelWires(greenCubeModel, Vector3.Zero, 1, Color.Black); - Raylib.DrawModel(blueCubeModel, blueCubePosition, 1, Color.Blue); - Raylib.DrawModelWires(blueCubeModel, blueCubePosition, 1, Color.Black); + Raylib.DrawModel(blueCubeModel, Vector3.Zero, 1, Color.Blue); + Raylib.DrawModelWires(blueCubeModel, Vector3.Zero, 1, Color.Black); } Raylib.EndMode3D(); - if (IsBoundingBoxVisible(camera, cameraPositions, [(greenCubeModel, greenCubePosition), (blueCubeModel, blueCubePosition)], (greenCubeModel, greenCubePosition), "green cube")) + if (IsBoundingBoxVisible(camera, cameraPositions, [greenCubeModel, blueCubeModel], greenCubeModel, "green cube")) { Raylib.DrawText("Green cube is visible", 10, 30, 30, Color.Green); Raylib.TraceLog(TraceLogLevel.All, "Green cube is visible"); @@ -158,13 +158,13 @@ private static void Main(string[] args) Raylib.TraceLog(TraceLogLevel.All, "Green cube is NOT visible"); } - if (IsBoundingBoxHovered(camera, greenCubeModel, greenCubePosition)) + if (IsBoundingBoxHovered(camera, greenCubeModel)) { Raylib.DrawText("Green cube is hovered", 10, 60, 30, Color.DarkGreen); Raylib.TraceLog(TraceLogLevel.All, "Green cube is hovered"); } - if (IsBoundingBoxVisible(camera, cameraPositions, [(greenCubeModel, greenCubePosition), (blueCubeModel, blueCubePosition)], (blueCubeModel, blueCubePosition), "blue cube")) + if (IsBoundingBoxVisible(camera, cameraPositions, [greenCubeModel, blueCubeModel], blueCubeModel, "blue cube")) { Raylib.DrawText("Blue cube is visible", 10, 120, 30, Color.Blue); Raylib.TraceLog(TraceLogLevel.All, "Blue cube is visible"); @@ -175,7 +175,7 @@ private static void Main(string[] args) Raylib.TraceLog(TraceLogLevel.All, "Blue cube is NOT visible"); } - if (IsBoundingBoxHovered(camera, blueCubeModel, blueCubePosition)) + if (IsBoundingBoxHovered(camera, blueCubeModel)) { Raylib.DrawText("Blue cube is hovered", 10, 150, 30, Color.DarkBlue); Raylib.TraceLog(TraceLogLevel.All, "Blue cube is hovered"); @@ -193,7 +193,7 @@ private static void Main(string[] args) Raylib.CloseWindow(); } - private static bool IsBoundingBoxVisible(Camera3D camera, Vector2[] cameraPositions, (Model model, Vector3 position)[] allModels, (Model model, Vector3 position) targetModel, string id) + private static bool IsBoundingBoxVisible(Camera3D camera, Vector2[] cameraPositions, Model [] allModels, Model targetModel, string id) { foreach (var cameraPosition in cameraPositions) { @@ -203,21 +203,18 @@ private static bool IsBoundingBoxVisible(Camera3D camera, Vector2[] cameraPositi foreach (var model in allModels) { - var boundingBox = Raylib.GetModelBoundingBox(model.model); - boundingBox.Min += model.position; - boundingBox.Max += model.position; - + var boundingBox = Raylib.GetModelBoundingBox(model); var collision = Raylib.GetRayCollisionBox(ray, boundingBox); if (collision.Hit && (collision.Distance < closestCollision?.Distance || closestCollision is null)) { Raylib.DrawBoundingBox(boundingBox, Color.Purple); closestCollision = collision; - closestModel = model.model; + closestModel = model; } } - if (closestCollision is not null && closestModel.Equals(targetModel.model)) + if (closestCollision is not null && closestModel.Equals(targetModel)) { Raylib.TraceLog(TraceLogLevel.All, $"{id} is visible at position {ray.Position} ({closestCollision})"); Raylib.DrawText("X", (int)cameraPosition.X, (int)cameraPosition.Y, 10, Color.DarkGreen); @@ -233,12 +230,10 @@ private static bool IsBoundingBoxVisible(Camera3D camera, Vector2[] cameraPositi return false; } - private static bool IsBoundingBoxHovered(Camera3D camera, Model model, Vector3 position) + private static bool IsBoundingBoxHovered(Camera3D camera, Model model) { var ray = Raylib.GetScreenToWorldRay(Raylib.GetMousePosition(), camera); var boundingBox = Raylib.GetModelBoundingBox(model); - boundingBox.Min += position; - boundingBox.Max += position; var rayCollision = Raylib.GetRayCollisionBox(ray, boundingBox); if (rayCollision.Hit)