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..48f632d
--- /dev/null
+++ b/Community/Models/RaylibCsExamples.Community.Core.Models.MeshPicking/Program.cs
@@ -0,0 +1,238 @@
+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);
+
+ 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);
+ 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..f485d63 100644
--- a/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs
+++ b/Local/Objects/RaylibCsExamples.Local.Objects.ObjectOcclusionTest/Program.cs
@@ -2,19 +2,112 @@
using System.Numerics;
using Raylib_cs;
-internal sealed unsafe class Program
+internal sealed class Program
{
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()
{
@@ -25,29 +118,18 @@ 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);
- var greenCubeSize = new Vector3(3, 3, 3);
- var greenCubeBoundingBox = new BoundingBox(
- greenCubePosition - greenCubeSize / 2,
- greenCubePosition + greenCubeSize / 2
- );
+ greenCubeModel.Transform = Raymath.MatrixTranslate(-5, 2, 0);
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 = Raymath.MatrixTranslate(5, 2, 0);
+
+ Raylib.SetMousePosition(screenWidth / 2, screenHeight / 2);
while (!Raylib.WindowShouldClose())
{
- var greenCubeVisible = true;
- var blueCubeVisible = true;
-
Raylib.UpdateCamera(ref camera, CameraMode.Orbital);
Raylib.BeginDrawing();
{
@@ -57,42 +139,48 @@ 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.Green);
+ 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.Blue);
-
- greenCubeVisible = IsModelVisible(camera, screenWidth, screenHeight, greenCubeModel);
- blueCubeVisible = IsModelVisible(camera, screenWidth, screenHeight, blueCubeModel);
+ Raylib.DrawModel(blueCubeModel, Vector3.Zero, 1, Color.Blue);
+ Raylib.DrawModelWires(blueCubeModel, Vector3.Zero, 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("Blue cube is visible", 10, 90, 30, Color.Blue);
+ 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, 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 +193,52 @@ 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)
{
- var ray = Raylib.GetScreenToWorldRay(new Vector2 (screenWidth / 2, screenHeight / 2), camera);
- var rayCollision = Raylib.GetRayCollisionMesh(ray, model.Meshes[0], model.Transform);
+ 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, boundingBox);
+
+ 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})");
+ Raylib.DrawText("X", (int)cameraPosition.X, (int)cameraPosition.Y, 10, Color.DarkGreen);
+
+ 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(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 @@
+