Merge pull request #463 from Hultan/mesh_picking
New example models/mesh_picking
This commit is contained in:
commit
60446bce15
3 changed files with 2149 additions and 0 deletions
261
examples/models/mesh_picking/main.go
Normal file
261
examples/models/mesh_picking/main.go
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
/*******************************************************************************************
|
||||||
|
*
|
||||||
|
* raylib [models] example - Mesh picking in 3d mode, ground plane, triangle, mesh
|
||||||
|
*
|
||||||
|
* Example originally created with raylib 1.7, last time updated with raylib 4.0
|
||||||
|
*
|
||||||
|
* Example contributed by Joel Davis (@joeld42) and reviewed by Ramon Santamaria (@raysan5)
|
||||||
|
*
|
||||||
|
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||||
|
* BSD-like license that allows static linking with closed source software
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2024 Joel Davis (@joeld42) and Ramon Santamaria (@raysan5)
|
||||||
|
*
|
||||||
|
********************************************************************************************/
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
rl "github.com/gen2brain/raylib-go/raylib"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
screenWidth = 800
|
||||||
|
screenHeight = 450
|
||||||
|
)
|
||||||
|
|
||||||
|
// Program main entry point
|
||||||
|
func main() {
|
||||||
|
rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh picking")
|
||||||
|
|
||||||
|
// Define the camera to look into our 3d world
|
||||||
|
camera := rl.Camera{
|
||||||
|
Position: rl.Vector3{
|
||||||
|
X: 20.0,
|
||||||
|
Y: 20.0,
|
||||||
|
Z: 20.0,
|
||||||
|
}, // Camera position
|
||||||
|
Target: rl.Vector3{Y: 8.0}, // Camera looking at point
|
||||||
|
Up: rl.Vector3{Y: 1.6}, // Camera up vector (rotation towards target)
|
||||||
|
Fovy: 45.0, // Camera field-of-view Y
|
||||||
|
Projection: rl.CameraPerspective, // Camera projection type
|
||||||
|
}
|
||||||
|
var ray rl.Ray // Picking ray
|
||||||
|
|
||||||
|
tower := rl.LoadModel("turret.obj") // Load OBJ model
|
||||||
|
texture := rl.LoadTexture("turret_diffuse.png") // Load model texture
|
||||||
|
materials := unsafe.Slice(tower.Materials, tower.MaterialCount)
|
||||||
|
materials[0].GetMap(rl.MapDiffuse).Texture = texture // Set model diffuse texture
|
||||||
|
|
||||||
|
towerPos := rl.Vector3{} // Set model position
|
||||||
|
meshes := unsafe.Slice(tower.Meshes, tower.MeshCount)
|
||||||
|
towerBBox := rl.GetMeshBoundingBox(meshes[0]) // Get mesh bounding box
|
||||||
|
|
||||||
|
// Ground quad
|
||||||
|
g0 := rl.Vector3{
|
||||||
|
X: -50.0,
|
||||||
|
Z: -50.0,
|
||||||
|
}
|
||||||
|
g1 := rl.Vector3{
|
||||||
|
X: -50.0,
|
||||||
|
Z: 50.0,
|
||||||
|
}
|
||||||
|
g2 := rl.Vector3{
|
||||||
|
X: 50.0,
|
||||||
|
Z: 50.0,
|
||||||
|
}
|
||||||
|
g3 := rl.Vector3{
|
||||||
|
X: 50.0,
|
||||||
|
Z: -50.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test triangle
|
||||||
|
ta := rl.Vector3{
|
||||||
|
X: -25.0,
|
||||||
|
Y: 0.5,
|
||||||
|
}
|
||||||
|
tb := rl.Vector3{
|
||||||
|
X: -4.0,
|
||||||
|
Y: 2.5,
|
||||||
|
Z: 1.0,
|
||||||
|
}
|
||||||
|
tc := rl.Vector3{
|
||||||
|
X: -8.0,
|
||||||
|
Y: 6.5,
|
||||||
|
}
|
||||||
|
|
||||||
|
bary := rl.Vector3{}
|
||||||
|
|
||||||
|
// Test sphere
|
||||||
|
sp := rl.Vector3{
|
||||||
|
X: -30.0,
|
||||||
|
Y: 5.0,
|
||||||
|
Z: 5.0,
|
||||||
|
}
|
||||||
|
sr := float32(4.0)
|
||||||
|
|
||||||
|
rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second
|
||||||
|
// Main game loop
|
||||||
|
for !rl.WindowShouldClose() { // Detect window close button or ESC key
|
||||||
|
// Update
|
||||||
|
if rl.IsCursorHidden() {
|
||||||
|
rl.UpdateCamera(&camera, rl.CameraFirstPerson) // Update camera
|
||||||
|
}
|
||||||
|
// Toggle camera controls
|
||||||
|
if rl.IsMouseButtonPressed(rl.MouseButtonRight) {
|
||||||
|
if rl.IsCursorHidden() {
|
||||||
|
rl.EnableCursor()
|
||||||
|
} else {
|
||||||
|
rl.DisableCursor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display information about the closest hit
|
||||||
|
collision := rl.RayCollision{
|
||||||
|
Distance: math.MaxFloat32,
|
||||||
|
Hit: false,
|
||||||
|
}
|
||||||
|
hitObjectName := "None"
|
||||||
|
cursorColor := rl.White
|
||||||
|
|
||||||
|
// Get ray and test against objects
|
||||||
|
// See issue : https://github.com/gen2brain/raylib-go/issues/457
|
||||||
|
//ray = rl.GetScreenToWorldRay(rl.GetMousePosition(), camera)
|
||||||
|
ray = rl.GetMouseRay(rl.GetMousePosition(), camera)
|
||||||
|
|
||||||
|
// Check ray collision against ground quad
|
||||||
|
groundHitInfo := rl.GetRayCollisionQuad(ray, g0, g1, g2, g3)
|
||||||
|
|
||||||
|
if (groundHitInfo.Hit) && (groundHitInfo.Distance < collision.Distance) {
|
||||||
|
collision = groundHitInfo
|
||||||
|
cursorColor = rl.Green
|
||||||
|
hitObjectName = "Ground"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check ray collision against test triangle
|
||||||
|
triHitInfo := rl.GetRayCollisionTriangle(ray, ta, tb, tc)
|
||||||
|
|
||||||
|
if (triHitInfo.Hit) && (triHitInfo.Distance < collision.Distance) {
|
||||||
|
collision = triHitInfo
|
||||||
|
cursorColor = rl.Purple
|
||||||
|
hitObjectName = "Triangle"
|
||||||
|
|
||||||
|
bary = rl.Vector3Barycenter(collision.Point, ta, tb, tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check ray collision against test sphere
|
||||||
|
sphereHitInfo := rl.GetRayCollisionSphere(ray, sp, sr)
|
||||||
|
|
||||||
|
if (sphereHitInfo.Hit) && (sphereHitInfo.Distance < collision.Distance) {
|
||||||
|
collision = sphereHitInfo
|
||||||
|
cursorColor = rl.Orange
|
||||||
|
hitObjectName = "Sphere"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check ray collision against bounding box first, before trying the full ray-mesh test
|
||||||
|
boxHitInfo := rl.GetRayCollisionBox(ray, towerBBox)
|
||||||
|
|
||||||
|
if (boxHitInfo.Hit) && (boxHitInfo.Distance < collision.Distance) {
|
||||||
|
collision = boxHitInfo
|
||||||
|
cursorColor = rl.Orange
|
||||||
|
hitObjectName = "Box"
|
||||||
|
|
||||||
|
// Check ray collision against model meshes
|
||||||
|
meshHitInfo := rl.RayCollision{}
|
||||||
|
for m := int32(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 = rl.GetRayCollisionMesh(ray, meshes[m], tower.Transform)
|
||||||
|
if meshHitInfo.Hit {
|
||||||
|
// Save the closest hit mesh
|
||||||
|
if (!collision.Hit) || (collision.Distance > meshHitInfo.Distance) {
|
||||||
|
collision = meshHitInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
break // Stop once one mesh collision is detected, the colliding mesh is m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if meshHitInfo.Hit {
|
||||||
|
collision = meshHitInfo
|
||||||
|
cursorColor = rl.Orange
|
||||||
|
hitObjectName = "Mesh"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
rl.BeginDrawing()
|
||||||
|
rl.ClearBackground(rl.RayWhite)
|
||||||
|
rl.BeginMode3D(camera)
|
||||||
|
|
||||||
|
// Draw the tower
|
||||||
|
// WARNING: If scale is different from 1.0f,
|
||||||
|
// not considered by GetRayCollisionModel()
|
||||||
|
rl.DrawModel(tower, towerPos, 1.0, rl.White)
|
||||||
|
|
||||||
|
// Draw the test triangle
|
||||||
|
rl.DrawLine3D(ta, tb, rl.Purple)
|
||||||
|
rl.DrawLine3D(tb, tc, rl.Purple)
|
||||||
|
rl.DrawLine3D(tc, ta, rl.Purple)
|
||||||
|
|
||||||
|
// Draw the test sphere
|
||||||
|
rl.DrawSphereWires(sp, sr, 8, 8, rl.Purple)
|
||||||
|
|
||||||
|
// Draw the mesh bbox if we hit it
|
||||||
|
if boxHitInfo.Hit {
|
||||||
|
rl.DrawBoundingBox(towerBBox, rl.Lime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we hit something, draw the cursor at the hit point
|
||||||
|
if collision.Hit {
|
||||||
|
rl.DrawCube(collision.Point, 0.3, 0.3, 0.3, cursorColor)
|
||||||
|
rl.DrawCubeWires(collision.Point, 0.3, 0.3, 0.3, rl.Red)
|
||||||
|
|
||||||
|
normalEnd := rl.Vector3{}
|
||||||
|
normalEnd.X = collision.Point.X + collision.Normal.X
|
||||||
|
normalEnd.Y = collision.Point.Y + collision.Normal.Y
|
||||||
|
normalEnd.Z = collision.Point.Z + collision.Normal.Z
|
||||||
|
|
||||||
|
rl.DrawLine3D(collision.Point, normalEnd, rl.Red)
|
||||||
|
}
|
||||||
|
|
||||||
|
rl.DrawRay(ray, rl.Maroon)
|
||||||
|
rl.DrawGrid(10, 10.0)
|
||||||
|
|
||||||
|
rl.EndMode3D()
|
||||||
|
|
||||||
|
// Draw some debug GUI text
|
||||||
|
rl.DrawText(fmt.Sprintf("Hit Object: %s", hitObjectName), 10, 50, 10, rl.Black)
|
||||||
|
|
||||||
|
if collision.Hit {
|
||||||
|
ypos := int32(70)
|
||||||
|
rl.DrawText(fmt.Sprintf("Distance: %3.2f", collision.Distance), 10, ypos, 10, rl.Black)
|
||||||
|
rl.DrawText(Vec2Str("Hit Pos : %3.2f %3.2f %3.2f", collision.Point), 10, ypos+15, 10, rl.Black)
|
||||||
|
rl.DrawText(Vec2Str("Hit Norm: %3.2f %3.2f %3.2f", collision.Normal), 10, ypos+30, 10, rl.Black)
|
||||||
|
if triHitInfo.Hit && hitObjectName == "Triangle" {
|
||||||
|
rl.DrawText(Vec2Str("Barycenter: %3.2f %3.2f %3.2f", bary), 10, ypos+45, 10, rl.Black)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rl.DrawText("Right click mouse to toggle camera controls", 10, 430, 10, rl.Gray)
|
||||||
|
rl.DrawText("(c) Turret 3D model by Alberto Cano", screenWidth-200, screenHeight-20, 10, rl.Gray)
|
||||||
|
|
||||||
|
rl.DrawFPS(10, 10)
|
||||||
|
|
||||||
|
rl.EndDrawing()
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-Initialization
|
||||||
|
rl.UnloadModel(tower) // Unload model
|
||||||
|
rl.UnloadTexture(texture) // Unload texture
|
||||||
|
|
||||||
|
rl.CloseWindow() // Close window and OpenGL context
|
||||||
|
}
|
||||||
|
|
||||||
|
func Vec2Str(format string, vec rl.Vector3) string {
|
||||||
|
return fmt.Sprintf(format, vec.X, vec.Y, vec.Z)
|
||||||
|
}
|
1888
examples/models/mesh_picking/turret.obj
Normal file
1888
examples/models/mesh_picking/turret.obj
Normal file
File diff suppressed because it is too large
Load diff
BIN
examples/models/mesh_picking/turret_diffuse.png
Normal file
BIN
examples/models/mesh_picking/turret_diffuse.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 371 KiB |
Loading…
Add table
Add a link
Reference in a new issue