WASM examples (+ backports of new official examples) (#344)
* chg: New build system that uses the officially distributed binaries, bumped version to 8.0.0, simplified git workflow, removed deprecated OpenGL 1.1 functionality. * chg: Modernize CI workflow, enable SourceLink - Bump workflow actions to latest majors (Node 24); drop deprecated softprops/action-gh-release@v1 - Trigger push builds on main instead of master - Create local nuget feed dir before pack (fixes NU1301) - Enable Microsoft.SourceLink.GitHub for debugging symbols (ref PR #340) * fix: centralized version data in Directory.build.props, and fixed various interop details that had incorrect function signatures * chore: updated readme * fix: version the native extract marker and chain download via DependsOnTargets The .extracted marker now includes the raylib package name, so bumping TargetRaylibTag re-extracts the new archive instead of silently keeping (and packing/copying) the previous version's files. _PrepareNativeLibrary and _StageWasmNative now depend directly on _DownloadAndExtractInternal instead of CallTarget-ing it; dependency targets run in the same project instance, so the resolved properties (RaylibPackageName etc.) propagate naturally. * fix: let the binding build for browser-wasm on both net8.0 and net10.0 The net8-era wasm workload (Microsoft.NET.Runtime.WebAssembly.Sdk 8.0.x, auto-imported for RID browser-wasm) treats every browser-wasm project as a wasm app: it forces OutputType=Exe after project evaluation (CS5001 for a classlib) and hooks its app-bundle build after Build, which errors because a library has no assemblies to bundle. Opt Raylib-cs out via DisableAutoWasmBuildApp (props time, before the workload defaults its trigger) and pin OutputType back to Library in Directory.Build.targets (evaluated after the workload props, so the assignment wins). net10's wasm SDK needs neither workaround. * chore: readme updated * chg: simplifying build logic - a simple line in the documentation should save us the code here * fix: Wrong signature of FrameBufferComplete * chore: readme update * feat: samples default to local project reference, and can optionally use the nuget package * feat: backporting existing raylib-cs examples and new official raylib examples to WASM, adopting raylib's original code style * chore: readme, gitignore, and targets backport. * fix: Examples.csproj runs the download task when building locally * feat: backporting existing raylib-cs examples and new official raylib examples to WASM, adopting raylib's original code style * chore: readme, gitignore, and targets backport. * chore: clean up linter warnings * feat: html harness focuses the example and allows quick navigation with J/K instead. * chore: readme mentions the property to use nuget vs. the local project reference * feat: replaced the J/K navigation with good old HTML buttons * chore: run dotnet format scoped default (was previously scoped to just 'style')
This commit is contained in:
parent
b207e633ae
commit
8c22e68c2a
236 changed files with 40405 additions and 10896 deletions
387
Examples/Models/AnimationBlendCustom.cs
Normal file
387
Examples/Models/AnimationBlendCustom.cs
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - animation blend custom
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by dmitrii-brand (@dmitrii-brand) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* DETAILS: Example demonstrates per-bone animation blending, allowing smooth transitions
|
||||
* between two animations by interpolating bone transforms. This is useful for:
|
||||
* - Blending movement animations (walk/run) with action animations (jump/attack)
|
||||
* - Creating smooth animation transitions
|
||||
* - Layering animations (e.g., upper body attack while lower body walks)
|
||||
*
|
||||
* WARNING: GPU skinning must be enabled in raylib with a compilation flag,
|
||||
* if not enabled, CPU skinning will be used instead
|
||||
*
|
||||
* 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) 2026 dmitrii-brand (@dmitrii-brand)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class AnimationBlendCustom : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
private const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Animation Blend Custom";
|
||||
|
||||
public string Title => "raylib [models] example - animation blend custom";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private Shader skinningShader;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex0;
|
||||
private int animIndex1;
|
||||
private int animCurrentFrame0;
|
||||
private int animCurrentFrame1;
|
||||
private bool upperBodyBlend;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(4.0f, 4.0f, 4.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load gltf model
|
||||
model = LoadModel("resources/models/gltf/greenman.glb");
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model position
|
||||
|
||||
// Load skinning shader
|
||||
// WARNING: GPU skinning must be enabled in raylib with a compilation flag,
|
||||
// if not enabled, CPU skinning will be used instead
|
||||
skinningShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.fs"
|
||||
);
|
||||
model.Materials[1].Shader = skinningShader;
|
||||
|
||||
// Load gltf model animations
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/gltf/greenman.glb", ref animCount);
|
||||
|
||||
// Use specific animation indices: 2-walk/move, 3-attack
|
||||
animIndex0 = 2; // Walk/Move animation (index 2)
|
||||
animIndex1 = 3; // Attack animation (index 3)
|
||||
animCurrentFrame0 = 0;
|
||||
animCurrentFrame1 = 0;
|
||||
|
||||
// Validate indices
|
||||
if (animIndex0 >= animCount)
|
||||
{
|
||||
animIndex0 = 0;
|
||||
}
|
||||
if (animIndex1 >= animCount)
|
||||
{
|
||||
animIndex1 = (animCount > 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
upperBodyBlend = true; // Toggle: true = upper/lower body blending, false = uniform blending (50/50)
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Toggle upper/lower body blending mode (SPACE key)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
upperBodyBlend = !upperBodyBlend;
|
||||
}
|
||||
|
||||
// Update animation frames
|
||||
var anim0 = anims[animIndex0];
|
||||
var anim1 = anims[animIndex1];
|
||||
|
||||
animCurrentFrame0 = (animCurrentFrame0 + 1) % anim0.KeyFrameCount;
|
||||
animCurrentFrame1 = (animCurrentFrame1 + 1) % anim1.KeyFrameCount;
|
||||
|
||||
// Blend the two animations
|
||||
// When upperBodyBlend is ON: upper body = attack (1.0), lower body = walk (0.0)
|
||||
// When upperBodyBlend is OFF: uniform blend at 0.5 (50% walk, 50% attack)
|
||||
var blendFactor = upperBodyBlend ? 1.0f : 0.5f;
|
||||
UpdateModelAnimationBones(anim0, animCurrentFrame0, anim1, animCurrentFrame1, blendFactor, upperBodyBlend);
|
||||
|
||||
// raylib provided animation blending function
|
||||
//UpdateModelAnimationEx(model, anim0, (float)animCurrentFrame0,
|
||||
// anim1, (float)animCurrentFrame1, blendFactor);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw UI
|
||||
DrawText($"ANIM 0: {anim0.NameToString()}", 10, 10, 20, Color.Gray);
|
||||
DrawText($"ANIM 1: {anim1.NameToString()}", 10, 40, 20, Color.Gray);
|
||||
DrawText($"[SPACE] Toggle blending mode: {(upperBodyBlend ? "Upper/Lower Body Blending" : "Uniform Blending")}",
|
||||
10, GetScreenHeight() - 30, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animation
|
||||
UnloadModel(model); // Unload model and meshes/material
|
||||
UnloadShader(skinningShader); // Unload GPU skinning shader
|
||||
}
|
||||
|
||||
// Check if a bone is part of upper body (for selective blending)
|
||||
private static bool IsUpperBodyBone(string boneName)
|
||||
{
|
||||
// Common upper body bone names (adjust based on your model)
|
||||
if (boneName is "spine" or "spine1" or "spine2" or
|
||||
"chest" or "upperChest" or
|
||||
"neck" or "head" or
|
||||
"shoulder" or "shoulder_L" or "shoulder_R" or
|
||||
"upperArm" or "upperArm_L" or "upperArm_R" or
|
||||
"lowerArm" or "lowerArm_L" or "lowerArm_R" or
|
||||
"hand" or "hand_L" or "hand_R" or
|
||||
"clavicle" or "clavicle_L" or "clavicle_R")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if bone name contains upper body keywords
|
||||
if (boneName.Contains("spine") || boneName.Contains("chest") ||
|
||||
boneName.Contains("neck") || boneName.Contains("head") ||
|
||||
boneName.Contains("shoulder") || boneName.Contains("arm") ||
|
||||
boneName.Contains("hand") || boneName.Contains("clavicle"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Blend two animations per-bone with selective upper/lower body blending
|
||||
private unsafe void UpdateModelAnimationBones(ModelAnimation anim0, int frame0,
|
||||
ModelAnimation anim1, int frame1, float blend, bool upperBodyBlend)
|
||||
{
|
||||
// Validate inputs
|
||||
if ((anim0.BoneCount != 0) && (anim0.KeyframePoses != null) &&
|
||||
(anim1.BoneCount != 0) && (anim1.KeyframePoses != null) &&
|
||||
(model.Skeleton.BoneCount != 0) && (model.Skeleton.BindPose != null))
|
||||
{
|
||||
// Clamp blend factor to [0, 1]
|
||||
blend = MathF.Min(1.0f, MathF.Max(0.0f, blend));
|
||||
|
||||
// Ensure frame indices are valid
|
||||
if (frame0 >= anim0.KeyFrameCount)
|
||||
{
|
||||
frame0 = anim0.KeyFrameCount - 1;
|
||||
}
|
||||
if (frame1 >= anim1.KeyFrameCount)
|
||||
{
|
||||
frame1 = anim1.KeyFrameCount - 1;
|
||||
}
|
||||
if (frame0 < 0)
|
||||
{
|
||||
frame0 = 0;
|
||||
}
|
||||
if (frame1 < 0)
|
||||
{
|
||||
frame1 = 0;
|
||||
}
|
||||
|
||||
// Get bone count (use minimum of all to be safe)
|
||||
var boneCount = model.Skeleton.BoneCount;
|
||||
if (anim0.BoneCount < boneCount)
|
||||
{
|
||||
boneCount = anim0.BoneCount;
|
||||
}
|
||||
if (anim1.BoneCount < boneCount)
|
||||
{
|
||||
boneCount = anim1.BoneCount;
|
||||
}
|
||||
|
||||
// Blend each bone
|
||||
for (var boneIndex = 0; boneIndex < boneCount; boneIndex++)
|
||||
{
|
||||
// Determine blend factor for this bone
|
||||
var boneBlendFactor = blend;
|
||||
|
||||
// If upper body blending is enabled, use different blend factors for upper vs lower body
|
||||
if (upperBodyBlend)
|
||||
{
|
||||
var boneName = model.Skeleton.Bones[boneIndex].NameToString();
|
||||
var isUpperBody = IsUpperBodyBone(boneName);
|
||||
|
||||
// Upper body: use anim1 (attack), Lower body: use anim0 (walk)
|
||||
// blend = 0.0 means full anim0 (walk), 1.0 means full anim1 (attack)
|
||||
if (isUpperBody)
|
||||
{
|
||||
boneBlendFactor = blend; // Upper body: blend towards anim1 (attack)
|
||||
}
|
||||
else
|
||||
{
|
||||
boneBlendFactor = 1.0f - blend; // Lower body: blend towards anim0 (walk) - invert the blend
|
||||
}
|
||||
}
|
||||
|
||||
// Get transforms from both animations
|
||||
var bindTransform = model.Skeleton.BindPose[boneIndex];
|
||||
var animTransform0 = anim0.KeyframePoses[frame0][boneIndex];
|
||||
var animTransform1 = anim1.KeyframePoses[frame1][boneIndex];
|
||||
|
||||
// Blend the transforms
|
||||
Transform blended = new();
|
||||
blended.Translation = Vector3Lerp(animTransform0.Translation, animTransform1.Translation, boneBlendFactor);
|
||||
blended.Rotation = QuaternionSlerp(animTransform0.Rotation, animTransform1.Rotation, boneBlendFactor);
|
||||
blended.Scale = Vector3Lerp(animTransform0.Scale, animTransform1.Scale, boneBlendFactor);
|
||||
|
||||
// Convert bind pose to matrix
|
||||
var bindMatrix = MatrixMultiply(MatrixMultiply(
|
||||
MatrixScale(bindTransform.Scale.X, bindTransform.Scale.Y, bindTransform.Scale.Z),
|
||||
QuaternionToMatrix(bindTransform.Rotation)),
|
||||
MatrixTranslate(bindTransform.Translation.X, bindTransform.Translation.Y, bindTransform.Translation.Z));
|
||||
|
||||
// Convert blended transform to matrix
|
||||
var blendedMatrix = MatrixMultiply(MatrixMultiply(
|
||||
MatrixScale(blended.Scale.X, blended.Scale.Y, blended.Scale.Z),
|
||||
QuaternionToMatrix(blended.Rotation)),
|
||||
MatrixTranslate(blended.Translation.X, blended.Translation.Y, blended.Translation.Z));
|
||||
|
||||
// Calculate final bone matrix (similar to UpdateModelAnimationBones)
|
||||
model.BoneMatrices[boneIndex] = MatrixMultiply(MatrixInvert(bindMatrix), blendedMatrix);
|
||||
}
|
||||
|
||||
// CPU skinning, updates CPU buffers and uploads them to GPU (if available)
|
||||
// NOTE: Fallback in case GPU skinning is not supported or enabled
|
||||
for (var m = 0; m < model.MeshCount; m++)
|
||||
{
|
||||
var mesh = model.Meshes[m];
|
||||
Vector3 animVertex;
|
||||
Vector3 animNormal;
|
||||
var vertexValuesCount = mesh.VertexCount * 3;
|
||||
|
||||
var boneCounter = 0;
|
||||
var bufferUpdateRequired = false; // Flag to check when anim vertex information is updated
|
||||
|
||||
// Skip if missing bone data or missing anim buffers initialization
|
||||
if ((mesh.BoneWeights == null) || (mesh.BoneIndices == null) ||
|
||||
(mesh.AnimVertices == null) || (mesh.AnimNormals == null))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var vCounter = 0; vCounter < vertexValuesCount; vCounter += 3)
|
||||
{
|
||||
mesh.AnimVertices[vCounter] = 0;
|
||||
mesh.AnimVertices[vCounter + 1] = 0;
|
||||
mesh.AnimVertices[vCounter + 2] = 0;
|
||||
if (mesh.AnimNormals != null)
|
||||
{
|
||||
mesh.AnimNormals[vCounter] = 0;
|
||||
mesh.AnimNormals[vCounter + 1] = 0;
|
||||
mesh.AnimNormals[vCounter + 2] = 0;
|
||||
}
|
||||
|
||||
// Iterates over 4 bones per vertex
|
||||
for (var j = 0; j < 4; j++, boneCounter++)
|
||||
{
|
||||
var boneWeight = mesh.BoneWeights[boneCounter];
|
||||
var boneIndex = mesh.BoneIndices[boneCounter];
|
||||
|
||||
// Early stop when no transformation will be applied
|
||||
if (boneWeight == 0.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
animVertex = new Vector3(mesh.Vertices[vCounter], mesh.Vertices[vCounter + 1], mesh.Vertices[vCounter + 2]);
|
||||
animVertex = Vector3Transform(animVertex, model.BoneMatrices[boneIndex]);
|
||||
mesh.AnimVertices[vCounter] += animVertex.X * boneWeight;
|
||||
mesh.AnimVertices[vCounter + 1] += animVertex.Y * boneWeight;
|
||||
mesh.AnimVertices[vCounter + 2] += animVertex.Z * boneWeight;
|
||||
bufferUpdateRequired = true;
|
||||
|
||||
// Normals processing
|
||||
// NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
|
||||
if ((mesh.Normals != null) && (mesh.AnimNormals != null))
|
||||
{
|
||||
animNormal = new Vector3(mesh.Normals[vCounter], mesh.Normals[vCounter + 1], mesh.Normals[vCounter + 2]);
|
||||
animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model.BoneMatrices[boneIndex])));
|
||||
mesh.AnimNormals[vCounter] += animNormal.X * boneWeight;
|
||||
mesh.AnimNormals[vCounter + 1] += animNormal.Y * boneWeight;
|
||||
mesh.AnimNormals[vCounter + 2] += animNormal.Z * boneWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferUpdateRequired)
|
||||
{
|
||||
// Update GPU vertex buffers with updated data (position + normals)
|
||||
Rlgl.UpdateVertexBuffer(mesh.VboId[(int)ShaderLocationIndex.VertexPosition], mesh.AnimVertices, mesh.VertexCount * 3 * sizeof(float), 0);
|
||||
if (mesh.Normals != null)
|
||||
{
|
||||
Rlgl.UpdateVertexBuffer(mesh.VboId[(int)ShaderLocationIndex.VertexNormal], mesh.AnimNormals, mesh.VertexCount * 3 * sizeof(float), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - animation blend custom");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AnimationBlendCustom();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
471
Examples/Models/AnimationBlending.cs
Normal file
471
Examples/Models/AnimationBlending.cs
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - animation blending
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Kirandeep (@Kirandeep-Singh-Khehra) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* WARNING: GPU skinning must be enabled in raylib with a compilation flag,
|
||||
* if not enabled, CPU skinning will be used instead
|
||||
*
|
||||
* 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) 2024-2026 Kirandeep (@Kirandeep-Singh-Khehra) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
// NOTE: The upstream example uses raygui for its UI controls (dropdowns, sliders, progress bars).
|
||||
// raygui is not part of raylib-cs, so the required controls are reimplemented here with
|
||||
// basic raylib drawing primitives, preserving the original behaviour.
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class AnimationBlending : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
private const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Animation Blending";
|
||||
|
||||
public string Title => "raylib [models] example - animation blending";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private Shader skinningShader;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
|
||||
private int currentAnimPlaying;
|
||||
private int nextAnimToPlay;
|
||||
private bool animTransition;
|
||||
|
||||
private int animIndex0;
|
||||
private float animCurrentFrame0;
|
||||
private float animFrameSpeed0;
|
||||
private int animIndex1;
|
||||
private float animCurrentFrame1;
|
||||
private float animFrameSpeed1;
|
||||
|
||||
private float animBlendFactor;
|
||||
private float animBlendTime;
|
||||
private float animBlendTimeCounter;
|
||||
|
||||
private bool animPause;
|
||||
|
||||
private string[] animNames;
|
||||
private bool dropdownEditMode0;
|
||||
private bool dropdownEditMode1;
|
||||
private float animFrameProgress0;
|
||||
private float animFrameProgress1;
|
||||
private float animBlendProgress;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(6.0f, 6.0f, 6.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/gltf/robot.glb"); // Load character model
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model world position
|
||||
|
||||
// Load skinning shader
|
||||
// NOTE: It must be a valid shader, following raylib attribs/uniform conventions for GPU skinning
|
||||
skinningShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.fs"
|
||||
);
|
||||
|
||||
// Skinning shader could be required to be assigned to all materials shaders, just to make
|
||||
// sure required uniforms are being updated for the mesh using that material (and shader)
|
||||
for (var i = 0; i < model.MaterialCount; i++)
|
||||
{
|
||||
model.Materials[i].Shader = skinningShader;
|
||||
}
|
||||
|
||||
// Load model animations
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/gltf/robot.glb", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
// NOTE: Two animations are played with a smooth transition between them
|
||||
currentAnimPlaying = 0; // Current animation playing (0 o 1)
|
||||
nextAnimToPlay = 1; // Next animation to play (to transition)
|
||||
animTransition = false; // Flag to register anim transition state
|
||||
|
||||
animIndex0 = 10; // Current animation playing (walking)
|
||||
animCurrentFrame0 = 0.0f; // Current animation frame (supporting interpolated frames)
|
||||
animFrameSpeed0 = 0.5f; // Current animation play speed
|
||||
animIndex1 = 6; // Next animation to play (running)
|
||||
animCurrentFrame1 = 0.0f; // Next animation frame (supporting interpolated frames)
|
||||
animFrameSpeed1 = 0.5f; // Next animation play speed
|
||||
|
||||
animBlendFactor = 0.0f; // Blend factor from anim0[frame0] --> anim1[frame1], [0.0f..1.0f]
|
||||
|
||||
animBlendTime = 2.0f; // Time to blend from one playing animation to another (in seconds)
|
||||
animBlendTimeCounter = 0.0f; // Time counter (delta time)
|
||||
|
||||
animPause = false; // Pause animation
|
||||
|
||||
// UI required variables
|
||||
animNames = new string[animCount];
|
||||
for (var i = 0; i < animCount; i++)
|
||||
{
|
||||
animNames[i] = anims[i].NameToString();
|
||||
}
|
||||
|
||||
dropdownEditMode0 = false;
|
||||
dropdownEditMode1 = false;
|
||||
animFrameProgress0 = 0.0f;
|
||||
animFrameProgress1 = 0.0f;
|
||||
animBlendProgress = 0.0f;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
animPause = !animPause;
|
||||
}
|
||||
|
||||
if (!animPause)
|
||||
{
|
||||
// Start transition from anim0[] to anim1[]
|
||||
if (IsKeyPressed(KeyboardKey.Space) && !animTransition)
|
||||
{
|
||||
if (currentAnimPlaying == 0)
|
||||
{
|
||||
// Transition anim0 --> anim1
|
||||
nextAnimToPlay = 1;
|
||||
animCurrentFrame1 = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transition anim1 --> anim0
|
||||
nextAnimToPlay = 0;
|
||||
animCurrentFrame0 = 0.0f;
|
||||
}
|
||||
|
||||
// Set animation transition
|
||||
animTransition = true;
|
||||
animBlendTimeCounter = 0.0f;
|
||||
animBlendFactor = 0.0f;
|
||||
}
|
||||
|
||||
if (animTransition)
|
||||
{
|
||||
// Playing anim0 and anim1 at the same time
|
||||
animCurrentFrame0 += animFrameSpeed0;
|
||||
if (animCurrentFrame0 >= anims[animIndex0].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame0 = 0.0f;
|
||||
}
|
||||
animCurrentFrame1 += animFrameSpeed1;
|
||||
if (animCurrentFrame1 >= anims[animIndex1].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame1 = 0.0f;
|
||||
}
|
||||
|
||||
// Increment blend factor over time to transition from anim0 --> anim1 over time
|
||||
// NOTE: Time blending could be other than linear, using some easing
|
||||
animBlendFactor = animBlendTimeCounter / animBlendTime;
|
||||
animBlendTimeCounter += GetFrameTime();
|
||||
animBlendProgress = animBlendFactor;
|
||||
|
||||
// Update model with animations blending
|
||||
if (nextAnimToPlay == 1)
|
||||
{
|
||||
// Blend anim0 --> anim1
|
||||
UpdateModelAnimationEx(model, anims[animIndex0], animCurrentFrame0,
|
||||
anims[animIndex1], animCurrentFrame1, animBlendFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Blend anim1 --> anim0
|
||||
UpdateModelAnimationEx(model, anims[animIndex1], animCurrentFrame1,
|
||||
anims[animIndex0], animCurrentFrame0, animBlendFactor);
|
||||
}
|
||||
|
||||
// Check if transition completed
|
||||
if (animBlendFactor > 1.0f)
|
||||
{
|
||||
// Reset frame states
|
||||
if (currentAnimPlaying == 0)
|
||||
{
|
||||
animCurrentFrame0 = 0.0f;
|
||||
}
|
||||
else if (currentAnimPlaying == 1)
|
||||
{
|
||||
animCurrentFrame1 = 0.0f;
|
||||
}
|
||||
currentAnimPlaying = nextAnimToPlay; // Update current animation playing
|
||||
|
||||
animBlendFactor = 0.0f; // Reset blend factor
|
||||
animTransition = false; // Exit transition mode
|
||||
animBlendTimeCounter = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Play only one anim, the current one
|
||||
if (currentAnimPlaying == 0)
|
||||
{
|
||||
// Playing anim0 at defined speed
|
||||
animCurrentFrame0 += animFrameSpeed0;
|
||||
if (animCurrentFrame0 >= anims[animIndex0].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame0 = 0.0f;
|
||||
}
|
||||
UpdateModelAnimation(model, anims[animIndex0], animCurrentFrame0);
|
||||
}
|
||||
else if (currentAnimPlaying == 1)
|
||||
{
|
||||
// Playing anim1 at defined speed
|
||||
animCurrentFrame1 += animFrameSpeed1;
|
||||
if (animCurrentFrame1 >= anims[animIndex1].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame1 = 0.0f;
|
||||
}
|
||||
UpdateModelAnimation(model, anims[animIndex1], animCurrentFrame1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update progress bars values with current frame for each animation
|
||||
animFrameProgress0 = animCurrentFrame0;
|
||||
animFrameProgress1 = animCurrentFrame1;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White); // Draw animated model
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
if (animTransition)
|
||||
{
|
||||
DrawText("ANIM TRANSITION BLENDING!", 170, 50, 30, Color.Blue);
|
||||
}
|
||||
|
||||
// Draw UI elements
|
||||
//---------------------------------------------------------------------------------------------
|
||||
GuiSlider(new Rectangle(10, 38, 160, 12), null, $"x{animFrameSpeed0:0.0}", ref animFrameSpeed0, 0.1f, 2.0f);
|
||||
GuiSlider(new Rectangle(GetScreenWidth() - 170.0f, 38, 160, 12), $"{animFrameSpeed1:0.0}x", null, ref animFrameSpeed1, 0.1f, 2.0f);
|
||||
|
||||
// Blending process progress bar
|
||||
GuiProgressBar(new Rectangle(180, 14, 440, 16), null, null, animBlendProgress, 0.0f, 1.0f);
|
||||
|
||||
// Centered "PRESS SPACE" label
|
||||
const string spaceLabel = "PRESS SPACE to START BLENDING";
|
||||
var spaceLabelWidth = MeasureText(spaceLabel, 20);
|
||||
DrawText(spaceLabel, (GetScreenWidth() - spaceLabelWidth) / 2, (int)(GetScreenHeight() - 100.0f + 10), 20, Color.DarkGray);
|
||||
|
||||
// Draw playing timeline with keyframes for anim0[]
|
||||
GuiProgressBar(new Rectangle(60, GetScreenHeight() - 60.0f, GetScreenWidth() - 180.0f, 20), "ANIM 0",
|
||||
$"FRAME: {animFrameProgress0:0.00} / {anims[animIndex0].KeyFrameCount}",
|
||||
animFrameProgress0, 0.0f, anims[animIndex0].KeyFrameCount);
|
||||
for (var i = 0; i < anims[animIndex0].KeyFrameCount; i++)
|
||||
{
|
||||
DrawRectangle(60 + (int)(((float)(GetScreenWidth() - 180) / anims[animIndex0].KeyFrameCount) * i),
|
||||
GetScreenHeight() - 60, 1, 20, Color.Blue);
|
||||
}
|
||||
|
||||
// Draw playing timeline with keyframes for anim1[]
|
||||
GuiProgressBar(new Rectangle(60, GetScreenHeight() - 30.0f, GetScreenWidth() - 180.0f, 20), "ANIM 1",
|
||||
$"FRAME: {animFrameProgress1:0.00} / {anims[animIndex1].KeyFrameCount}",
|
||||
animFrameProgress1, 0.0f, anims[animIndex1].KeyFrameCount);
|
||||
for (var i = 0; i < anims[animIndex1].KeyFrameCount; i++)
|
||||
{
|
||||
DrawRectangle(60 + (int)(((float)(GetScreenWidth() - 180) / anims[animIndex1].KeyFrameCount) * i),
|
||||
GetScreenHeight() - 30, 1, 20, Color.Blue);
|
||||
}
|
||||
|
||||
// Draw animation selectors for blending transition (drawn last so open lists render on top)
|
||||
// NOTE: Transition does not start until requested
|
||||
if (GuiDropdownBox(new Rectangle(10, 10, 160, 24), animNames, ref animIndex0, dropdownEditMode0))
|
||||
{
|
||||
dropdownEditMode0 = !dropdownEditMode0;
|
||||
}
|
||||
if (GuiDropdownBox(new Rectangle(GetScreenWidth() - 170.0f, 10, 160, 24), animNames, ref animIndex1, dropdownEditMode1))
|
||||
{
|
||||
dropdownEditMode1 = !dropdownEditMode1;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animation
|
||||
UnloadModel(model); // Unload model and meshes/material
|
||||
UnloadShader(skinningShader); // Unload GPU skinning shader
|
||||
}
|
||||
|
||||
// Minimal immediate-mode slider (raygui replacement)
|
||||
private static bool GuiSlider(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
|
||||
{
|
||||
var mouse = GetMousePosition();
|
||||
var dragging = false;
|
||||
if (CheckCollisionPointRec(mouse, bounds) && IsMouseButtonDown(MouseButton.Left))
|
||||
{
|
||||
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
|
||||
if (value < minValue)
|
||||
{
|
||||
value = minValue;
|
||||
}
|
||||
if (value > maxValue)
|
||||
{
|
||||
value = maxValue;
|
||||
}
|
||||
dragging = true;
|
||||
}
|
||||
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
var pct = (value - minValue) / (maxValue - minValue);
|
||||
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (!string.IsNullOrEmpty(textLeft))
|
||||
{
|
||||
DrawText(textLeft, (int)(bounds.X - MeasureText(textLeft, 10) - 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(textRight))
|
||||
{
|
||||
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
return dragging;
|
||||
}
|
||||
|
||||
// Minimal immediate-mode progress bar (raygui replacement)
|
||||
private static void GuiProgressBar(Rectangle bounds, string textLeft, string textRight, float value, float minValue, float maxValue)
|
||||
{
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
var pct = maxValue > minValue ? (value - minValue) / (maxValue - minValue) : 0.0f;
|
||||
if (pct < 0)
|
||||
{
|
||||
pct = 0;
|
||||
}
|
||||
if (pct > 1)
|
||||
{
|
||||
pct = 1;
|
||||
}
|
||||
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (!string.IsNullOrEmpty(textLeft))
|
||||
{
|
||||
DrawText(textLeft, (int)(bounds.X - MeasureText(textLeft, 10) - 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(textRight))
|
||||
{
|
||||
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
}
|
||||
|
||||
// Minimal immediate-mode dropdown box (raygui replacement)
|
||||
private static bool GuiDropdownBox(Rectangle bounds, string[] items, ref int active, bool editMode)
|
||||
{
|
||||
var result = false;
|
||||
var mouse = GetMousePosition();
|
||||
|
||||
// Draw main box
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (active >= 0 && active < items.Length)
|
||||
{
|
||||
DrawText(items[active], (int)bounds.X + 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
DrawText(editMode ? "^" : "v", (int)(bounds.X + bounds.Width - 12), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
|
||||
// Draw items when open
|
||||
if (editMode)
|
||||
{
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
Rectangle item = new(bounds.X, bounds.Y + bounds.Height * (i + 1), bounds.Width, bounds.Height);
|
||||
var hover = CheckCollisionPointRec(mouse, item);
|
||||
DrawRectangleRec(item, hover ? Color.SkyBlue : Color.LightGray);
|
||||
DrawRectangleLinesEx(item, 1, Color.Gray);
|
||||
DrawText(items[i], (int)item.X + 5, (int)(item.Y + item.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
if (editMode)
|
||||
{
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
Rectangle item = new(bounds.X, bounds.Y + bounds.Height * (i + 1), bounds.Width, bounds.Height);
|
||||
if (CheckCollisionPointRec(mouse, item))
|
||||
{
|
||||
active = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = true; // any click closes the dropdown
|
||||
}
|
||||
else if (CheckCollisionPointRec(mouse, bounds))
|
||||
{
|
||||
result = true; // open the dropdown
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - animation blending");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AnimationBlending();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
157
Examples/Models/AnimationGpuSkinning.cs
Normal file
157
Examples/Models/AnimationGpuSkinning.cs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - animation gpu skinning
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by Daniel Holden (@orangeduck) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* WARNING: GPU skinning must be enabled in raylib with a compilation flag,
|
||||
* if not enabled, CPU skinning will be used instead
|
||||
*
|
||||
* 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) 2024-2025 Daniel Holden (@orangeduck)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class AnimationGpuSkinning : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
private const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Animation GPU Skinning";
|
||||
|
||||
public string Title => "raylib [models] example - animation gpu skinning";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private Shader skinningShader;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private int animCurrentFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 5.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load gltf model
|
||||
model = LoadModel("resources/models/gltf/greenman.glb"); // Load character model
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model position
|
||||
|
||||
// Load skinning shader
|
||||
// NOTE: It must be a valid shader, following raylib attribs/uniform conventions for GPU skinning
|
||||
skinningShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.fs"
|
||||
);
|
||||
|
||||
// Skinning shader could be required to be assigned to all materials shaders, just to make
|
||||
// sure required uniforms are being updated for the mesh using that material (and shader)
|
||||
model.Materials[1].Shader = skinningShader; // Just assigning to materials[1] for this model
|
||||
|
||||
// Load gltf model animations
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/gltf/greenman.glb", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 0; // Current animation playing
|
||||
animCurrentFrame = 0; // Current animation frame
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Select current animation
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
animIndex = (animIndex + 1) % animCount;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
animIndex = (animIndex + animCount - 1) % animCount;
|
||||
}
|
||||
|
||||
// Update model animation
|
||||
animCurrentFrame = (animCurrentFrame + 1) % anims[animIndex].KeyFrameCount;
|
||||
UpdateModelAnimation(model, anims[animIndex], animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 40, 20, Color.Maroon);
|
||||
DrawText("Use the LEFT/RIGHT keys to switch animation", 10, 10, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animation
|
||||
UnloadModel(model); // Unload model and meshes/material
|
||||
UnloadShader(skinningShader); // Unload GPU skinning shader
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - animation gpu skinning");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AnimationGpuSkinning();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
289
Examples/Models/AnimationTiming.cs
Normal file
289
Examples/Models/AnimationTiming.cs
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - animation timing
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* 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) 2026 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
// NOTE: The upstream example uses raygui for its UI controls (dropdown, slider, progress bar).
|
||||
// raygui is not part of raylib-cs, so the required controls are reimplemented here with
|
||||
// basic raylib drawing primitives, preserving the original behaviour.
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class AnimationTiming : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Animation Timing";
|
||||
|
||||
public string Title => "raylib [models] example - animation timing";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private float animCurrentFrame;
|
||||
private float animFrameSpeed;
|
||||
private bool animPause;
|
||||
private string[] animNames;
|
||||
private bool dropdownEditMode;
|
||||
private float animFrameProgress;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(6.0f, 6.0f, 6.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/gltf/robot.glb");
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model world position
|
||||
|
||||
// Load model animations
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/gltf/robot.glb", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 10; // Current animation playing
|
||||
animCurrentFrame = 0.0f; // Current animation frame (supporting interpolated frames)
|
||||
animFrameSpeed = 0.5f; // Animation play speed
|
||||
animPause = false; // Pause animation
|
||||
|
||||
// UI required variables
|
||||
animNames = new string[animCount];
|
||||
for (var i = 0; i < animCount; i++)
|
||||
{
|
||||
animNames[i] = anims[i].NameToString();
|
||||
}
|
||||
|
||||
dropdownEditMode = false;
|
||||
animFrameProgress = 0.0f;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
animPause = !animPause;
|
||||
}
|
||||
|
||||
if (!animPause && (animIndex < animCount))
|
||||
{
|
||||
// Update model animation
|
||||
animCurrentFrame += animFrameSpeed;
|
||||
if (animCurrentFrame >= anims[animIndex].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame = 0.0f;
|
||||
}
|
||||
UpdateModelAnimation(model, anims[animIndex], animCurrentFrame);
|
||||
}
|
||||
|
||||
// NOTE: Animation and playing speed selected through UI
|
||||
|
||||
// Update progressbar value with current frame
|
||||
animFrameProgress = animCurrentFrame;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw UI, select anim and playing speed
|
||||
GuiSlider(new Rectangle(260, 10, 500, 24), "FRAME SPEED: ", $"x{animFrameSpeed:0.0}", ref animFrameSpeed, 0.1f, 2.0f);
|
||||
|
||||
// Draw playing timeline with keyframes
|
||||
DrawText($"CURRENT FRAME: {animFrameProgress:0.00} / {anims[animIndex].KeyFrameCount}",
|
||||
10, (int)(GetScreenHeight() - 64.0f), 10, Color.DarkGray);
|
||||
GuiProgressBar(new Rectangle(10, GetScreenHeight() - 40.0f, GetScreenWidth() - 20.0f, 24), null, null,
|
||||
animFrameProgress, 0.0f, anims[animIndex].KeyFrameCount);
|
||||
for (var i = 0; i < anims[animIndex].KeyFrameCount; i++)
|
||||
{
|
||||
DrawRectangle(10 + (int)(((float)(GetScreenWidth() - 20) / anims[animIndex].KeyFrameCount) * i),
|
||||
GetScreenHeight() - 40, 1, 24, Color.Blue);
|
||||
}
|
||||
|
||||
// NOTE: Dropdown drawn last so its open item list renders on top
|
||||
if (GuiDropdownBox(new Rectangle(10, 10, 140, 24), animNames, ref animIndex, dropdownEditMode))
|
||||
{
|
||||
dropdownEditMode = !dropdownEditMode;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animation
|
||||
UnloadModel(model); // Unload model and meshes/material
|
||||
}
|
||||
|
||||
// Minimal immediate-mode slider (raygui replacement)
|
||||
private static bool GuiSlider(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
|
||||
{
|
||||
var mouse = GetMousePosition();
|
||||
var dragging = false;
|
||||
if (CheckCollisionPointRec(mouse, bounds) && IsMouseButtonDown(MouseButton.Left))
|
||||
{
|
||||
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
|
||||
if (value < minValue)
|
||||
{
|
||||
value = minValue;
|
||||
}
|
||||
if (value > maxValue)
|
||||
{
|
||||
value = maxValue;
|
||||
}
|
||||
dragging = true;
|
||||
}
|
||||
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
var pct = (value - minValue) / (maxValue - minValue);
|
||||
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (!string.IsNullOrEmpty(textLeft))
|
||||
{
|
||||
DrawText(textLeft, (int)(bounds.X - MeasureText(textLeft, 10) - 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(textRight))
|
||||
{
|
||||
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
return dragging;
|
||||
}
|
||||
|
||||
// Minimal immediate-mode progress bar (raygui replacement)
|
||||
private static void GuiProgressBar(Rectangle bounds, string textLeft, string textRight, float value, float minValue, float maxValue)
|
||||
{
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
var pct = maxValue > minValue ? (value - minValue) / (maxValue - minValue) : 0.0f;
|
||||
if (pct < 0)
|
||||
{
|
||||
pct = 0;
|
||||
}
|
||||
if (pct > 1)
|
||||
{
|
||||
pct = 1;
|
||||
}
|
||||
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (!string.IsNullOrEmpty(textLeft))
|
||||
{
|
||||
DrawText(textLeft, (int)(bounds.X - MeasureText(textLeft, 10) - 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(textRight))
|
||||
{
|
||||
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
}
|
||||
|
||||
// Minimal immediate-mode dropdown box (raygui replacement)
|
||||
private static bool GuiDropdownBox(Rectangle bounds, string[] items, ref int active, bool editMode)
|
||||
{
|
||||
var result = false;
|
||||
var mouse = GetMousePosition();
|
||||
|
||||
// Draw main box
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (active >= 0 && active < items.Length)
|
||||
{
|
||||
DrawText(items[active], (int)bounds.X + 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
DrawText(editMode ? "^" : "v", (int)(bounds.X + bounds.Width - 12), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
|
||||
// Draw items when open
|
||||
if (editMode)
|
||||
{
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
Rectangle item = new(bounds.X, bounds.Y + bounds.Height * (i + 1), bounds.Width, bounds.Height);
|
||||
var hover = CheckCollisionPointRec(mouse, item);
|
||||
DrawRectangleRec(item, hover ? Color.SkyBlue : Color.LightGray);
|
||||
DrawRectangleLinesEx(item, 1, Color.Gray);
|
||||
DrawText(items[i], (int)item.X + 5, (int)(item.Y + item.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
if (editMode)
|
||||
{
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
Rectangle item = new(bounds.X, bounds.Y + bounds.Height * (i + 1), bounds.Width, bounds.Height);
|
||||
if (CheckCollisionPointRec(mouse, item))
|
||||
{
|
||||
active = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = true; // any click closes the dropdown
|
||||
}
|
||||
else if (CheckCollisionPointRec(mouse, bounds))
|
||||
{
|
||||
result = true; // open the dropdown
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - animation timing");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AnimationTiming();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
199
Examples/Models/BasicVoxel.cs
Normal file
199
Examples/Models/BasicVoxel.cs
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - basic voxel
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Tim Little (@timlittle) 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) 2025 Tim Little (@timlittle)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class BasicVoxel : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int WorldSize = 8; // Size of our voxel world (8x8x8 cubes)
|
||||
|
||||
public string Name => "Models / Basic Voxel";
|
||||
|
||||
public string Title => "raylib [models] example - basic voxel";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model cubeModel;
|
||||
private bool[,,] voxels;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world (first person)
|
||||
camera = new();
|
||||
camera.Position = new Vector3(-2.0f, 0.0f, -2.0f); // Camera position at ground level
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Create a cube model
|
||||
var cubeMesh = GenMeshCube(1.0f, 1.0f, 1.0f); // Create a unit cube mesh
|
||||
cubeModel = LoadModelFromMesh(cubeMesh); // Convert mesh to a model
|
||||
cubeModel.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Color = Color.Beige;
|
||||
|
||||
// Initialize voxel world - fill with voxels
|
||||
voxels = new bool[WorldSize, WorldSize, WorldSize];
|
||||
for (var x = 0; x < WorldSize; x++)
|
||||
{
|
||||
for (var y = 0; y < WorldSize; y++)
|
||||
{
|
||||
for (var z = 0; z < WorldSize; z++)
|
||||
{
|
||||
voxels[x, y, z] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
|
||||
// Handle voxel removal with mouse click
|
||||
// This method is quite inefficient. Ray marching through the voxel grid using DDA would be faster, but more complex.
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Cast a ray from the screen center (where crosshair would be)
|
||||
Vector2 screenCenter = new(GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f);
|
||||
var ray = GetScreenToWorldRay(screenCenter, camera);
|
||||
|
||||
// Check ray collision with all voxels
|
||||
var closestDistance = 99999.0f;
|
||||
Vector3 closestVoxelPosition = new(-1, -1, -1);
|
||||
var voxelFound = false;
|
||||
for (var x = 0; x < WorldSize; x++)
|
||||
{
|
||||
for (var y = 0; y < WorldSize; y++)
|
||||
{
|
||||
for (var z = 0; z < WorldSize; z++)
|
||||
{
|
||||
if (!voxels[x, y, z])
|
||||
{
|
||||
continue; // Skip empty voxels
|
||||
}
|
||||
|
||||
// Build a bounding box for this voxel
|
||||
Vector3 position = new(x, y, z);
|
||||
BoundingBox box = new(
|
||||
new Vector3(position.X - 0.5f, position.Y - 0.5f, position.Z - 0.5f),
|
||||
new Vector3(position.X + 0.5f, position.Y + 0.5f, position.Z + 0.5f)
|
||||
);
|
||||
|
||||
// Check ray-box collision
|
||||
var collision = GetRayCollisionBox(ray, box);
|
||||
if (collision.Hit && (collision.Distance < closestDistance))
|
||||
{
|
||||
closestDistance = collision.Distance;
|
||||
closestVoxelPosition = new Vector3(x, y, z);
|
||||
voxelFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the closest voxel if one was hit
|
||||
if (voxelFound)
|
||||
{
|
||||
voxels[(int)closestVoxelPosition.X,
|
||||
(int)closestVoxelPosition.Y,
|
||||
(int)closestVoxelPosition.Z] = false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Draw all voxels
|
||||
for (var x = 0; x < WorldSize; x++)
|
||||
{
|
||||
for (var y = 0; y < WorldSize; y++)
|
||||
{
|
||||
for (var z = 0; z < WorldSize; z++)
|
||||
{
|
||||
if (!voxels[x, y, z])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3 position = new(x, y, z);
|
||||
DrawModel(cubeModel, position, 1.0f, Color.Beige);
|
||||
DrawCubeWires(position, 1.0f, 1.0f, 1.0f, Color.Black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw reference point for raycasting to delete blocks
|
||||
DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 4, Color.Red);
|
||||
|
||||
DrawText("Left-click a voxel to remove it!", 10, 10, 20, Color.DarkGray);
|
||||
DrawText("WASD to move, mouse to look around", 10, 35, 10, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(cubeModel);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - basic voxel");
|
||||
|
||||
DisableCursor(); // Lock mouse to window center
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BasicVoxel();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,134 +1,145 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Drawing billboards
|
||||
* raylib [models] example - billboard rendering
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 3.5
|
||||
*
|
||||
* 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class BillboardDemo
|
||||
public partial class BillboardDemo : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Billboard Demo";
|
||||
|
||||
public string Title => "raylib [models] example - billboard rendering";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D bill;
|
||||
private Vector3 billPositionStatic;
|
||||
private Vector3 billPositionRotating;
|
||||
private Rectangle source;
|
||||
private Vector3 billUp;
|
||||
private Vector2 size;
|
||||
private Vector2 origin;
|
||||
private float distanceStatic;
|
||||
private float distanceRotating;
|
||||
private float rotation;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 4.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
bill = LoadTexture("resources/billboard.png"); // Our billboard texture
|
||||
billPositionStatic = new(0.0f, 2.0f, 0.0f); // Position of static billboard
|
||||
billPositionRotating = new(1.0f, 2.0f, 1.0f); // Position of rotating billboard
|
||||
|
||||
// Entire billboard texture, source is used to take a segment from a larger texture
|
||||
source = new(0.0f, 0.0f, (float)bill.Width, (float)bill.Height);
|
||||
|
||||
// NOTE: Billboard locked on axis-Y
|
||||
billUp = new(0.0f, 1.0f, 0.0f);
|
||||
|
||||
// Set the height of the rotating billboard to 1.0 with the aspect ratio fixed
|
||||
size = new(source.Width / source.Height, 1.0f);
|
||||
|
||||
// Rotate around origin
|
||||
// Here we choose to rotate around the image center
|
||||
origin = size * 0.5f;
|
||||
|
||||
// Distance is needed for the correct billboard draw order
|
||||
// Larger distance (further away from the camera) should be drawn prior to smaller distance
|
||||
distanceStatic = 0.0f;
|
||||
distanceRotating = 0.0f;
|
||||
rotation = 0.0f;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
rotation += 0.4f;
|
||||
distanceStatic = Vector3.Distance(camera.Position, billPositionStatic);
|
||||
distanceRotating = Vector3.Distance(camera.Position, billPositionRotating);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
// Draw order matters!
|
||||
if (distanceStatic > distanceRotating)
|
||||
{
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, Color.White);
|
||||
DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, Color.White);
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, Color.White);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(bill); // Unload texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - billboard rendering");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - drawing billboards");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(5.0f, 4.0f, 5.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Our texture billboard
|
||||
Texture2D bill = LoadTexture("resources/billboard.png");
|
||||
|
||||
// Position of billboard billboard
|
||||
Vector3 billPositionStatic = new(0.0f, 2.0f, 0.0f);
|
||||
Vector3 billPositionRotating = new(1.0f, 2.0f, 1.0f);
|
||||
|
||||
// Entire billboard texture, source is used to take a segment from a larger texture.
|
||||
Rectangle source = new(0.0f, 0.0f, (float)bill.Width, (float)bill.Height);
|
||||
|
||||
// NOTE: Billboard locked on axis-Y
|
||||
Vector3 billUp = new(0.0f, 1.0f, 0.0f);
|
||||
|
||||
// Rotate around origin
|
||||
// Here we choose to rotate around the image center
|
||||
// NOTE: (-1, 1) is the range where origin.X, origin.Y is inside the texture
|
||||
Vector2 rotateOrigin = Vector2.Zero;
|
||||
|
||||
// Distance is needed for the correct billboard draw order
|
||||
// Larger distance (further away from the camera) should be drawn prior to smaller distance.
|
||||
float distanceStatic = 0.0f;
|
||||
float distanceRotating = 0.0f;
|
||||
|
||||
float rotation = 0.0f;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BillboardDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
rotation += 0.4f;
|
||||
distanceStatic = Vector3.Distance(camera.Position, billPositionStatic);
|
||||
distanceRotating = Vector3.Distance(camera.Position, billPositionRotating);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Draw order matters!
|
||||
if (distanceStatic > distanceRotating)
|
||||
{
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, Color.White);
|
||||
DrawBillboardPro(
|
||||
camera,
|
||||
bill,
|
||||
source,
|
||||
billPositionRotating,
|
||||
billUp,
|
||||
new Vector2(1.0f, 1.0f),
|
||||
rotateOrigin,
|
||||
rotation,
|
||||
Color.White
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawBillboardPro(
|
||||
camera,
|
||||
bill,
|
||||
source,
|
||||
billPositionRotating,
|
||||
billUp,
|
||||
new Vector2(1.0f, 1.0f),
|
||||
rotateOrigin,
|
||||
rotation,
|
||||
Color.White
|
||||
);
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, Color.White);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(bill);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
244
Examples/Models/BoneSocket.cs
Normal file
244
Examples/Models/BoneSocket.cs
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - bone socket
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by iP (@ipzaur) 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) 2024-2025 iP (@ipzaur)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class BoneSocket : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int BoneSockets = 3;
|
||||
private const int BoneSocketHat = 0;
|
||||
private const int BoneSocketHandR = 1;
|
||||
private const int BoneSocketHandL = 2;
|
||||
|
||||
public string Name => "Models / Bone Socket";
|
||||
|
||||
public string Title => "raylib [models] example - bone socket";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model characterModel;
|
||||
private Model[] equipModel;
|
||||
private bool[] showEquip;
|
||||
private int animsCount;
|
||||
private int animIndex;
|
||||
private int animCurrentFrame;
|
||||
private unsafe ModelAnimation* modelAnimations;
|
||||
private int[] boneSocketIndex;
|
||||
private Vector3 position;
|
||||
private int angle;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 5.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load gltf model
|
||||
characterModel = LoadModel("resources/models/gltf/greenman.glb"); // Load character model
|
||||
equipModel = new Model[BoneSockets]
|
||||
{
|
||||
LoadModel("resources/models/gltf/greenman_hat.glb"), // Index for the hat model is the same as BONE_SOCKET_HAT
|
||||
LoadModel("resources/models/gltf/greenman_sword.glb"), // Index for the sword model is the same as BONE_SOCKET_HAND_R
|
||||
LoadModel("resources/models/gltf/greenman_shield.glb") // Index for the shield model is the same as BONE_SOCKET_HAND_L
|
||||
};
|
||||
|
||||
showEquip = new bool[3] { true, true, true }; // Toggle on/off equip
|
||||
|
||||
// Load gltf model animations
|
||||
animsCount = 0;
|
||||
animIndex = 0;
|
||||
animCurrentFrame = 0;
|
||||
modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", ref animsCount);
|
||||
|
||||
// Indices of bones for sockets
|
||||
boneSocketIndex = new int[BoneSockets] { -1, -1, -1 };
|
||||
|
||||
// Search bones for sockets
|
||||
for (var i = 0; i < characterModel.Skeleton.BoneCount; i++)
|
||||
{
|
||||
var boneName = characterModel.Skeleton.Bones[i].NameToString();
|
||||
|
||||
if (boneName == "socket_hat")
|
||||
{
|
||||
boneSocketIndex[BoneSocketHat] = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (boneName == "socket_hand_R")
|
||||
{
|
||||
boneSocketIndex[BoneSocketHandR] = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (boneName == "socket_hand_L")
|
||||
{
|
||||
boneSocketIndex[BoneSocketHandL] = i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model position
|
||||
angle = 0; // Set angle for rotate character
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.ThirdPerson);
|
||||
|
||||
// Rotate character
|
||||
if (IsKeyDown(KeyboardKey.F))
|
||||
{
|
||||
angle = (angle + 1) % 360;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.H))
|
||||
{
|
||||
angle = (360 + angle - 1) % 360;
|
||||
}
|
||||
|
||||
// Select current animation
|
||||
if (IsKeyPressed(KeyboardKey.T))
|
||||
{
|
||||
animIndex = (animIndex + 1) % animsCount;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.G))
|
||||
{
|
||||
animIndex = (animIndex + animsCount - 1) % animsCount;
|
||||
}
|
||||
|
||||
// Toggle shown of equip
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
showEquip[BoneSocketHat] = !showEquip[BoneSocketHat];
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
showEquip[BoneSocketHandR] = !showEquip[BoneSocketHandR];
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
showEquip[BoneSocketHandL] = !showEquip[BoneSocketHandL];
|
||||
}
|
||||
|
||||
// Update model animation
|
||||
var anim = modelAnimations[animIndex];
|
||||
animCurrentFrame = (animCurrentFrame + 1) % anim.KeyFrameCount;
|
||||
UpdateModelAnimation(characterModel, anim, animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw character
|
||||
var characterRotate = QuaternionFromAxisAngle(new Vector3(0.0f, 1.0f, 0.0f), angle * DEG2RAD);
|
||||
characterModel.Transform = MatrixMultiply(QuaternionToMatrix(characterRotate), MatrixTranslate(position.X, position.Y, position.Z));
|
||||
UpdateModelAnimation(characterModel, anim, animCurrentFrame);
|
||||
DrawMesh(characterModel.Meshes[0], characterModel.Materials[1], characterModel.Transform);
|
||||
|
||||
// Draw equipments (hat, sword, shield)
|
||||
for (var i = 0; i < BoneSockets; i++)
|
||||
{
|
||||
if (!showEquip[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var transform = &anim.KeyframePoses[animCurrentFrame][boneSocketIndex[i]];
|
||||
var inRotation = characterModel.Skeleton.BindPose[boneSocketIndex[i]].Rotation;
|
||||
var outRotation = transform->Rotation;
|
||||
|
||||
// Calculate socket rotation (angle between bone in initial pose and same bone in current animation frame)
|
||||
var rotate = QuaternionMultiply(outRotation, QuaternionInvert(inRotation));
|
||||
var matrixTransform = QuaternionToMatrix(rotate);
|
||||
// Translate socket to its position in the current animation
|
||||
matrixTransform = MatrixMultiply(matrixTransform, MatrixTranslate(transform->Translation.X, transform->Translation.Y, transform->Translation.Z));
|
||||
// Transform the socket using the transform of the character (angle and translate)
|
||||
matrixTransform = MatrixMultiply(matrixTransform, characterModel.Transform);
|
||||
|
||||
// Draw mesh at socket position with socket angle rotation
|
||||
DrawMesh(equipModel[i].Meshes[0], equipModel[i].Materials[1], matrixTransform);
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Use the T/G to switch animation", 10, 10, 20, Color.Gray);
|
||||
DrawText("Use the F/H to rotate character left/right", 10, 35, 20, Color.Gray);
|
||||
DrawText("Use the 1,2,3 to toggle shown of hat, sword and shield", 10, 60, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(modelAnimations, animsCount);
|
||||
UnloadModel(characterModel); // Unload character model and meshes/material
|
||||
|
||||
// Unload equipment model and meshes/material
|
||||
for (var i = 0; i < BoneSockets; i++)
|
||||
{
|
||||
UnloadModel(equipModel[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - bone socket");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BoneSocket();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,142 +1,179 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Detect basic 3d collisions (box vs sphere vs box)
|
||||
* raylib [models] example - box collisions
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 3.5
|
||||
*
|
||||
* 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class BoxCollisions
|
||||
public partial class BoxCollisions : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Box Collisions";
|
||||
|
||||
public string Title => "raylib [models] example - box collisions";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
private Vector3 playerPosition;
|
||||
private Vector3 playerSize;
|
||||
private Color playerColor;
|
||||
|
||||
private Vector3 enemyBoxPos;
|
||||
private Vector3 enemyBoxSize;
|
||||
|
||||
private Vector3 enemySpherePos;
|
||||
private float enemySphereSize;
|
||||
|
||||
private bool collision;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - box collisions");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
Vector3 playerPosition = new(0.0f, 1.0f, 2.0f);
|
||||
Vector3 playerSize = new(1.0f, 2.0f, 1.0f);
|
||||
Color playerColor = Color.Green;
|
||||
playerPosition = new(0.0f, 1.0f, 2.0f);
|
||||
playerSize = new(1.0f, 2.0f, 1.0f);
|
||||
playerColor = Color.Green;
|
||||
|
||||
Vector3 enemyBoxPos = new(-4.0f, 1.0f, 0.0f);
|
||||
Vector3 enemyBoxSize = new(2.0f, 2.0f, 2.0f);
|
||||
enemyBoxPos = new(-4.0f, 1.0f, 0.0f);
|
||||
enemyBoxSize = new(2.0f, 2.0f, 2.0f);
|
||||
|
||||
Vector3 enemySpherePos = new(4.0f, 0.0f, 0.0f);
|
||||
float enemySphereSize = 1.5f;
|
||||
enemySpherePos = new(4.0f, 0.0f, 0.0f);
|
||||
enemySphereSize = 1.5f;
|
||||
|
||||
bool collision = false;
|
||||
collision = false;
|
||||
}
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Move player
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
playerPosition.X += 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
playerPosition.X -= 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
playerPosition.Z += 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
playerPosition.Z -= 0.2f;
|
||||
}
|
||||
|
||||
collision = false;
|
||||
|
||||
// Check collisions player vs enemy-box
|
||||
BoundingBox box1 = new(
|
||||
playerPosition - (playerSize / 2),
|
||||
playerPosition + (playerSize / 2)
|
||||
);
|
||||
BoundingBox box2 = new(
|
||||
enemyBoxPos - (enemyBoxSize / 2),
|
||||
enemyBoxPos + (enemyBoxSize / 2)
|
||||
);
|
||||
|
||||
if (CheckCollisionBoxes(box1, box2))
|
||||
{
|
||||
collision = true;
|
||||
}
|
||||
|
||||
// Check collisions player vs enemy-sphere
|
||||
if (CheckCollisionBoxSphere(box1, enemySpherePos, enemySphereSize))
|
||||
{
|
||||
collision = true;
|
||||
}
|
||||
|
||||
if (collision)
|
||||
{
|
||||
playerColor = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
playerColor = Color.Green;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw enemy-box
|
||||
DrawCube(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, Color.Gray);
|
||||
DrawCubeWires(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, Color.DarkGray);
|
||||
|
||||
// Draw enemy-sphere
|
||||
DrawSphere(enemySpherePos, enemySphereSize, Color.Gray);
|
||||
DrawSphereWires(enemySpherePos, enemySphereSize, 16, 16, Color.DarkGray);
|
||||
|
||||
// Draw player
|
||||
DrawCubeV(playerPosition, playerSize, playerColor);
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Move player with arrow keys to collide", 220, 40, 20, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - box collisions");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BoxCollisions();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Move player
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
playerPosition.X += 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
playerPosition.X -= 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
playerPosition.Z += 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
playerPosition.Z -= 0.2f;
|
||||
}
|
||||
|
||||
collision = false;
|
||||
|
||||
// Check collisions player vs enemy-box
|
||||
BoundingBox box1 = new(
|
||||
playerPosition - (playerSize / 2),
|
||||
playerPosition + (playerSize / 2)
|
||||
);
|
||||
BoundingBox box2 = new(
|
||||
enemyBoxPos - (enemyBoxSize / 2),
|
||||
enemyBoxPos + (enemyBoxSize / 2)
|
||||
);
|
||||
|
||||
if (CheckCollisionBoxes(box1, box2))
|
||||
{
|
||||
collision = true;
|
||||
}
|
||||
|
||||
// Check collisions player vs enemy-sphere
|
||||
if (CheckCollisionBoxSphere(box1, enemySpherePos, enemySphereSize))
|
||||
{
|
||||
collision = true;
|
||||
}
|
||||
|
||||
if (collision)
|
||||
{
|
||||
playerColor = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
playerColor = Color.Green;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw enemy-box
|
||||
DrawCube(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, Color.Gray);
|
||||
DrawCubeWires(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, Color.DarkGray);
|
||||
|
||||
// Draw enemy-sphere
|
||||
DrawSphere(enemySpherePos, enemySphereSize, Color.Gray);
|
||||
DrawSphereWires(enemySpherePos, enemySphereSize, 16, 16, Color.DarkGray);
|
||||
|
||||
// Draw player
|
||||
DrawCubeV(playerPosition, playerSize, playerColor);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Move player with cursors to collide", 220, 40, 20, Color.Gray);
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,104 +1,142 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Cubicmap loading and drawing
|
||||
* raylib [models] example - cubicmap rendering
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.8, last time updated with raylib 3.5
|
||||
*
|
||||
* 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class CubicmapDemo
|
||||
public partial class CubicmapDemo : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Cubicmap Demo";
|
||||
|
||||
public string Title => "raylib [models] example - cubicmap rendering";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D cubicmap;
|
||||
private Texture2D texture;
|
||||
private Model model;
|
||||
private Vector3 mapPosition;
|
||||
private bool pause;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - cubesmap loading and drawing");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(16.0f, 14.0f, 16.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(16.0f, 14.0f, 16.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
Image image = LoadImage("resources/cubicmap.png");
|
||||
Texture2D cubicmap = LoadTextureFromImage(image);
|
||||
var image = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM)
|
||||
cubicmap = LoadTextureFromImage(image); // Convert image to texture to display (VRAM)
|
||||
|
||||
Mesh mesh = GenMeshCubicmap(image, new Vector3(1.0f, 1.0f, 1.0f));
|
||||
Model model = LoadModelFromMesh(mesh);
|
||||
var mesh = GenMeshCubicmap(image, new Vector3(1.0f, 1.0f, 1.0f));
|
||||
model = LoadModelFromMesh(mesh);
|
||||
|
||||
// NOTE: By default each cube is mapped to one part of texture atlas
|
||||
Texture2D texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture
|
||||
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 mapPosition = new(-16.0f, 0.0f, -8.0f);
|
||||
UnloadImage(image);
|
||||
mapPosition = new(-16.0f, 0.0f, -8.0f); // Set model position
|
||||
|
||||
SetTargetFPS(60);
|
||||
UnloadImage(image); // Unload cubesmap image from RAM, already uploaded to VRAM
|
||||
|
||||
pause = false; // Pause camera orbital rotation (and zoom)
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
}
|
||||
|
||||
if (!pause)
|
||||
{
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, mapPosition, 1.0f, Color.White);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
Vector2 position = new(screenWidth - cubicmap.Width * 4 - 20, 20);
|
||||
DrawTextureEx(cubicmap, position, 0.0f, 4.0f, Color.White);
|
||||
DrawRectangleLines(
|
||||
screenWidth - cubicmap.Width * 4 - 20,
|
||||
20,
|
||||
cubicmap.Width * 4,
|
||||
cubicmap.Height * 4,
|
||||
Color.Green
|
||||
);
|
||||
|
||||
DrawText("cubicmap image used to", 658, 90, 10, Color.Gray);
|
||||
DrawText("generate map 3d model", 658, 104, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(cubicmap); // Unload cubicmap texture
|
||||
UnloadTexture(texture); // Unload map texture
|
||||
UnloadModel(model); // Unload map model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - cubicmap rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new CubicmapDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, mapPosition, 1.0f, Color.White);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
Vector2 position = new(screenWidth - cubicmap.Width * 4 - 20, 20);
|
||||
DrawTextureEx(cubicmap, position, 0.0f, 4.0f, Color.White);
|
||||
DrawRectangleLines(
|
||||
screenWidth - cubicmap.Width * 4 - 20,
|
||||
20,
|
||||
cubicmap.Width * 4,
|
||||
cubicmap.Height * 4,
|
||||
Color.Green
|
||||
);
|
||||
|
||||
DrawText("cubicmap image used to", 658, 90, 10, Color.Gray);
|
||||
DrawText("generate map 3d model", 658, 104, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(cubicmap);
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
602
Examples/Models/Decals.cs
Normal file
602
Examples/Models/Decals.cs
Normal file
|
|
@ -0,0 +1,602 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - decals
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
|
||||
* Based on previous work by @mrdoob
|
||||
*
|
||||
* 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) 2025 JP Mortiboys (@themushroompirates) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class Decals : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxDecals = 256;
|
||||
|
||||
public string Name => "Models / Decals";
|
||||
|
||||
public string Title => "raylib [models] example - decals";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D modelTexture;
|
||||
private BoundingBox modelBBox;
|
||||
private float decalSize;
|
||||
private float decalOffset;
|
||||
private Model placementCube;
|
||||
private Material decalMaterial;
|
||||
private Texture2D decalTexture;
|
||||
private bool showModel;
|
||||
private readonly List<Model> decalModels = new();
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 5.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.6f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load character model
|
||||
model = LoadModel("resources/models/obj/character.obj");
|
||||
|
||||
// Apply character skin
|
||||
modelTexture = LoadTexture("resources/models/obj/character_diffuse.png");
|
||||
SetTextureFilter(modelTexture, TextureFilter.Bilinear);
|
||||
model.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = modelTexture;
|
||||
|
||||
modelBBox = GetMeshBoundingBox(model.Meshes[0]); // Get mesh bounding box
|
||||
|
||||
camera.Target = Vector3Lerp(modelBBox.Min, modelBBox.Max, 0.5f);
|
||||
camera.Position = modelBBox.Max * 1.0f;
|
||||
camera.Position.X *= 0.1f;
|
||||
|
||||
var modelSize = MathF.Min(
|
||||
MathF.Min(MathF.Abs(modelBBox.Max.X - modelBBox.Min.X), MathF.Abs(modelBBox.Max.Y - modelBBox.Min.Y)),
|
||||
MathF.Abs(modelBBox.Max.Z - modelBBox.Min.Z));
|
||||
|
||||
camera.Position = new Vector3(0.0f, modelBBox.Max.Y * 1.2f, modelSize * 3.0f);
|
||||
|
||||
decalSize = modelSize * 0.25f;
|
||||
decalOffset = 0.01f;
|
||||
|
||||
placementCube = LoadModelFromMesh(GenMeshCube(decalSize, decalSize, decalSize));
|
||||
placementCube.Materials[0].Maps[0].Color = Color.Lime;
|
||||
|
||||
decalMaterial = LoadMaterialDefault();
|
||||
decalMaterial.Maps[0].Color = Color.Yellow;
|
||||
|
||||
var decalImage = LoadImage("resources/raylib_logo.png");
|
||||
ImageResizeNN(ref decalImage, decalImage.Width / 4, decalImage.Height / 4);
|
||||
decalTexture = LoadTextureFromImage(decalImage);
|
||||
UnloadImage(decalImage);
|
||||
|
||||
SetTextureFilter(decalTexture, TextureFilter.Bilinear);
|
||||
decalMaterial.Maps[(int)MaterialMapIndex.Diffuse].Texture = decalTexture;
|
||||
decalMaterial.Maps[(int)MaterialMapIndex.Diffuse].Color = Color.RayWhite;
|
||||
|
||||
showModel = true;
|
||||
decalModels.Clear();
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
UpdateCamera(ref camera, CameraMode.ThirdPerson);
|
||||
}
|
||||
|
||||
// Display information about closest hit
|
||||
RayCollision collision = new();
|
||||
collision.Distance = float.MaxValue;
|
||||
collision.Hit = false;
|
||||
|
||||
// Get mouse ray
|
||||
var ray = GetScreenToWorldRay(GetMousePosition(), camera);
|
||||
|
||||
// Check ray collision against bounding box first, before trying the full ray-mesh test
|
||||
var boxHitInfo = GetRayCollisionBox(ray, modelBBox);
|
||||
|
||||
RayCollision meshHitInfo = new();
|
||||
if (boxHitInfo.Hit && (decalModels.Count < MaxDecals))
|
||||
{
|
||||
// Check ray collision against model meshes
|
||||
for (var m = 0; m < model.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 = GetRayCollisionMesh(ray, model.Meshes[m], model.Transform);
|
||||
if (meshHitInfo.Hit)
|
||||
{
|
||||
// Save the closest hit mesh
|
||||
if (!collision.Hit || (collision.Distance > meshHitInfo.Distance))
|
||||
{
|
||||
collision = meshHitInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (meshHitInfo.Hit)
|
||||
{
|
||||
collision = meshHitInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Add decal to mesh on hit point
|
||||
if (collision.Hit && IsMouseButtonPressed(MouseButton.Left) && (decalModels.Count < MaxDecals))
|
||||
{
|
||||
// Create the transformation to project the decal
|
||||
var origin = collision.Point + (collision.Normal * 1.0f);
|
||||
var splat = MatrixLookAt(collision.Point, origin, new Vector3(0.0f, 1.0f, 0.0f));
|
||||
|
||||
// Spin the placement around a bit
|
||||
splat = MatrixMultiply(splat, MatrixRotateZ(DEG2RAD * GetRandomValue(-180, 180)));
|
||||
|
||||
var decalMesh = GenMeshDecal(model, splat, decalSize, decalOffset);
|
||||
|
||||
if (decalMesh.VertexCount > 0)
|
||||
{
|
||||
var decalModel = LoadModelFromMesh(decalMesh);
|
||||
decalModel.Materials[0].Maps[0] = decalMaterial.Maps[0];
|
||||
decalModels.Add(decalModel);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw the model at the origin and default scale
|
||||
if (showModel)
|
||||
{
|
||||
DrawModel(model, new Vector3(0.0f, 0.0f, 0.0f), 1.0f, Color.White);
|
||||
}
|
||||
|
||||
// Draw the decal models
|
||||
for (var i = 0; i < decalModels.Count; i++)
|
||||
{
|
||||
DrawModel(decalModels[i], Vector3.Zero, 1.0f, Color.White);
|
||||
}
|
||||
|
||||
// If we hit the mesh, draw the box for the decal
|
||||
if (collision.Hit)
|
||||
{
|
||||
var origin = collision.Point + (collision.Normal * 1.0f);
|
||||
var splat = MatrixLookAt(collision.Point, origin, new Vector3(0, 1, 0));
|
||||
placementCube.Transform = MatrixInvert(splat);
|
||||
DrawModel(placementCube, Vector3.Zero, 1.0f, Fade(Color.White, 0.5f));
|
||||
}
|
||||
|
||||
DrawGrid(10, 10.0f);
|
||||
EndMode3D();
|
||||
|
||||
float yPos = 10;
|
||||
var x0 = GetScreenWidth() - 300.0f;
|
||||
var x1 = x0 + 100;
|
||||
var x2 = x1 + 100;
|
||||
|
||||
DrawText("Vertices", (int)x1, (int)yPos, 10, Color.Lime);
|
||||
DrawText("Triangles", (int)x2, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
|
||||
var vertexCount = 0;
|
||||
var triangleCount = 0;
|
||||
|
||||
for (var i = 0; i < model.MeshCount; i++)
|
||||
{
|
||||
vertexCount += model.Meshes[i].VertexCount;
|
||||
triangleCount += model.Meshes[i].TriangleCount;
|
||||
}
|
||||
|
||||
DrawText("Main model", (int)x0, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{vertexCount}", (int)x1, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{triangleCount}", (int)x2, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
|
||||
for (var i = 0; i < decalModels.Count; i++)
|
||||
{
|
||||
if (i == 20)
|
||||
{
|
||||
DrawText("...", (int)x0, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
}
|
||||
|
||||
if (i < 20)
|
||||
{
|
||||
DrawText($"Decal #{i + 1}", (int)x0, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{decalModels[i].Meshes[0].VertexCount}", (int)x1, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{decalModels[i].Meshes[0].TriangleCount}", (int)x2, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
}
|
||||
|
||||
vertexCount += decalModels[i].Meshes[0].VertexCount;
|
||||
triangleCount += decalModels[i].Meshes[0].TriangleCount;
|
||||
}
|
||||
|
||||
DrawText("TOTAL", (int)x0, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{vertexCount}", (int)x1, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{triangleCount}", (int)x2, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
|
||||
DrawText("Hold RMB to move camera", 10, 430, 10, Color.Gray);
|
||||
DrawText("(c) Character model and texture from kenney.nl", screenWidth - 260, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
// UI elements
|
||||
if (GuiButton(new Rectangle(10, screenHeight - 1000.0f, 100, 60), showModel ? "Hide Model" : "Show Model"))
|
||||
{
|
||||
showModel = !showModel;
|
||||
}
|
||||
|
||||
if (GuiButton(new Rectangle(10 + 110, screenHeight - 100.0f, 100, 60), "Clear Decals"))
|
||||
{
|
||||
// Clear decals, unload all decal models
|
||||
for (var i = 0; i < decalModels.Count; i++)
|
||||
{
|
||||
UnloadModel(decalModels[i]);
|
||||
}
|
||||
decalModels.Clear();
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(model);
|
||||
UnloadTexture(modelTexture);
|
||||
|
||||
// Unload decal models
|
||||
for (var i = 0; i < decalModels.Count; i++)
|
||||
{
|
||||
UnloadModel(decalModels[i]);
|
||||
}
|
||||
decalModels.Clear();
|
||||
|
||||
UnloadTexture(decalTexture);
|
||||
UnloadModel(placementCube);
|
||||
}
|
||||
|
||||
// Clip segment
|
||||
private static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s)
|
||||
{
|
||||
var d0 = Vector3.Dot(v0, p) - s;
|
||||
var d1 = Vector3.Dot(v1, p) - s;
|
||||
var s0 = d0 / (d0 - d1);
|
||||
|
||||
return Vector3.Lerp(v0, v1, s0);
|
||||
}
|
||||
|
||||
// Generate mesh decals for provided model
|
||||
private static unsafe Mesh GenMeshDecal(Model target, Matrix4x4 projection, float decalSize, float decalOffset)
|
||||
{
|
||||
// We're going to use these to build up our decal meshes
|
||||
var meshBuilders = new List<Vector3>[2] { new(), new() };
|
||||
|
||||
// We're going to need the inverse matrix
|
||||
var invProj = MatrixInvert(projection);
|
||||
|
||||
// We'll be flip-flopping between the two mesh builders
|
||||
// Reading from one and writing to the other, then swapping
|
||||
var mbIndex = 0;
|
||||
|
||||
// First pass, just get any triangle inside the bounding box (for each mesh of the model)
|
||||
for (var meshIndex = 0; meshIndex < target.MeshCount; meshIndex++)
|
||||
{
|
||||
var mesh = target.Meshes[meshIndex];
|
||||
for (var tri = 0; tri < mesh.TriangleCount; tri++)
|
||||
{
|
||||
var vertices = new Vector3[3];
|
||||
|
||||
// The way we calculate the vertices of the mesh triangle
|
||||
// depend on whether the mesh vertices are indexed or not
|
||||
if (mesh.Indices == null)
|
||||
{
|
||||
for (var v = 0; v < 3; v++)
|
||||
{
|
||||
vertices[v] = new Vector3(
|
||||
mesh.Vertices[3 * 3 * tri + 3 * v + 0],
|
||||
mesh.Vertices[3 * 3 * tri + 3 * v + 1],
|
||||
mesh.Vertices[3 * 3 * tri + 3 * v + 2]
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var v = 0; v < 3; v++)
|
||||
{
|
||||
vertices[v] = new Vector3(
|
||||
mesh.Vertices[3 * mesh.Indices[3 * tri + 0] + v],
|
||||
mesh.Vertices[3 * mesh.Indices[3 * tri + 1] + v],
|
||||
mesh.Vertices[3 * mesh.Indices[3 * tri + 2] + v]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Transform all 3 vertices of the triangle
|
||||
// and check if they are inside our decal box
|
||||
var insideCount = 0;
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
// To projection space
|
||||
var v = Vector3Transform(vertices[i], projection);
|
||||
|
||||
if ((MathF.Abs(v.X) < decalSize) || (MathF.Abs(v.Y) <= decalSize) || (MathF.Abs(v.Z) <= decalSize))
|
||||
{
|
||||
insideCount++;
|
||||
}
|
||||
|
||||
// We need to keep the transformed vertex
|
||||
vertices[i] = v;
|
||||
}
|
||||
|
||||
// If any of them are inside, we add the triangle - we'll clip it later
|
||||
if (insideCount > 0)
|
||||
{
|
||||
meshBuilders[mbIndex].Add(vertices[0]);
|
||||
meshBuilders[mbIndex].Add(vertices[1]);
|
||||
meshBuilders[mbIndex].Add(vertices[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clipping time! We need to clip against all 6 directions
|
||||
Vector3[] planes =
|
||||
{
|
||||
new(1, 0, 0),
|
||||
new(-1, 0, 0),
|
||||
new(0, 1, 0),
|
||||
new(0, -1, 0),
|
||||
new(0, 0, 1),
|
||||
new(0, 0, -1)
|
||||
};
|
||||
|
||||
for (var face = 0; face < 6; face++)
|
||||
{
|
||||
// Swap current model builder (so we read from the one we just wrote to)
|
||||
mbIndex = 1 - mbIndex;
|
||||
|
||||
var inMesh = meshBuilders[1 - mbIndex];
|
||||
var outMesh = meshBuilders[mbIndex];
|
||||
|
||||
// Reset write builder
|
||||
outMesh.Clear();
|
||||
|
||||
var s = 0.5f * decalSize;
|
||||
|
||||
for (var i = 0; i < inMesh.Count; i += 3)
|
||||
{
|
||||
Vector3 nV1, nV2, nV3, nV4;
|
||||
|
||||
var d1 = Vector3.Dot(inMesh[i + 0], planes[face]) - s;
|
||||
var d2 = Vector3.Dot(inMesh[i + 1], planes[face]) - s;
|
||||
var d3 = Vector3.Dot(inMesh[i + 2], planes[face]) - s;
|
||||
|
||||
var v1Out = d1 > 0;
|
||||
var v2Out = d2 > 0;
|
||||
var v3Out = d3 > 0;
|
||||
|
||||
// Calculate, how many vertices of the face lie outside of the clipping plane
|
||||
var total = (v1Out ? 1 : 0) + (v2Out ? 1 : 0) + (v3Out ? 1 : 0);
|
||||
|
||||
switch (total)
|
||||
{
|
||||
case 0:
|
||||
// The entire face lies inside of the plane, no clipping needed
|
||||
outMesh.Add(inMesh[i]);
|
||||
outMesh.Add(inMesh[i + 1]);
|
||||
outMesh.Add(inMesh[i + 2]);
|
||||
break;
|
||||
case 1:
|
||||
// One vertex lies outside of the plane, perform clipping
|
||||
if (v2Out)
|
||||
{
|
||||
nV1 = inMesh[i];
|
||||
nV2 = inMesh[i + 2];
|
||||
nV3 = ClipSegment(inMesh[i + 1], nV1, planes[face], s);
|
||||
nV4 = ClipSegment(inMesh[i + 1], nV2, planes[face], s);
|
||||
|
||||
outMesh.Add(nV3);
|
||||
outMesh.Add(nV2);
|
||||
outMesh.Add(nV1);
|
||||
outMesh.Add(nV2);
|
||||
outMesh.Add(nV3);
|
||||
outMesh.Add(nV4);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v1Out)
|
||||
{
|
||||
nV1 = inMesh[i + 1];
|
||||
nV2 = inMesh[i + 2];
|
||||
nV3 = ClipSegment(inMesh[i], nV1, planes[face], s);
|
||||
nV4 = ClipSegment(inMesh[i], nV2, planes[face], s);
|
||||
}
|
||||
else // v3Out
|
||||
{
|
||||
nV1 = inMesh[i];
|
||||
nV2 = inMesh[i + 1];
|
||||
nV3 = ClipSegment(inMesh[i + 2], nV1, planes[face], s);
|
||||
nV4 = ClipSegment(inMesh[i + 2], nV2, planes[face], s);
|
||||
}
|
||||
|
||||
outMesh.Add(nV1);
|
||||
outMesh.Add(nV2);
|
||||
outMesh.Add(nV3);
|
||||
outMesh.Add(nV4);
|
||||
outMesh.Add(nV3);
|
||||
outMesh.Add(nV2);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Two vertices lies outside of the plane, perform clipping
|
||||
if (!v1Out)
|
||||
{
|
||||
nV1 = inMesh[i];
|
||||
nV2 = ClipSegment(nV1, inMesh[i + 1], planes[face], s);
|
||||
nV3 = ClipSegment(nV1, inMesh[i + 2], planes[face], s);
|
||||
outMesh.Add(nV1);
|
||||
outMesh.Add(nV2);
|
||||
outMesh.Add(nV3);
|
||||
}
|
||||
|
||||
if (!v2Out)
|
||||
{
|
||||
nV1 = inMesh[i + 1];
|
||||
nV2 = ClipSegment(nV1, inMesh[i + 2], planes[face], s);
|
||||
nV3 = ClipSegment(nV1, inMesh[i], planes[face], s);
|
||||
outMesh.Add(nV1);
|
||||
outMesh.Add(nV2);
|
||||
outMesh.Add(nV3);
|
||||
}
|
||||
|
||||
if (!v3Out)
|
||||
{
|
||||
nV1 = inMesh[i + 2];
|
||||
nV2 = ClipSegment(nV1, inMesh[i], planes[face], s);
|
||||
nV3 = ClipSegment(nV1, inMesh[i + 1], planes[face], s);
|
||||
outMesh.Add(nV1);
|
||||
outMesh.Add(nV2);
|
||||
outMesh.Add(nV3);
|
||||
}
|
||||
break;
|
||||
default: // The entire face lies outside of the plane, so let's discard the corresponding vertices
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we just need to re-transform the vertices
|
||||
var theMesh = meshBuilders[mbIndex];
|
||||
|
||||
// Allocate room for UVs
|
||||
if (theMesh.Count > 0)
|
||||
{
|
||||
var uvs = new Vector2[theMesh.Count];
|
||||
|
||||
for (var i = 0; i < theMesh.Count; i++)
|
||||
{
|
||||
var vert = theMesh[i];
|
||||
|
||||
// Calculate the UVs based on the projected coords
|
||||
// They are clipped to (-decalSize .. decalSize) and we want them (0..1)
|
||||
uvs[i] = new Vector2(vert.X / decalSize + 0.5f, vert.Y / decalSize + 0.5f);
|
||||
|
||||
// Tiny nudge in the normal direction so it renders properly over the mesh
|
||||
vert.Z -= decalOffset;
|
||||
|
||||
// From projection space to world space
|
||||
theMesh[i] = Vector3Transform(vert, invProj);
|
||||
}
|
||||
|
||||
// Decal model data ready, create the mesh and return it
|
||||
return BuildMesh(theMesh, uvs);
|
||||
}
|
||||
|
||||
// Return a blank mesh as there's nothing to add
|
||||
return new Mesh();
|
||||
}
|
||||
|
||||
// Build a Mesh from builder data
|
||||
private static unsafe Mesh BuildMesh(List<Vector3> builderVertices, Vector2[] uvs)
|
||||
{
|
||||
Mesh outMesh = new(builderVertices.Count, builderVertices.Count / 3);
|
||||
outMesh.AllocVertices();
|
||||
outMesh.AllocTexCoords();
|
||||
|
||||
var vertices = outMesh.VerticesAs<Vector3>();
|
||||
var texcoords = outMesh.TexCoordsAs<Vector2>();
|
||||
|
||||
for (var i = 0; i < builderVertices.Count; i++)
|
||||
{
|
||||
vertices[i] = builderVertices[i];
|
||||
texcoords[i] = uvs[i];
|
||||
}
|
||||
|
||||
UploadMesh(ref outMesh, false);
|
||||
|
||||
return outMesh;
|
||||
}
|
||||
|
||||
// Button UI element
|
||||
private static bool GuiButton(Rectangle rec, string label)
|
||||
{
|
||||
var bgColor = Color.Gray;
|
||||
var pressed = false;
|
||||
|
||||
if (CheckCollisionPointRec(GetMousePosition(), rec))
|
||||
{
|
||||
bgColor = Color.LightGray;
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
DrawRectangleRec(rec, bgColor);
|
||||
DrawRectangleLinesEx(rec, 2.0f, Color.DarkGray);
|
||||
|
||||
var fontSize = 10;
|
||||
var textWidth = MeasureText(label, fontSize);
|
||||
|
||||
DrawText(label, (int)(rec.X + rec.Width * 0.5f - textWidth * 0.5f), (int)(rec.Y + rec.Height * 0.5f - fontSize * 0.5f), fontSize, Color.DarkGray);
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - decals");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Decals();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
145
Examples/Models/DirectionalBillboard.cs
Normal file
145
Examples/Models/DirectionalBillboard.cs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - directional billboard
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Robin (@RobinsAviary) 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) 2025 Robin (@RobinsAviary)
|
||||
* Killbot art by patvanmackelberg https://opengameart.org/content/killbot-8-directional under CC0
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class DirectionalBillboard : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Directional Billboard";
|
||||
|
||||
public string Title => "raylib [models] example - directional billboard";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D skillbot;
|
||||
private float animTimer;
|
||||
private uint anim;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Set up the camera
|
||||
camera = new();
|
||||
camera.Position = new Vector3(2.0f, 1.0f, 2.0f); // Starting position
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 0.0f); // Target position
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Up vector
|
||||
camera.FovY = 45.0f; // FOV
|
||||
camera.Projection = CameraProjection.Perspective; // Projection type (Standard 3D perspective)
|
||||
|
||||
// Load billboard texture
|
||||
skillbot = LoadTexture("resources/skillbot.png");
|
||||
|
||||
// Timer to update animation
|
||||
animTimer = 0.0f;
|
||||
// Animation frame
|
||||
anim = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Update timer with delta time
|
||||
animTimer += GetFrameTime();
|
||||
|
||||
// Update frame index after a certain amount of time (half a second)
|
||||
if (animTimer > 0.5f)
|
||||
{
|
||||
animTimer = 0.0f;
|
||||
anim += 1;
|
||||
}
|
||||
|
||||
// Reset frame index to zero on overflow
|
||||
if (anim >= 4)
|
||||
{
|
||||
anim = 0;
|
||||
}
|
||||
|
||||
// Find the current direction frame based on the camera position to the billboard object
|
||||
var dir = (float)Math.Floor(((Vector2Angle(new Vector2(2.0f, 0.0f), new Vector2(camera.Position.X, camera.Position.Z)) / MathF.PI) * 4.0f) + 0.25f);
|
||||
|
||||
// Correct frame index if angle is negative
|
||||
if (dir < 0.0f)
|
||||
{
|
||||
dir = 8.0f - Math.Abs((int)dir);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Draw billboard pointing straight up to the sky, rotated relative to the camera and offset from the bottom
|
||||
DrawBillboardPro(camera, skillbot, new Rectangle(0.0f + (anim * 24.0f), 0.0f + (dir * 24.0f), 24.0f, 24.0f),
|
||||
Vector3.Zero, new Vector3(0.0f, 1.0f, 0.0f), Vector2.One, new Vector2(0.5f, 0.0f), 0, Color.White);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Render various variables for reference
|
||||
DrawText($"animation: {anim}", 10, 10, 20, Color.DarkGray);
|
||||
DrawText($"direction frame: {dir:0}", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// Unload billboard texture
|
||||
UnloadTexture(skillbot);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - directional billboard");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DirectionalBillboard();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,27 @@
|
|||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class DynamicMesh
|
||||
public partial class DynamicMesh : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int triangleRows = 48;
|
||||
private const int vertexRows = triangleRows + 1;
|
||||
|
||||
public string Name => "Models / Dynamic Mesh";
|
||||
|
||||
public string Title => "raylib [models] example - dynamic mesh";
|
||||
|
||||
private Camera3D camera;
|
||||
private Mesh dynamicMesh;
|
||||
private Texture2D texture;
|
||||
private Color[] pixels;
|
||||
private Material material;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - dynamic mesh");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = Vector3.One * 1.5f;
|
||||
camera.Target = camera.Position + new Vector3(1f, -0.25f, 1f);
|
||||
camera.Up = Vector3.UnitY;
|
||||
|
|
@ -23,18 +29,14 @@ public class DynamicMesh
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Generate a dynamic mesh using utils to allocate/access mesh attribute data
|
||||
const int triangleRows = 48;
|
||||
const int vertexRows = triangleRows + 1;
|
||||
Mesh dynamicMesh = new(vertexRows * vertexRows, triangleRows * triangleRows * 2);
|
||||
dynamicMesh = new(vertexRows * vertexRows, triangleRows * triangleRows * 2);
|
||||
dynamicMesh.AllocVertices();
|
||||
dynamicMesh.AllocTexCoords();
|
||||
dynamicMesh.AllocIndices();
|
||||
Span<Vector3> vertices = dynamicMesh.VerticesAs<Vector3>();
|
||||
Span<Vector2> texcoords = dynamicMesh.TexCoordsAs<Vector2>();
|
||||
Span<ushort> indices = dynamicMesh.IndicesAs<ushort>();
|
||||
var indices = dynamicMesh.IndicesAs<ushort>();
|
||||
for (int z = 0, i = 0; z < triangleRows; z++)
|
||||
{
|
||||
for (int x = 0; x < triangleRows; x++, i += 6)
|
||||
for (var x = 0; x < triangleRows; x++, i += 6)
|
||||
{
|
||||
indices[i + 0] = (ushort)(x + (z * vertexRows));
|
||||
indices[i + 1] = (ushort)(indices[i] + vertexRows);
|
||||
|
|
@ -47,73 +49,96 @@ public class DynamicMesh
|
|||
UploadMesh(ref dynamicMesh, true);
|
||||
|
||||
// Allocate the texture
|
||||
Image image = GenImageColor(triangleRows, triangleRows, Color.Blank);
|
||||
Texture2D texture = LoadTextureFromImage(image);
|
||||
Color[] pixels = new Color[texture.Width * texture.Height];
|
||||
var image = GenImageColor(triangleRows, triangleRows, Color.Blank);
|
||||
texture = LoadTextureFromImage(image);
|
||||
pixels = new Color[texture.Width * texture.Height];
|
||||
UnloadImage(image);
|
||||
|
||||
// Load the material
|
||||
Material material = LoadMaterialDefault();
|
||||
material = LoadMaterialDefault();
|
||||
SetMaterialTexture(ref material, MaterialMapIndex.Diffuse, texture);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var time = (float)GetTime();
|
||||
Random random = new(42);
|
||||
|
||||
var vertices = dynamicMesh.VerticesAs<Vector3>();
|
||||
var texcoords = dynamicMesh.TexCoordsAs<Vector2>();
|
||||
|
||||
for (int z = 0, i = 0; z < vertexRows; z++)
|
||||
{
|
||||
for (var x = 0; x < vertexRows; x++, i++)
|
||||
{
|
||||
var noiseX = SmoothNoise(time + random.Next(10000));
|
||||
var noiseZ = SmoothNoise(time + random.Next(10000));
|
||||
vertices[i].X = x + noiseX - .5f;
|
||||
vertices[i].Y = (noiseX + noiseZ) / 2;
|
||||
vertices[i].Z = z + noiseZ - .5f;
|
||||
texcoords[i].X = (x - noiseZ) / triangleRows;
|
||||
texcoords[i].Y = (z - noiseX) / triangleRows;
|
||||
}
|
||||
}
|
||||
UpdateMeshBuffer<Vector3>(dynamicMesh, Mesh.VboIdIndexVertices, vertices, 0);
|
||||
UpdateMeshBuffer<Vector2>(dynamicMesh, Mesh.VboIdIndexTexCoords, texcoords, 0);
|
||||
|
||||
for (int y = 0, i = 0; y < texture.Height; y++)
|
||||
{
|
||||
for (var x = 0; x < texture.Width; x++, i++)
|
||||
{
|
||||
pixels[i] = new(32, 178, 170, 255);
|
||||
pixels[i] = ColorBrightness(pixels[i], (SmoothNoise(time + random.Next(10000)) / 8) - (1 / 16f));
|
||||
pixels[i] = ColorAlpha(pixels[i], (triangleRows - new Vector2(x, y).Length()) / triangleRows);
|
||||
}
|
||||
}
|
||||
UpdateTexture(texture, pixels);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawMesh(dynamicMesh, material, Matrix4x4.Identity);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMaterial(material);
|
||||
// Raylib.UnloadTexture(texture); <- No need to unload the texture. UnloadMaterial(Material) already unloaded it for us
|
||||
UnloadMesh(dynamicMesh);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - dynamic mesh");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DynamicMesh();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
float time = (float)GetTime();
|
||||
Random random = new(42);
|
||||
|
||||
for (int z = 0, i = 0; z < vertexRows; z++)
|
||||
{
|
||||
for (int x = 0; x < vertexRows; x++, i++)
|
||||
{
|
||||
float noiseX = SmoothNoise(time + random.Next(10000));
|
||||
float noiseZ = SmoothNoise(time + random.Next(10000));
|
||||
vertices[i].X = x + noiseX - .5f;
|
||||
vertices[i].Y = (noiseX + noiseZ) / 2;
|
||||
vertices[i].Z = z + noiseZ - .5f;
|
||||
texcoords[i].X = (x - noiseZ) / triangleRows;
|
||||
texcoords[i].Y = (z - noiseX) / triangleRows;
|
||||
}
|
||||
}
|
||||
UpdateMeshBuffer<Vector3>(dynamicMesh, Mesh.VboIdIndexVertices, vertices, 0);
|
||||
UpdateMeshBuffer<Vector2>(dynamicMesh, Mesh.VboIdIndexTexCoords, texcoords, 0);
|
||||
|
||||
for (int y = 0, i = 0; y < texture.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < texture.Width; x++, i++)
|
||||
{
|
||||
pixels[i] = new(32, 178, 170, 255);
|
||||
pixels[i] = ColorBrightness(pixels[i], (SmoothNoise(time + random.Next(10000)) / 8) - (1 / 16f));
|
||||
pixels[i] = ColorAlpha(pixels[i], (triangleRows - new Vector2(x, y).Length()) / triangleRows);
|
||||
}
|
||||
}
|
||||
UpdateTexture(texture, pixels);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawMesh(dynamicMesh, material, Matrix4x4.Identity);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadMaterial(material);
|
||||
// Raylib.UnloadTexture(texture); <- No need to unload the texture. UnloadMaterial(Material) already unloaded it for us
|
||||
UnloadMesh(dynamicMesh);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -2,152 +2,176 @@
|
|||
*
|
||||
* raylib [models] example - first person maze
|
||||
*
|
||||
* This example has been created using raylib 2.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2019 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 3.5
|
||||
*
|
||||
* 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) 2019-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class FirstPersonMaze
|
||||
public unsafe partial class FirstPersonMaze : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / First Person Maze";
|
||||
|
||||
public string Title => "raylib [models] example - first person maze";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D cubicmap;
|
||||
private Texture2D texture;
|
||||
private Model model;
|
||||
private Color* mapPixels;
|
||||
private Vector3 mapPosition;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - first person maze");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(0.2f, 0.4f, 0.2f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.2f, 0.4f, 0.2f); // Camera position
|
||||
camera.Target = new Vector3(0.185f, 0.4f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
Image imMap = LoadImage("resources/cubicmap.png");
|
||||
Texture2D cubicmap = LoadTextureFromImage(imMap);
|
||||
Mesh mesh = GenMeshCubicmap(imMap, new Vector3(1.0f, 1.0f, 1.0f));
|
||||
Model model = LoadModelFromMesh(mesh);
|
||||
var imMap = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM)
|
||||
cubicmap = LoadTextureFromImage(imMap); // Convert image to texture to display (VRAM)
|
||||
var mesh = GenMeshCubicmap(imMap, new Vector3(1.0f, 1.0f, 1.0f));
|
||||
model = LoadModelFromMesh(mesh);
|
||||
|
||||
// NOTE: By default each cube is mapped to one part of texture atlas
|
||||
Texture2D texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture
|
||||
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
// Get map image data to be used for collision detection
|
||||
Color* mapPixels = LoadImageColors(imMap);
|
||||
UnloadImage(imMap);
|
||||
mapPixels = LoadImageColors(imMap);
|
||||
UnloadImage(imMap); // Unload image from RAM
|
||||
|
||||
Vector3 mapPosition = new(-16.0f, 0.0f, -8.0f);
|
||||
Vector3 playerPosition = camera.Position;
|
||||
mapPosition = new(-16.0f, 0.0f, -8.0f); // Set model position
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var oldCamPos = camera.Position; // Store old camera position
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
|
||||
// Check player collision (we simplify to 2D collision detection)
|
||||
Vector2 playerPos = new(camera.Position.X, camera.Position.Z);
|
||||
var playerRadius = 0.1f; // Collision radius (player is modelled as a cilinder for collision)
|
||||
|
||||
var playerCellX = (int)(playerPos.X - mapPosition.X + 0.5f);
|
||||
var playerCellY = (int)(playerPos.Y - mapPosition.Z + 0.5f);
|
||||
|
||||
// Out-of-limits security check
|
||||
if (playerCellX < 0)
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
Vector3 oldCamPos = camera.Position;
|
||||
playerCellX = 0;
|
||||
}
|
||||
else if (playerCellX >= cubicmap.Width)
|
||||
{
|
||||
playerCellX = cubicmap.Width - 1;
|
||||
}
|
||||
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
if (playerCellY < 0)
|
||||
{
|
||||
playerCellY = 0;
|
||||
}
|
||||
else if (playerCellY >= cubicmap.Height)
|
||||
{
|
||||
playerCellY = cubicmap.Height - 1;
|
||||
}
|
||||
|
||||
// Check player collision (we simplify to 2D collision detection)
|
||||
Vector2 playerPos = new(camera.Position.X, camera.Position.Z);
|
||||
|
||||
// Collision radius (player is modelled as a cilinder for collision)
|
||||
float playerRadius = 0.1f;
|
||||
|
||||
int playerCellX = (int)(playerPos.X - mapPosition.X + 0.5f);
|
||||
int playerCellY = (int)(playerPos.Y - mapPosition.Z + 0.5f);
|
||||
|
||||
// Out-of-limits security check
|
||||
if (playerCellX < 0)
|
||||
// Check map collisions using image data and player position against surrounding cells only
|
||||
for (var y = playerCellY - 1; y <= playerCellY + 1; y++)
|
||||
{
|
||||
// Avoid map accessing out of bounds
|
||||
if ((y >= 0) && (y < cubicmap.Height))
|
||||
{
|
||||
playerCellX = 0;
|
||||
}
|
||||
else if (playerCellX >= cubicmap.Width)
|
||||
{
|
||||
playerCellX = cubicmap.Width - 1;
|
||||
}
|
||||
|
||||
if (playerCellY < 0)
|
||||
{
|
||||
playerCellY = 0;
|
||||
}
|
||||
else if (playerCellY >= cubicmap.Height)
|
||||
{
|
||||
playerCellY = cubicmap.Height - 1;
|
||||
}
|
||||
|
||||
// Check map collisions using image data and player position
|
||||
// TODO: Improvement: Just check player surrounding cells for collision
|
||||
for (int y = 0; y < cubicmap.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < cubicmap.Width; x++)
|
||||
for (var x = playerCellX - 1; x <= playerCellX + 1; x++)
|
||||
{
|
||||
Color* mapPixelsData = mapPixels;
|
||||
|
||||
// Collision: Color.white pixel, only check R channel
|
||||
Rectangle rec = new(
|
||||
mapPosition.X - 0.5f + x * 1.0f,
|
||||
mapPosition.Z - 0.5f + y * 1.0f,
|
||||
1.0f,
|
||||
1.0f
|
||||
);
|
||||
|
||||
bool collision = CheckCollisionCircleRec(playerPos, playerRadius, rec);
|
||||
if ((mapPixelsData[y * cubicmap.Width + x].R == 255) && collision)
|
||||
// NOTE: Collision: Only checking R channel for white pixel
|
||||
if (((x >= 0) && (x < cubicmap.Width)) &&
|
||||
(mapPixels[y * cubicmap.Width + x].R == 255) &&
|
||||
(CheckCollisionCircleRec(playerPos, playerRadius,
|
||||
new Rectangle(mapPosition.X - 0.5f + x * 1.0f, mapPosition.Z - 0.5f + y * 1.0f, 1.0f, 1.0f))))
|
||||
{
|
||||
// Collision detected, reset camera position
|
||||
camera.Position = oldCamPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw maze map
|
||||
BeginMode3D(camera);
|
||||
DrawModel(model, mapPosition, 1.0f, Color.White);
|
||||
EndMode3D();
|
||||
|
||||
DrawTextureEx(cubicmap, new Vector2(GetScreenWidth() - cubicmap.Width * 4 - 20, 20), 0.0f, 4.0f, Color.White);
|
||||
DrawRectangleLines(GetScreenWidth() - cubicmap.Width * 4 - 20, 20, cubicmap.Width * 4, cubicmap.Height * 4, Color.Green);
|
||||
|
||||
// Draw player position radar
|
||||
DrawRectangle(GetScreenWidth() - cubicmap.Width * 4 - 20 + playerCellX * 4, 20 + playerCellY * 4, 4, 4, Color.Red);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawModel(model, mapPosition, 1.0f, Color.White); // Draw maze map
|
||||
EndMode3D();
|
||||
|
||||
DrawTextureEx(cubicmap, new Vector2(GetScreenWidth() - cubicmap.Width * 4 - 20, 20), 0.0f, 4.0f, Color.White);
|
||||
DrawRectangleLines(GetScreenWidth() - cubicmap.Width * 4 - 20, 20, cubicmap.Width * 4, cubicmap.Height * 4, Color.Green);
|
||||
|
||||
// Draw player position radar
|
||||
DrawRectangle(GetScreenWidth() - cubicmap.Width * 4 - 20 + playerCellX * 4, 20 + playerCellY * 4, 4, 4, Color.Red);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadImageColors(mapPixels); // Unload color array
|
||||
|
||||
UnloadTexture(cubicmap); // Unload cubicmap texture
|
||||
UnloadTexture(texture); // Unload map texture
|
||||
UnloadModel(model); // Unload map model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - first person maze");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new FirstPersonMaze();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadImageColors(mapPixels);
|
||||
|
||||
UnloadTexture(cubicmap);
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,83 +1,105 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Draw some basic geometric shapes (cube, sphere, cylinder...)
|
||||
* raylib [models] example - geometric shapes
|
||||
*
|
||||
* This example has been created using raylib 1.0 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Copyright (c) 2014 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.0, last time updated with raylib 3.5
|
||||
*
|
||||
* 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) 2014-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class GeometricShapes
|
||||
public partial class GeometricShapes : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Geometric Shapes";
|
||||
|
||||
public string Title => "raylib [models] example - geometric shapes";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
}
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
public void Update()
|
||||
{
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Gold);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, -2.0f), 3.0f, 6.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawSphere(new Vector3(-1.0f, 0.0f, -2.0f), 1.0f, Color.Green);
|
||||
DrawSphereWires(new Vector3(1.0f, 0.0f, 2.0f), 2.0f, 16, 16, Color.Lime);
|
||||
|
||||
DrawCylinder(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.SkyBlue);
|
||||
DrawCylinderWires(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.DarkBlue);
|
||||
DrawCylinderWires(new Vector3(4.5f, -1.0f, 2.0f), 1.0f, 1.0f, 2.0f, 6, Color.Brown);
|
||||
|
||||
DrawCylinder(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Gold);
|
||||
DrawCylinderWires(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Pink);
|
||||
|
||||
DrawCapsule(new Vector3(-3.0f, 1.5f, -4.0f), new Vector3(-4.0f, -1.0f, -4.0f), 1.2f, 8, 8, Color.Violet);
|
||||
DrawCapsuleWires(new Vector3(-3.0f, 1.5f, -4.0f), new Vector3(-4.0f, -1.0f, -4.0f), 1.2f, 8, 8, Color.Purple);
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new GeometricShapes();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Gold);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, -2.0f), 3.0f, 6.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawSphere(new Vector3(-1.0f, 0.0f, -2.0f), 1.0f, Color.Green);
|
||||
DrawSphereWires(new Vector3(1.0f, 0.0f, 2.0f), 2.0f, 16, 16, Color.Lime);
|
||||
|
||||
DrawCylinder(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.SkyBlue);
|
||||
DrawCylinderWires(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.DarkBlue);
|
||||
DrawCylinderWires(new Vector3(4.5f, -1.0f, 2.0f), 1.0f, 1.0f, 2.0f, 6, Color.Brown);
|
||||
|
||||
DrawCylinder(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Gold);
|
||||
DrawCylinderWires(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Pink);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,90 +1,116 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Heightmap loading and drawing
|
||||
* raylib [models] example - heightmap rendering
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.8, last time updated with raylib 3.5
|
||||
*
|
||||
* 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class HeightmapDemo
|
||||
public partial class HeightmapDemo : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Heightmap Demo";
|
||||
|
||||
public string Title => "raylib [models] example - heightmap rendering";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D texture;
|
||||
private Model model;
|
||||
private Vector3 mapPosition;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing");
|
||||
|
||||
// Define our custom camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(18.0f, 16.0f, 18.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(18.0f, 21.0f, 18.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
Image image = LoadImage("resources/heightmap.png");
|
||||
Texture2D texture = LoadTextureFromImage(image);
|
||||
var image = LoadImage("resources/heightmap.png"); // Load heightmap image (RAM)
|
||||
texture = LoadTextureFromImage(image); // Convert image to texture (VRAM)
|
||||
|
||||
Mesh mesh = GenMeshHeightmap(image, new Vector3(16, 8, 16));
|
||||
Model model = LoadModelFromMesh(mesh);
|
||||
var mesh = GenMeshHeightmap(image, new Vector3(16, 8, 16)); // Generate heightmap mesh (RAM and VRAM)
|
||||
model = LoadModelFromMesh(mesh); // Load model from generated mesh
|
||||
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 mapPosition = new(-8.0f, 0.0f, -8.0f);
|
||||
mapPosition = new(-8.0f, 0.0f, -8.0f); // Define model position
|
||||
|
||||
UnloadImage(image);
|
||||
UnloadImage(image); // Unload heightmap image from RAM, already uploaded to VRAM
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, mapPosition, 1.0f, Color.Red);
|
||||
|
||||
DrawGrid(20, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawTexture(texture, screenWidth - texture.Width - 20, 20, Color.White);
|
||||
DrawRectangleLines(screenWidth - texture.Width - 20, 20, texture.Width, texture.Height, Color.Green);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new HeightmapDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, mapPosition, 1.0f, Color.Red);
|
||||
|
||||
DrawGrid(20, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawTexture(texture, screenWidth - texture.Width - 20, 20, Color.White);
|
||||
DrawRectangleLines(screenWidth - texture.Width - 20, 20, texture.Width, texture.Height, Color.Green);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -20,98 +20,124 @@
|
|||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class LoadingGltf
|
||||
public partial class LoadingGltf : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Loading GLTF";
|
||||
|
||||
public string Title => "raylib [models] example - loading gltf";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private float animCurrentFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(6.0f, 6.0f, 6.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/gltf/robot.glb");
|
||||
position = new(0.0f, 0.0f, 0.0f); // Set model world position
|
||||
|
||||
// Load model animations
|
||||
anims = LoadModelAnimations("resources/models/gltf/robot.glb", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 0; // Current animation playing
|
||||
animCurrentFrame = 0.0f; // Current animation frame
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Select current animation
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
animIndex = (animIndex + 1) % animCount;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
animIndex = (animIndex + animCount - 1) % animCount;
|
||||
}
|
||||
|
||||
|
||||
// Update model animation
|
||||
animCurrentFrame = (animCurrentFrame + 1) % anims[animIndex].KeyFrameCount;
|
||||
UpdateModelAnimation(model, anims[animIndex], (float)animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(
|
||||
model,
|
||||
position,
|
||||
1f,
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 40, 20, Color.Maroon);
|
||||
DrawText("Use the LEFT/RIGHT keys to switch animation", 10, 10, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animations data
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading gltf");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(6.0f, 6.0f, 6.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
Model model = LoadModel("resources/models/gltf/robot.glb");
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Load animation data
|
||||
var anims = LoadModelAnimations("resources/models/gltf/robot.glb");
|
||||
|
||||
// Animation playing variables
|
||||
int animIndex = 0;
|
||||
float animCurrentFrame = 0.0f;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LoadingGltf();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
animIndex = (animIndex + 1) % anims.Length;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
animIndex = (animIndex + anims.Length - 1) % anims.Length;
|
||||
}
|
||||
|
||||
|
||||
// Update model animation
|
||||
animCurrentFrame = (animCurrentFrame + 1) % anims[animIndex].KeyFrameCount;
|
||||
UpdateModelAnimation(model, anims[animIndex], (float)animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(
|
||||
model,
|
||||
position,
|
||||
1f,
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 40, 20, Color.Maroon);
|
||||
DrawText("Use the LEFT/RIGHT keys to switch animation", 10, 10, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadModelAnimations(anims);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,99 +19,123 @@
|
|||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class LoadingIqm
|
||||
public partial class LoadingIqm : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Loading IQM";
|
||||
|
||||
public string Title => "raylib [models] example - loading iqm";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private Vector3 position;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private float animCurrentFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 4.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera mode type
|
||||
|
||||
model = LoadModel("resources/models/iqm/guy.iqm"); // Load the animated model mesh and basic data
|
||||
texture = LoadTexture("resources/models/iqm/guytex.png"); // Load model texture and set material
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Diffuse, ref texture); // Set model material map texture
|
||||
position = new(0.0f, 0.0f, 0.0f); // Set model position
|
||||
|
||||
// Load animation data
|
||||
anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 0; // Current animation playing
|
||||
animCurrentFrame = 0.0f; // Current animation frame (supporting interpolated frames)
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Play animation when spacebar is held down
|
||||
animCurrentFrame += 1.0f;
|
||||
UpdateModelAnimation(model, anims[0], animCurrentFrame);
|
||||
|
||||
if (animCurrentFrame >= anims[0].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame = 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModelEx(
|
||||
model,
|
||||
position,
|
||||
new Vector3(1.0f, 0.0f, 0.0f),
|
||||
-90.0f,
|
||||
new Vector3(1.0f, 1.0f, 1.0f),
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 10, 20, Color.Maroon);
|
||||
DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animations data
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading iqm");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 4.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
Model model = LoadModel("resources/models/iqm/guy.iqm");
|
||||
Texture2D texture = LoadTexture("resources/models/iqm/guytex.png");
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Diffuse, ref texture);
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Load animation data
|
||||
var anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm");
|
||||
|
||||
// Animation playing variables
|
||||
int animIndex = 0;
|
||||
float animCurrentFrame = 0.0f;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LoadingIqm();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Play animation when spacebar is held down
|
||||
animCurrentFrame += 1.0f;
|
||||
UpdateModelAnimation(model, anims[0], animCurrentFrame);
|
||||
|
||||
if (animCurrentFrame >= anims[0].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame = 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModelEx(
|
||||
model,
|
||||
position,
|
||||
new Vector3(1.0f, 0.0f, 0.0f),
|
||||
-90.0f,
|
||||
new Vector3(1.0f, 1.0f, 1.0f),
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 10, 20, Color.Maroon);
|
||||
DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(texture);
|
||||
UnloadModelAnimations(anims);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
170
Examples/Models/LoadingM3d.cs
Normal file
170
Examples/Models/LoadingM3d.cs
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - loading m3d
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by bzt (@bztsrc) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* NOTES:
|
||||
* - Model3D (M3D) fileformat specs: https://gitlab.com/bztsrc/model3d
|
||||
* - Bender M3D exported: https://gitlab.com/bztsrc/model3d/-/tree/master/blender
|
||||
*
|
||||
* 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) 2022-2025 bzt (@bztsrc)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class LoadingM3d : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Loading M3D";
|
||||
|
||||
public string Title => "raylib [models] example - loading m3d";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private float animCurrentFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(1.5f, 1.5f, 1.5f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.4f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/m3d/cesium_man.m3d"); // Load the animated model mesh and basic data
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model position
|
||||
|
||||
// Load animation data
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/m3d/cesium_man.m3d", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 0; // Current animation playing
|
||||
animCurrentFrame = 0.0f; // Current animation frame (supporting interpolated frames)
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Select current animation
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
animIndex = (animIndex + 1) % animCount;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
animIndex = (animIndex + animCount - 1) % animCount;
|
||||
}
|
||||
|
||||
// Update model animation
|
||||
animCurrentFrame += 1.0f;
|
||||
if (animCurrentFrame >= anims[animIndex].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame = 0.0f;
|
||||
}
|
||||
UpdateModelAnimation(model, anims[animIndex], animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw 3d model with texture
|
||||
if (!IsKeyDown(KeyboardKey.Space))
|
||||
{
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the animated skeleton
|
||||
DrawModelSkeleton(model.Skeleton, anims[animIndex].KeyframePoses[(int)animCurrentFrame], 1.0f, Color.Red);
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 10, 20, Color.LightGray);
|
||||
DrawText("Press SPACE to draw skeleton", 10, 40, 20, Color.Maroon);
|
||||
DrawText("(c) CesiumMan model by KhronosGroup", GetScreenWidth() - 210, GetScreenHeight() - 20, 10, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animations data
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
// Draw model skeleton
|
||||
private static unsafe void DrawModelSkeleton(ModelSkeleton skeleton, Transform* pose, float scale, Color color)
|
||||
{
|
||||
// Loop to (boneCount - 1) because the last one is a special "no bone" bone,
|
||||
// needed to workaround buggy models without a -1, a cube is always drawn at the origin
|
||||
for (var i = 0; i < skeleton.BoneCount - 1; i++)
|
||||
{
|
||||
// Display the frame-pose skeleton
|
||||
DrawCube(pose[i].Translation, scale * 0.05f, scale * 0.05f, scale * 0.05f, color);
|
||||
|
||||
if (skeleton.Bones[i].Parent >= 0)
|
||||
{
|
||||
DrawLine3D(pose[i].Translation, pose[skeleton.Bones[i].Parent].Translation, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading m3d");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LoadingM3d();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
244
Examples/Models/LoadingVox.cs
Normal file
244
Examples/Models/LoadingVox.cs
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - loading vox
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 4.0, last time updated with raylib 4.0
|
||||
*
|
||||
* Example contributed by Johann Nadalutti (@procfxgen) 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) 2021-2025 Johann Nadalutti (@procfxgen) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raymath;
|
||||
using Examples.Shared;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class LoadingVox : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxVoxFiles = 4;
|
||||
private const int MaxLights = 4;
|
||||
|
||||
#if BROWSER
|
||||
private const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Loading VOX";
|
||||
|
||||
public string Title => "raylib [models] example - loading vox";
|
||||
|
||||
private static readonly string[] VoxFileNames =
|
||||
{
|
||||
"resources/models/vox/chr_knight.vox",
|
||||
"resources/models/vox/chr_sword.vox",
|
||||
"resources/models/vox/monu9.vox",
|
||||
"resources/models/vox/fez.vox"
|
||||
};
|
||||
|
||||
private Camera3D camera;
|
||||
private Model[] models;
|
||||
private int currentModel;
|
||||
private Vector3 modelpos;
|
||||
private Vector3 camerarot;
|
||||
private Shader shader;
|
||||
private Light[] lights;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load MagicaVoxel files
|
||||
models = new Model[MaxVoxFiles];
|
||||
|
||||
for (var i = 0; i < MaxVoxFiles; i++)
|
||||
{
|
||||
// Load VOX file and measure time
|
||||
var t0 = GetTime() * 1000.0;
|
||||
models[i] = LoadModel(VoxFileNames[i]);
|
||||
var t1 = GetTime() * 1000.0;
|
||||
|
||||
TraceLog(TraceLogLevel.Info, $"[{VoxFileNames[i]}] Model file loaded in {t1 - t0:0.000} ms");
|
||||
|
||||
// Compute model translation matrix to center model on draw position (0, 0 , 0)
|
||||
var bb = GetModelBoundingBox(models[i]);
|
||||
Vector3 center = new();
|
||||
center.X = bb.Min.X + ((bb.Max.X - bb.Min.X) / 2);
|
||||
center.Z = bb.Min.Z + ((bb.Max.Z - bb.Min.Z) / 2);
|
||||
|
||||
var matTranslate = MatrixTranslate(-center.X, 0, -center.Z);
|
||||
models[i].Transform = matTranslate;
|
||||
}
|
||||
|
||||
currentModel = 0;
|
||||
modelpos = new Vector3(0, 0, 0);
|
||||
camerarot = new Vector3(0, 0, 0);
|
||||
|
||||
// Load voxel shader
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/voxel_lighting.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/voxel_lighting.fs"
|
||||
);
|
||||
|
||||
// Get some required shader locations
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(shader, "viewPos");
|
||||
// NOTE: "matModel" location name is automatically assigned on shader loading,
|
||||
// no need to get the location again if using that uniform name
|
||||
//shader.Locs[(int)ShaderLocationIndex.MatrixModel] = GetShaderLocation(shader, "matModel");
|
||||
|
||||
// Ambient light level (some basic lighting)
|
||||
var ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
Raylib.SetShaderValue(shader, ambientLoc, new[] { 0.1f, 0.1f, 0.1f, 1.0f }, ShaderUniformDataType.Vec4);
|
||||
|
||||
// Assign out lighting shader to model
|
||||
for (var i = 0; i < MaxVoxFiles; i++)
|
||||
{
|
||||
for (var j = 0; j < models[i].MaterialCount; j++)
|
||||
{
|
||||
models[i].Materials[j].Shader = shader;
|
||||
}
|
||||
}
|
||||
|
||||
// Create lights
|
||||
lights = new Light[MaxLights];
|
||||
lights[0] = Rlights.CreateLight(0, LightType.Point, new Vector3(-20, 20, -20), Vector3.Zero, Color.Gray, shader);
|
||||
lights[1] = Rlights.CreateLight(1, LightType.Point, new Vector3(20, -20, 20), Vector3.Zero, Color.Gray, shader);
|
||||
lights[2] = Rlights.CreateLight(2, LightType.Point, new Vector3(-20, 20, 20), Vector3.Zero, Color.Gray, shader);
|
||||
lights[3] = Rlights.CreateLight(3, LightType.Point, new Vector3(20, -20, -20), Vector3.Zero, Color.Gray, shader);
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsMouseButtonDown(MouseButton.Middle))
|
||||
{
|
||||
var mouseDelta = GetMouseDelta();
|
||||
camerarot.X = mouseDelta.X * 0.05f;
|
||||
camerarot.Y = mouseDelta.Y * 0.05f;
|
||||
}
|
||||
else
|
||||
{
|
||||
camerarot.X = 0;
|
||||
camerarot.Y = 0;
|
||||
}
|
||||
|
||||
// Update camere movement, custom controls
|
||||
UpdateCameraPro(ref camera,
|
||||
new Vector3(
|
||||
(IsKeyDown(KeyboardKey.W) || IsKeyDown(KeyboardKey.Up) ? 0.1f : 0.0f) - (IsKeyDown(KeyboardKey.S) || IsKeyDown(KeyboardKey.Down) ? 0.1f : 0.0f), // Move forward-backward
|
||||
(IsKeyDown(KeyboardKey.D) || IsKeyDown(KeyboardKey.Right) ? 0.1f : 0.0f) - (IsKeyDown(KeyboardKey.A) || IsKeyDown(KeyboardKey.Left) ? 0.1f : 0.0f), // Move right-left
|
||||
0.0f), // Move up-down
|
||||
camerarot, // Camera rotation
|
||||
GetMouseWheelMove() * -2.0f); // Move to target (zoom)
|
||||
|
||||
// Cycle between models on mouse click
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
currentModel = (currentModel + 1) % MaxVoxFiles;
|
||||
}
|
||||
|
||||
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
|
||||
Raylib.SetShaderValue(shader, shader.Locs[(int)ShaderLocationIndex.VectorView], camera.Position, ShaderUniformDataType.Vec3);
|
||||
|
||||
// Update light values (actually, only enable/disable them)
|
||||
for (var i = 0; i < MaxLights; i++)
|
||||
{
|
||||
Rlights.UpdateLightValues(shader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw 3D model
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(models[currentModel], modelpos, 1.0f, Color.White);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Draw spheres to show where the lights are
|
||||
for (var i = 0; i < MaxLights; i++)
|
||||
{
|
||||
if (lights[i].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[i].Position, 0.2f, 8, 8, lights[i].Color);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[i].Position, 0.2f, 8, 8, ColorAlpha(lights[i].Color, 0.3f));
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Display info
|
||||
DrawRectangle(10, 40, 340, 70, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 40, 340, 70, Fade(Color.DarkBlue, 0.5f));
|
||||
DrawText("- MOUSE LEFT BUTTON: CYCLE VOX MODELS", 20, 50, 10, Color.Blue);
|
||||
DrawText("- MOUSE MIDDLE BUTTON: ZOOM OR ROTATE CAMERA", 20, 70, 10, Color.Blue);
|
||||
DrawText("- UP-DOWN-LEFT-RIGHT KEYS: MOVE CAMERA", 20, 90, 10, Color.Blue);
|
||||
DrawText($"VOX model file: {GetFileName(VoxFileNames[currentModel])}", 10, 10, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// Unload models data (GPU VRAM)
|
||||
for (var i = 0; i < MaxVoxFiles; i++)
|
||||
{
|
||||
UnloadModel(models[i]);
|
||||
}
|
||||
|
||||
UnloadShader(shader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading vox");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LoadingVox();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,23 @@
|
|||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class MeshDemo
|
||||
public partial class MeshDemo : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Mesh Demo";
|
||||
|
||||
public string Title => "raylib [models] example - mesh demo";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private float rotationAngle;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh demo");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = Vector3.One * 1.5f;
|
||||
camera.Target = Vector3.Zero;
|
||||
camera.Up = Vector3.UnitY;
|
||||
|
|
@ -28,10 +30,10 @@ public class MeshDemo
|
|||
tetrahedron.AllocTexCoords();
|
||||
tetrahedron.AllocColors();
|
||||
tetrahedron.AllocIndices();
|
||||
Span<Vector3> vertices = tetrahedron.VerticesAs<Vector3>();
|
||||
Span<Vector2> texcoords = tetrahedron.TexCoordsAs<Vector2>();
|
||||
Span<Color> colors = tetrahedron.ColorsAs<Color>();
|
||||
Span<ushort> indices = tetrahedron.IndicesAs<ushort>();
|
||||
var vertices = tetrahedron.VerticesAs<Vector3>();
|
||||
var texcoords = tetrahedron.TexCoordsAs<Vector2>();
|
||||
var colors = tetrahedron.ColorsAs<Color>();
|
||||
var indices = tetrahedron.IndicesAs<ushort>();
|
||||
|
||||
// Coordinates for a regular tetrahedron
|
||||
vertices[0] = new(MathF.Sqrt(8f / 9f), 0f, -1f / 3f);
|
||||
|
|
@ -65,49 +67,69 @@ public class MeshDemo
|
|||
indices[10] = 3;
|
||||
indices[11] = 2;
|
||||
|
||||
float rotationAngle = 0f;
|
||||
rotationAngle = 0f;
|
||||
Raylib.UploadMesh(ref tetrahedron, false);
|
||||
Model model = Raylib.LoadModelFromMesh(tetrahedron);
|
||||
model = Raylib.LoadModelFromMesh(tetrahedron);
|
||||
|
||||
Image image = Raylib.GenImagePerlinNoise(16, 16, 0, 0, 1000f);
|
||||
var image = Raylib.GenImagePerlinNoise(16, 16, 0, 0, 1000f);
|
||||
Raylib.ImageBlurGaussian(ref image, 2);
|
||||
Raylib.ImageColorBrightness(ref image, 100);
|
||||
Raylib.ImageDither(ref image, 4, 4, 4, 4);
|
||||
Texture2D texture = Raylib.LoadTextureFromImage(image);
|
||||
texture = Raylib.LoadTextureFromImage(image);
|
||||
Raylib.UnloadImage(image);
|
||||
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Diffuse, ref texture);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
rotationAngle = Raymath.Wrap(rotationAngle += 1f, 0f, 360f);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
Raylib.DrawModelEx(model, Vector3.Zero, Vector3.UnitX, rotationAngle, Vector3.One, Color.White);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh demo");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MeshDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
rotationAngle = Raymath.Wrap(rotationAngle += 1f, 0f, 360f);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
Raylib.DrawModelEx(model, Vector3.Zero, Vector3.UnitX, rotationAngle, Vector3.One, Color.White);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,38 +1,45 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib example - procedural mesh generation
|
||||
* raylib [models] example - mesh generation
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2017 Ramon Santamaria (Ray San)
|
||||
* Example originally created with raylib 1.8, last time updated with raylib 4.0
|
||||
*
|
||||
* 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-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class MeshGeneration
|
||||
public partial class MeshGeneration : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Mesh Generation";
|
||||
|
||||
public string Title => "raylib [models] example - mesh generation";
|
||||
|
||||
private Texture2D texture;
|
||||
private Model[] models;
|
||||
private Camera3D camera;
|
||||
private Vector3 position;
|
||||
private int currentModel;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh generation");
|
||||
|
||||
// We generate a isChecked image for texturing
|
||||
Image isChecked = GenImageChecked(2, 2, 1, 1, Color.Red, Color.Green);
|
||||
Texture2D texture = LoadTextureFromImage(isChecked);
|
||||
// We generate a checked image for texturing
|
||||
var isChecked = GenImageChecked(2, 2, 1, 1, Color.Red, Color.Green);
|
||||
texture = LoadTextureFromImage(isChecked);
|
||||
UnloadImage(isChecked);
|
||||
|
||||
Model[] models = new Model[9];
|
||||
models = new Model[9];
|
||||
|
||||
models[0] = LoadModelFromMesh(GenMeshPlane(2, 2, 5, 5));
|
||||
models[0] = LoadModelFromMesh(GenMeshPlane(2, 2, 4, 3));
|
||||
models[1] = LoadModelFromMesh(GenMeshCube(2.0f, 1.0f, 2.0f));
|
||||
models[2] = LoadModelFromMesh(GenMeshSphere(2, 32, 32));
|
||||
models[3] = LoadModelFromMesh(GenMeshHemiSphere(2, 16, 16));
|
||||
|
|
@ -42,15 +49,17 @@ public class MeshGeneration
|
|||
models[7] = LoadModelFromMesh(GenMeshPoly(5, 2.0f));
|
||||
models[8] = LoadModelFromMesh(GenMeshCustom());
|
||||
|
||||
// Set isChecked texture as default diffuse component for all models material
|
||||
for (int i = 0; i < models.Length; i++)
|
||||
// NOTE: Generated meshes could be exported using ExportMesh()
|
||||
|
||||
// Set checked texture as default diffuse component for all models material
|
||||
for (var i = 0; i < models.Length; i++)
|
||||
{
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref models[i], 0, MaterialMapIndex.Albedo, ref texture);
|
||||
}
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 5.0f, 5.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
|
@ -58,92 +67,102 @@ public class MeshGeneration
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Model drawing position
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
position = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
int currentModel = 0;
|
||||
currentModel = 0;
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Cycle between the textures
|
||||
currentModel = (currentModel + 1) % models.Length;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(models[currentModel], position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(30, 400, 310, 30, ColorAlpha(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(30, 400, 310, 30, ColorAlpha(Color.DarkBlue, 0.5f));
|
||||
DrawText("MOUSE LEFT BUTTON to CYCLE PROCEDURAL MODELS", 40, 410, 10, Color.Blue);
|
||||
|
||||
switch (currentModel)
|
||||
{
|
||||
case 0:
|
||||
DrawText("PLANE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 1:
|
||||
DrawText("CUBE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 2:
|
||||
DrawText("SPHERE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 3:
|
||||
DrawText("HEMISPHERE", 640, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 4:
|
||||
DrawText("CYLINDER", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 5:
|
||||
DrawText("TORUS", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 6:
|
||||
DrawText("KNOT", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 7:
|
||||
DrawText("POLY", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 8:
|
||||
DrawText("Custom (triagnle)", 580, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
currentModel = (currentModel + 1) % models.Length; // Cycle between the textures
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
for (int i = 0; i < models.Length; i++)
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
currentModel++;
|
||||
if (currentModel >= models.Length)
|
||||
{
|
||||
currentModel = 0;
|
||||
}
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
currentModel--;
|
||||
if (currentModel < 0)
|
||||
{
|
||||
currentModel = models.Length - 1;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(models[currentModel], position, 1.0f, Color.White);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(30, 400, 310, 30, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(30, 400, 310, 30, Fade(Color.DarkBlue, 0.5f));
|
||||
DrawText("MOUSE LEFT BUTTON to CYCLE PROCEDURAL MODELS", 40, 410, 10, Color.Blue);
|
||||
|
||||
switch (currentModel)
|
||||
{
|
||||
case 0:
|
||||
DrawText("PLANE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 1:
|
||||
DrawText("CUBE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 2:
|
||||
DrawText("SPHERE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 3:
|
||||
DrawText("HEMISPHERE", 640, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 4:
|
||||
DrawText("CYLINDER", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 5:
|
||||
DrawText("TORUS", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 6:
|
||||
DrawText("KNOT", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 7:
|
||||
DrawText("POLY", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 8:
|
||||
DrawText("Custom (triangle)", 580, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture); // Unload texture
|
||||
|
||||
// Unload models data (GPU VRAM)
|
||||
for (var i = 0; i < models.Length; i++)
|
||||
{
|
||||
UnloadModel(models[i]);
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate a simple triangle mesh from code
|
||||
|
|
@ -153,9 +172,9 @@ public class MeshGeneration
|
|||
mesh.AllocVertices();
|
||||
mesh.AllocTexCoords();
|
||||
mesh.AllocNormals();
|
||||
Span<Vector3> vertices = mesh.VerticesAs<Vector3>();
|
||||
Span<Vector2> texcoords = mesh.TexCoordsAs<Vector2>();
|
||||
Span<Vector3> normals = mesh.NormalsAs<Vector3>();
|
||||
var vertices = mesh.VerticesAs<Vector3>();
|
||||
var texcoords = mesh.TexCoordsAs<Vector2>();
|
||||
var normals = mesh.NormalsAs<Vector3>();
|
||||
|
||||
// Vertex at (0, 0, 0)
|
||||
vertices[0] = new(0, 0, 0);
|
||||
|
|
@ -177,4 +196,32 @@ public class MeshGeneration
|
|||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh generation");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MeshGeneration();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +1,54 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Mesh picking in 3d mode, ground plane, triangle, mesh
|
||||
* raylib [models] example - mesh picking
|
||||
*
|
||||
* This example has been created using raylib 1.7 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example contributed by Joel Davis (@joeld42)
|
||||
* 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-2025 Joel Davis (@joeld42) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class MeshPicking
|
||||
public partial class MeshPicking : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Mesh Picking";
|
||||
|
||||
public string Title => "raylib [models] example - mesh picking";
|
||||
|
||||
private Camera3D camera;
|
||||
private Ray ray;
|
||||
private Model tower;
|
||||
private Texture2D texture;
|
||||
private Vector3 towerPos;
|
||||
private BoundingBox towerBBox;
|
||||
private Vector3 g0;
|
||||
private Vector3 g1;
|
||||
private Vector3 g2;
|
||||
private Vector3 g3;
|
||||
private Vector3 ta;
|
||||
private Vector3 tb;
|
||||
private Vector3 tc;
|
||||
private Vector3 bary;
|
||||
private Vector3 sp;
|
||||
private float sr;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh picking");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(20.0f, 20.0f, 20.0f);
|
||||
camera.Target = new Vector3(0.0f, 8.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.6f, 0.0f);
|
||||
|
|
@ -36,210 +56,232 @@ public class MeshPicking
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Picking ray
|
||||
Ray ray = new();
|
||||
ray = new();
|
||||
|
||||
Model tower = LoadModel("resources/models/obj/turret.obj");
|
||||
Texture2D texture = LoadTexture("resources/models/obj/turret_diffuse.png");
|
||||
tower = LoadModel("resources/models/obj/turret.obj");
|
||||
texture = LoadTexture("resources/models/obj/turret_diffuse.png");
|
||||
Raylib.SetMaterialTexture(ref tower, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 towerPos = new(0.0f, 0.0f, 0.0f);
|
||||
BoundingBox towerBBox = GetMeshBoundingBox(tower.Meshes[0]);
|
||||
towerPos = new(0.0f, 0.0f, 0.0f);
|
||||
towerBBox = 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);
|
||||
g0 = new(-50.0f, 0.0f, -50.0f);
|
||||
g1 = new(-50.0f, 0.0f, 50.0f);
|
||||
g2 = new(50.0f, 0.0f, 50.0f);
|
||||
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);
|
||||
ta = new(-25.0f, 0.5f, 0.0f);
|
||||
tb = new(-4.0f, 2.5f, 1.0f);
|
||||
tc = new(-8.0f, 6.5f, 0.0f);
|
||||
|
||||
Vector3 bary = new(0.0f, 0.0f, 0.0f);
|
||||
bary = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Test sphere
|
||||
Vector3 sp = new(-30.0f, 5.0f, 5.0f);
|
||||
float sr = 4.0f;
|
||||
sp = new(-30.0f, 5.0f, 5.0f);
|
||||
sr = 4.0f;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
//----------------------------------------------------------------------------------
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
}
|
||||
|
||||
// Toggle camera controls
|
||||
if (IsMouseButtonPressed(MouseButton.Right))
|
||||
{
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
EnableCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
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 = GetScreenToWorldRay(GetMousePosition(), camera);
|
||||
|
||||
// Check ray collision against ground quad
|
||||
var groundHitInfo = 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 = GetRayCollisionTriangle(ray, ta, tb, tc);
|
||||
if (triHitInfo.Hit && (triHitInfo.Distance < collision.Distance))
|
||||
{
|
||||
collision = triHitInfo;
|
||||
cursorColor = Color.Purple;
|
||||
hitObjectName = "Triangle";
|
||||
|
||||
bary = Vector3Barycenter(collision.Point, ta, tb, tc);
|
||||
}
|
||||
|
||||
// Check ray collision against test sphere
|
||||
var sphereHitInfo = 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 = 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 = 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
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw the tower
|
||||
// WARNING: If scale is different than 1.0f,
|
||||
// not considered by GetRayCollisionModel()
|
||||
DrawModel(tower, towerPos, 1.0f, Color.White);
|
||||
|
||||
// Draw the test triangle
|
||||
DrawLine3D(ta, tb, Color.Purple);
|
||||
DrawLine3D(tb, tc, Color.Purple);
|
||||
DrawLine3D(tc, ta, Color.Purple);
|
||||
|
||||
// Draw the test sphere
|
||||
DrawSphereWires(sp, sr, 8, 8, Color.Purple);
|
||||
|
||||
// Draw the mesh bbox if we hit it
|
||||
if (boxHitInfo.Hit)
|
||||
{
|
||||
DrawBoundingBox(towerBBox, Color.Lime);
|
||||
}
|
||||
|
||||
// If we hit something, draw the cursor at the hit point
|
||||
if (collision.Hit)
|
||||
{
|
||||
DrawCube(collision.Point, 0.3f, 0.3f, 0.3f, cursorColor);
|
||||
DrawCubeWires(collision.Point, 0.3f, 0.3f, 0.3f, Color.Red);
|
||||
|
||||
var normalEnd = collision.Point + collision.Normal;
|
||||
DrawLine3D(collision.Point, normalEnd, Color.Red);
|
||||
}
|
||||
|
||||
DrawRay(ray, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw some debug GUI text
|
||||
DrawText($"Hit Object: {hitObjectName}", 10, 50, 10, Color.Black);
|
||||
|
||||
if (collision.Hit)
|
||||
{
|
||||
var ypos = 70;
|
||||
|
||||
DrawText($"Distance: {collision.Distance}", 10, ypos, 10, Color.Black);
|
||||
|
||||
DrawText($"Hit Pos: {collision.Point}", 10, ypos + 15, 10, Color.Black);
|
||||
|
||||
DrawText($"Hit Norm: {collision.Normal}", 10, ypos + 30, 10, Color.Black);
|
||||
|
||||
if (triHitInfo.Hit && hitObjectName == "Triangle")
|
||||
{
|
||||
DrawText($"Barycenter: {bary}", 10, ypos + 45, 10, Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
DrawText("Right click mouse to toggle camera controls", 10, 430, 10, Color.Gray);
|
||||
|
||||
DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(tower);
|
||||
UnloadTexture(texture);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh picking");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MeshPicking();
|
||||
game.Init();
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Main game loop
|
||||
//--------------------------------------------------------------------------------------
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
//----------------------------------------------------------------------------------
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
}
|
||||
|
||||
// Toggle camera controls
|
||||
if (IsMouseButtonPressed(MouseButton.Right))
|
||||
{
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
EnableCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableCursor();
|
||||
}
|
||||
}
|
||||
|
||||
// Display information about closest hit
|
||||
RayCollision collision = new();
|
||||
string hitObjectName = "None";
|
||||
collision.Distance = float.MaxValue;
|
||||
collision.Hit = false;
|
||||
Color cursorColor = Color.White;
|
||||
|
||||
// Get ray and test against objects
|
||||
ray = GetScreenToWorldRay(GetMousePosition(), camera);
|
||||
|
||||
// Check ray collision aginst ground quad
|
||||
RayCollision groundHitInfo = 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
|
||||
RayCollision triHitInfo = GetRayCollisionTriangle(ray, ta, tb, tc);
|
||||
if (triHitInfo.Hit && (triHitInfo.Distance < collision.Distance))
|
||||
{
|
||||
collision = triHitInfo;
|
||||
cursorColor = Color.Purple;
|
||||
hitObjectName = "Triangle";
|
||||
|
||||
bary = Vector3Barycenter(collision.Point, ta, tb, tc);
|
||||
}
|
||||
|
||||
// Check ray collision against test sphere
|
||||
RayCollision sphereHitInfo = 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
|
||||
RayCollision boxHitInfo = 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 (int 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 = 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
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw the tower
|
||||
DrawModel(tower, towerPos, 1.0f, Color.White);
|
||||
|
||||
// Draw the test triangle
|
||||
DrawLine3D(ta, tb, Color.Purple);
|
||||
DrawLine3D(tb, tc, Color.Purple);
|
||||
DrawLine3D(tc, ta, Color.Purple);
|
||||
|
||||
// Draw the test sphere
|
||||
DrawSphereWires(sp, sr, 8, 8, Color.Purple);
|
||||
|
||||
// Draw the mesh bbox if we hit it
|
||||
if (boxHitInfo.Hit)
|
||||
{
|
||||
DrawBoundingBox(towerBBox, Color.Lime);
|
||||
}
|
||||
|
||||
// If we hit something, draw the cursor at the hit point
|
||||
if (collision.Hit)
|
||||
{
|
||||
DrawCube(collision.Point, 0.3f, 0.3f, 0.3f, cursorColor);
|
||||
DrawCubeWires(collision.Point, 0.3f, 0.3f, 0.3f, Color.Red);
|
||||
|
||||
Vector3 normalEnd = collision.Point + collision.Normal;
|
||||
DrawLine3D(collision.Point, normalEnd, Color.Red);
|
||||
}
|
||||
|
||||
DrawRay(ray, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw some debug GUI text
|
||||
DrawText($"Hit Object: {hitObjectName}", 10, 50, 10, Color.Black);
|
||||
|
||||
if (collision.Hit)
|
||||
{
|
||||
int ypos = 70;
|
||||
|
||||
DrawText($"Distance: {collision.Distance}", 10, ypos, 10, Color.Black);
|
||||
|
||||
DrawText($"Hit Pos: {collision.Point}", 10, ypos + 15, 10, Color.Black);
|
||||
|
||||
DrawText($"Hit Norm: {collision.Normal}", 10, ypos + 30, 10, Color.Black);
|
||||
|
||||
if (triHitInfo.Hit)
|
||||
{
|
||||
DrawText($"Barycenter: {bary}", 10, ypos + 45, 10, Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
DrawText("Right click mouse to toggle camera controls", 10, 430, 10, Color.Gray);
|
||||
|
||||
DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadModel(tower);
|
||||
UnloadTexture(texture);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,34 +1,36 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Draw textured cube
|
||||
* raylib [models] example - textured cube
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* 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) 2022-2023 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2022-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class ModelCubeTexture
|
||||
public partial class ModelCubeTexture : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Model Cube Texture";
|
||||
|
||||
public string Title => "raylib [models] example - textured cube";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D texture;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - draw cube texture");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
|
@ -36,60 +38,48 @@ public class ModelCubeTexture
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load texture to be applied to the cubes sides
|
||||
Texture2D texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
public void Update()
|
||||
{
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
// Draw cube with an applied texture
|
||||
DrawCubeTexture(texture, new Vector3(-2.0f, 2.0f, 0.0f), 2.0f, 4.0f, 2.0f, Color.White);
|
||||
|
||||
BeginMode3D(camera);
|
||||
// Draw cube with an applied texture, but only a defined rectangle piece of the texture
|
||||
DrawCubeTextureRec(
|
||||
texture,
|
||||
new Rectangle(0, texture.Height / 2, texture.Width / 2, texture.Height / 2),
|
||||
new Vector3(2.0f, 1.0f, 0.0f),
|
||||
2.0f,
|
||||
2.0f,
|
||||
2.0f,
|
||||
Color.White
|
||||
);
|
||||
|
||||
// Draw cube with an applied texture
|
||||
DrawCubeTexture(texture, new Vector3(-2.0f, 2.0f, 0.0f), 2.0f, 4.0f, 2.0f, Color.White);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Draw cube with an applied texture, but only a defined rectangle piece of the texture
|
||||
DrawCubeTextureRec(
|
||||
texture,
|
||||
new Rectangle(0, texture.Height / 2, texture.Width / 2, texture.Height / 2),
|
||||
new Vector3(2.0f, 1.0f, 0.0f),
|
||||
2.0f,
|
||||
2.0f,
|
||||
2.0f,
|
||||
Color.White
|
||||
);
|
||||
EndMode3D();
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Draw cube textured
|
||||
// NOTE: Cube position is the center position
|
||||
static void DrawCubeTexture(
|
||||
private static void DrawCubeTexture(
|
||||
Texture2D texture,
|
||||
Vector3 position,
|
||||
float width,
|
||||
|
|
@ -98,9 +88,9 @@ public class ModelCubeTexture
|
|||
Color color
|
||||
)
|
||||
{
|
||||
float x = position.X;
|
||||
float y = position.Y;
|
||||
float z = position.Z;
|
||||
var x = position.X;
|
||||
var y = position.Y;
|
||||
var z = position.Z;
|
||||
|
||||
// Set desired texture to be enabled while drawing following vertex data
|
||||
Rlgl.SetTexture(texture.Id);
|
||||
|
|
@ -218,7 +208,7 @@ public class ModelCubeTexture
|
|||
}
|
||||
|
||||
// Draw cube with texture piece applied to all faces
|
||||
static void DrawCubeTextureRec(
|
||||
private static void DrawCubeTextureRec(
|
||||
Texture2D texture,
|
||||
Rectangle source,
|
||||
Vector3 position,
|
||||
|
|
@ -228,11 +218,11 @@ public class ModelCubeTexture
|
|||
Color color
|
||||
)
|
||||
{
|
||||
float x = position.X;
|
||||
float y = position.Y;
|
||||
float z = position.Z;
|
||||
float texWidth = (float)texture.Width;
|
||||
float texHeight = (float)texture.Height;
|
||||
var x = position.X;
|
||||
var y = position.Y;
|
||||
var z = position.Z;
|
||||
var texWidth = (float)texture.Width;
|
||||
var texHeight = (float)texture.Height;
|
||||
|
||||
// Set desired texture to be enabled while drawing following vertex data
|
||||
Rlgl.SetTexture(texture.Id);
|
||||
|
|
@ -312,5 +302,32 @@ public class ModelCubeTexture
|
|||
|
||||
Rlgl.SetTexture(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - textured cube");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ModelCubeTexture();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,157 +1,197 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Models loading
|
||||
* raylib [models] example - loading
|
||||
*
|
||||
* raylib supports multiple models file formats:
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* - OBJ > Text file, must include vertex position-texcoords-normals information,
|
||||
* if files references some .mtl materials file, it will be loaded (or try to)
|
||||
* - GLTF > Modern text/binary file format, includes lot of information and it could
|
||||
* also reference external files, raylib will try loading mesh and materials data
|
||||
* - IQM > Binary file format including mesh vertex data but also animation data,
|
||||
* raylib can load .iqm animations.
|
||||
* NOTE: raylib supports multiple models file formats:
|
||||
*
|
||||
* This example has been created using raylib 2.6 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* - OBJ > Text file format. Must include vertex position-texcoords-normals information,
|
||||
* if .obj references some .mtl materials file, it will be tried to be loaded
|
||||
* - GLTF/GLB > Text/binary file formats. Includes lot of information and it could
|
||||
* also reference external files, mesh and materials data will be tried to be loaded
|
||||
* - IQM > Binary file format. Includes mesh vertex data but also animation data,
|
||||
* meshes and animation data can be loaded
|
||||
* - VOX > Binary file format. MagikaVoxel mesh format:
|
||||
* https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox.txt
|
||||
* - M3D > Binary file format. Model 3D format:
|
||||
* https://bztsrc.gitlab.io/model3d
|
||||
*
|
||||
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 2.0, last time updated with raylib 4.2
|
||||
*
|
||||
* 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) 2014-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class ModelLoading
|
||||
public partial class ModelLoading : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Model Loading";
|
||||
|
||||
public string Title => "raylib [models] example - loading";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private Vector3 position;
|
||||
private BoundingBox bounds;
|
||||
private bool selected;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - models loading");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(50.0f, 50.0f, 50.0f);
|
||||
camera.Target = new Vector3(0.0f, 10.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(50.0f, 50.0f, 50.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 12.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera mode type
|
||||
|
||||
Model model = LoadModel("resources/models/obj/castle.obj");
|
||||
Texture2D texture = LoadTexture("resources/models/obj/castle_diffuse.png");
|
||||
model = LoadModel("resources/models/obj/castle.obj"); // Load model
|
||||
texture = LoadTexture("resources/models/obj/castle_diffuse.png"); // Load model texture
|
||||
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
BoundingBox bounds = GetMeshBoundingBox(model.Meshes[0]);
|
||||
position = new(0.0f, 0.0f, 0.0f); // Set model position
|
||||
bounds = GetMeshBoundingBox(model.Meshes[0]); // Set model bounds
|
||||
|
||||
// NOTE: bounds are calculated from the original size of the model,
|
||||
// if model is scaled on drawing, bounds must be also scaled
|
||||
|
||||
bool selected = false;
|
||||
selected = false;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
#if BROWSER
|
||||
// NOTE: drag-and-drop model loading is not supported in the browser host; default loaded model is kept.
|
||||
#else
|
||||
// Load new models/textures on drag&drop
|
||||
if (IsFileDropped())
|
||||
{
|
||||
var droppedFiles = Raylib.GetDroppedFiles();
|
||||
|
||||
if (droppedFiles.Length == 1) // Only support one file dropped
|
||||
{
|
||||
if (IsFileExtension(droppedFiles[0], ".obj") ||
|
||||
IsFileExtension(droppedFiles[0], ".gltf") ||
|
||||
IsFileExtension(droppedFiles[0], ".glb") ||
|
||||
IsFileExtension(droppedFiles[0], ".vox") ||
|
||||
IsFileExtension(droppedFiles[0], ".iqm") ||
|
||||
IsFileExtension(droppedFiles[0], ".m3d") // Model file formats supported
|
||||
)
|
||||
{
|
||||
UnloadModel(model); // Unload previous model
|
||||
model = LoadModel(droppedFiles[0]); // Load new model
|
||||
|
||||
// Set current map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
bounds = GetMeshBoundingBox(model.Meshes[0]);
|
||||
|
||||
// Move camera position from target enough distance to visualize model properly
|
||||
camera.Position.X = bounds.Max.X + 10.0f;
|
||||
camera.Position.Y = bounds.Max.Y + 10.0f;
|
||||
camera.Position.Z = bounds.Max.Z + 10.0f;
|
||||
}
|
||||
else if (IsFileExtension(droppedFiles[0], ".png")) // Texture file formats supported
|
||||
{
|
||||
// Unload current model texture and load new one
|
||||
UnloadTexture(texture);
|
||||
texture = LoadTexture(droppedFiles[0]);
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Select model on mouse click
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Check collision between ray and box
|
||||
if (GetRayCollisionBox(GetScreenToWorldRay(GetMousePosition(), camera), bounds).Hit)
|
||||
{
|
||||
selected = !selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
selected = false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White); // Draw 3d model with texture
|
||||
|
||||
DrawGrid(20, 10.0f); // Draw a grid
|
||||
|
||||
if (selected)
|
||||
{
|
||||
DrawBoundingBox(bounds, Color.Green); // Draw selection box
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Drag & drop model to load mesh/texture.", 10, GetScreenHeight() - 20, 10, Color.DarkGray);
|
||||
if (selected)
|
||||
{
|
||||
DrawText("MODEL SELECTED", GetScreenWidth() - 110, 10, 10, Color.Green);
|
||||
}
|
||||
|
||||
DrawText("(c) Castle 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ModelLoading();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsFileDropped())
|
||||
{
|
||||
string[] droppedFiles = Raylib.GetDroppedFiles();
|
||||
|
||||
if (droppedFiles.Length == 1)
|
||||
{
|
||||
if (IsFileExtension(droppedFiles[0], ".obj") ||
|
||||
IsFileExtension(droppedFiles[0], ".gltf") ||
|
||||
IsFileExtension(droppedFiles[0], ".glb") ||
|
||||
IsFileExtension(droppedFiles[0], ".vox") ||
|
||||
IsFileExtension(droppedFiles[0], ".iqm") ||
|
||||
IsFileExtension(droppedFiles[0], ".m3d")
|
||||
)
|
||||
{
|
||||
UnloadModel(model);
|
||||
model = LoadModel(droppedFiles[0]);
|
||||
|
||||
// Set current map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
bounds = GetMeshBoundingBox(model.Meshes[0]);
|
||||
|
||||
// TODO: Move camera position from target enough distance to visualize model properly
|
||||
}
|
||||
else if (IsFileExtension(droppedFiles[0], ".png"))
|
||||
{
|
||||
// Unload model texture and load new one
|
||||
UnloadTexture(texture);
|
||||
texture = LoadTexture(droppedFiles[0]);
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select model on mouse click
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Check collision between ray and box
|
||||
if (GetRayCollisionBox(GetScreenToWorldRay(GetMousePosition(), camera), bounds).Hit)
|
||||
{
|
||||
selected = !selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
selected = false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(20, 10.0f);
|
||||
|
||||
if (selected)
|
||||
{
|
||||
DrawBoundingBox(bounds, Color.Green);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Drag & drop model to load mesh/texture.", 10, GetScreenHeight() - 20, 10, Color.DarkGray);
|
||||
if (selected)
|
||||
{
|
||||
DrawText("MODEL SELECTED", GetScreenWidth() - 110, 10, 10, Color.Green);
|
||||
}
|
||||
|
||||
DrawText("(c) Castle 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,111 +1,135 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Show the difference between perspective and orthographic projection
|
||||
* raylib [models] example - orthographic projection
|
||||
*
|
||||
* This program is heavily based on the geometric objects example
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* This example has been created using raylib 1.9.7 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example originally created with raylib 2.0, last time updated with raylib 3.7
|
||||
*
|
||||
* Copyright (c) 2018 Max Danielsson ref Ramon Santamaria (@raysan5)
|
||||
* Example contributed by Max Danielsson (@autious) 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) 2018-2025 Max Danielsson (@autious) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class OrthographicProjection
|
||||
public partial class OrthographicProjection : IExample
|
||||
{
|
||||
public const float FOVY_PERSPECTIVE = 45.0f;
|
||||
public const float WIDTH_ORTHOGRAPHIC = 10.0f;
|
||||
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Orthographic Projection";
|
||||
|
||||
public string Title => "raylib [models] example - orthographic projection";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = FOVY_PERSPECTIVE;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
camera.FovY = WIDTH_ORTHOGRAPHIC;
|
||||
camera.Projection = CameraProjection.Orthographic;
|
||||
}
|
||||
else
|
||||
{
|
||||
camera.FovY = FOVY_PERSPECTIVE;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Gold);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, -2.0f), 3.0f, 6.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawSphere(new Vector3(-1.0f, 0.0f, -2.0f), 1.0f, Color.Green);
|
||||
DrawSphereWires(new Vector3(1.0f, 0.0f, 2.0f), 2.0f, 16, 16, Color.Lime);
|
||||
|
||||
DrawCylinder(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.SkyBlue);
|
||||
DrawCylinderWires(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.DarkBlue);
|
||||
DrawCylinderWires(new Vector3(4.5f, -1.0f, 2.0f), 1.0f, 1.0f, 2.0f, 6, Color.Brown);
|
||||
|
||||
DrawCylinder(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Gold);
|
||||
DrawCylinderWires(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Pink);
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Press Spacebar to switch camera type", 10, GetScreenHeight() - 30, 20, Color.DarkGray);
|
||||
|
||||
if (camera.Projection == CameraProjection.Orthographic)
|
||||
{
|
||||
DrawText("ORTHOGRAPHIC", 10, 40, 20, Color.Black);
|
||||
}
|
||||
else if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
DrawText("PERSPECTIVE", 10, 40, 20, Color.Black);
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - orthographic projection");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new OrthographicProjection();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
camera.FovY = WIDTH_ORTHOGRAPHIC;
|
||||
camera.Projection = CameraProjection.Orthographic;
|
||||
}
|
||||
else
|
||||
{
|
||||
camera.FovY = FOVY_PERSPECTIVE;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Gold);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, -2.0f), 3.0f, 6.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawSphere(new Vector3(-1.0f, 0.0f, -2.0f), 1.0f, Color.Green);
|
||||
DrawSphereWires(new Vector3(1.0f, 0.0f, 2.0f), 2.0f, 16, 16, Color.Lime);
|
||||
|
||||
DrawCylinder(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.SkyBlue);
|
||||
DrawCylinderWires(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.DarkBlue);
|
||||
DrawCylinderWires(new Vector3(4.5f, -1.0f, 2.0f), 1.0f, 1.0f, 2.0f, 6, Color.Brown);
|
||||
|
||||
DrawCylinder(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Gold);
|
||||
DrawCylinderWires(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Pink);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Press Spacebar to switch camera type", 10, GetScreenHeight() - 30, 20, Color.DarkGray);
|
||||
|
||||
if (camera.Projection == CameraProjection.Orthographic)
|
||||
{
|
||||
DrawText("ORTHOGRAPHIC", 10, 40, 20, Color.Black);
|
||||
}
|
||||
else if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
DrawText("PERSPECTIVE", 10, 40, 20, Color.Black);
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
231
Examples/Models/PointRendering.cs
Normal file
231
Examples/Models/PointRendering.cs
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - point rendering
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.0
|
||||
*
|
||||
* Example contributed by Reese Gallagher (@satchelfrost) 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) 2024-2025 Reese Gallagher (@satchelfrost)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
[ExcludeFromBrowser("rlEnablePointMode needs glPolygonMode, which OpenGL ES/WebGL lacks (renders as triangles)")]
|
||||
public partial class PointRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxPoints = 10000000; // 10 million
|
||||
private const int MinPoints = 1000; // 1 thousand
|
||||
|
||||
public string Name => "Models / Point Rendering";
|
||||
|
||||
public string Title => "raylib [models] example - point rendering";
|
||||
|
||||
private static readonly Random Rand = new();
|
||||
|
||||
private Camera3D camera;
|
||||
private Vector3 position;
|
||||
private bool useDrawModelPoints;
|
||||
private bool numPointsChanged;
|
||||
private int numPoints;
|
||||
private Mesh mesh;
|
||||
private Model model;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
camera = new()
|
||||
{
|
||||
Position = new Vector3(3.0f, 3.0f, 3.0f),
|
||||
Target = new Vector3(0.0f, 0.0f, 0.0f),
|
||||
Up = new Vector3(0.0f, 1.0f, 0.0f),
|
||||
FovY = 45.0f,
|
||||
Projection = CameraProjection.Perspective
|
||||
};
|
||||
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
useDrawModelPoints = true;
|
||||
numPointsChanged = false;
|
||||
numPoints = 1000;
|
||||
|
||||
mesh = GenMeshPoints(numPoints);
|
||||
model = LoadModelFromMesh(mesh);
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
useDrawModelPoints = !useDrawModelPoints;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Up))
|
||||
{
|
||||
numPoints = (numPoints * 10 > MaxPoints) ? MaxPoints : numPoints * 10;
|
||||
numPointsChanged = true;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Down))
|
||||
{
|
||||
numPoints = (numPoints / 10 < MinPoints) ? MinPoints : numPoints / 10;
|
||||
numPointsChanged = true;
|
||||
}
|
||||
|
||||
// Upload a different point cloud size
|
||||
if (numPointsChanged)
|
||||
{
|
||||
UnloadModel(model);
|
||||
mesh = GenMeshPoints(numPoints);
|
||||
model = LoadModelFromMesh(mesh);
|
||||
numPointsChanged = false;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// The new method only uploads the points once to the GPU
|
||||
if (useDrawModelPoints)
|
||||
{
|
||||
DrawModelPoints(model, position, 1.0f, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The old method must continually draw the "points" (lines)
|
||||
for (var i = 0; i < numPoints; i++)
|
||||
{
|
||||
Vector3 pos = new(
|
||||
mesh.Vertices[i * 3 + 0],
|
||||
mesh.Vertices[i * 3 + 1],
|
||||
mesh.Vertices[i * 3 + 2]
|
||||
);
|
||||
Color color = new(
|
||||
mesh.Colors[i * 4 + 0],
|
||||
mesh.Colors[i * 4 + 1],
|
||||
mesh.Colors[i * 4 + 2],
|
||||
mesh.Colors[i * 4 + 3]
|
||||
);
|
||||
|
||||
DrawPoint3D(pos, color);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a unit sphere for reference
|
||||
DrawSphereWires(position, 1.0f, 10, 10, Color.Yellow);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw UI text
|
||||
DrawText($"Point Count: {numPoints}", 10, screenHeight - 50, 40, Color.White);
|
||||
DrawText("UP - Increase points", 10, 40, 20, Color.White);
|
||||
DrawText("DOWN - Decrease points", 10, 70, 20, Color.White);
|
||||
DrawText("SPACE - Drawing function", 10, 100, 20, Color.White);
|
||||
|
||||
if (useDrawModelPoints)
|
||||
{
|
||||
DrawText("Using: DrawModelPoints()", 10, 130, 20, Color.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("Using: DrawPoint3D()", 10, 130, 20, Color.Red);
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(model);
|
||||
}
|
||||
|
||||
// Generate a spherical point cloud
|
||||
private static unsafe Mesh GenMeshPoints(int numPoints)
|
||||
{
|
||||
Mesh mesh = new(numPoints, 1);
|
||||
mesh.AllocVertices();
|
||||
mesh.AllocColors();
|
||||
|
||||
// REF: https://en.wikipedia.org/wiki/Spherical_coordinate_system
|
||||
for (var i = 0; i < numPoints; i++)
|
||||
{
|
||||
var theta = MathF.PI * (float)Rand.NextDouble();
|
||||
var phi = 2.0f * MathF.PI * (float)Rand.NextDouble();
|
||||
var r = 10.0f * (float)Rand.NextDouble();
|
||||
|
||||
mesh.Vertices[i * 3 + 0] = r * MathF.Sin(theta) * MathF.Cos(phi);
|
||||
mesh.Vertices[i * 3 + 1] = r * MathF.Sin(theta) * MathF.Sin(phi);
|
||||
mesh.Vertices[i * 3 + 2] = r * MathF.Cos(theta);
|
||||
|
||||
var color = ColorFromHSV(r * 360.0f, 1.0f, 1.0f);
|
||||
|
||||
mesh.Colors[i * 4 + 0] = color.R;
|
||||
mesh.Colors[i * 4 + 1] = color.G;
|
||||
mesh.Colors[i * 4 + 2] = color.B;
|
||||
mesh.Colors[i * 4 + 3] = color.A;
|
||||
}
|
||||
|
||||
// Upload mesh data from CPU (RAM) to GPU (VRAM) memory
|
||||
UploadMesh(ref mesh, false);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// Draw a model points
|
||||
// WARNING: OpenGL ES 2.0 does not support point mode drawing
|
||||
private static void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
|
||||
{
|
||||
Rlgl.EnablePointMode();
|
||||
Rlgl.DisableBackfaceCulling();
|
||||
|
||||
DrawModel(model, position, scale, tint);
|
||||
|
||||
Rlgl.EnableBackfaceCulling();
|
||||
Rlgl.DisablePointMode();
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - point rendering");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new PointRendering();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
119
Examples/Models/RotatingCube.cs
Normal file
119
Examples/Models/RotatingCube.cs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - rotating cube
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jopestpe (@jopestpe)
|
||||
*
|
||||
* 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) 2025 Jopestpe (@jopestpe)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class RotatingCube : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Rotating Cube";
|
||||
|
||||
public string Title => "raylib [models] example - rotating cube";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private float rotation;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 3.0f, 3.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load image to create texture for the cube
|
||||
model = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
|
||||
var img = LoadImage("resources/cubicmap_atlas.png");
|
||||
var crop = ImageFromImage(img, new Rectangle(0, img.Height / 2.0f, img.Width / 2.0f, img.Height / 2.0f));
|
||||
texture = LoadTextureFromImage(crop);
|
||||
UnloadImage(img);
|
||||
UnloadImage(crop);
|
||||
|
||||
model.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = texture;
|
||||
|
||||
rotation = 0.0f;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
rotation += 1.0f;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw model defining: position, size, rotation-axis, rotation (degrees), size, and tint-color
|
||||
DrawModelEx(model, new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.5f, 1.0f, 0.0f),
|
||||
rotation, new Vector3(1.0f, 1.0f, 1.0f), Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - rotating cube");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new RotatingCube();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,50 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Skybox loading and drawing
|
||||
* raylib [models] example - skybox rendering
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2017 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.8, last time updated with raylib 4.0
|
||||
*
|
||||
* 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-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class SkyboxDemo
|
||||
[ExcludeFromBrowser("cubemap generation is too memory-heavy on web (upstream note)")]
|
||||
public partial class SkyboxDemo : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
// GLSL version used for shaders (330 desktop, 100 web/GLES)
|
||||
#if BROWSER
|
||||
public const int GlslVersion = 100;
|
||||
#else
|
||||
public const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Skybox Demo";
|
||||
|
||||
public string Title => "raylib [models] example - skybox rendering";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model skybox;
|
||||
private bool useHdr;
|
||||
private Shader shdrCubemap;
|
||||
private string skyboxFileName;
|
||||
private Texture2D panorama;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - skybox loading and drawing");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(1.0f, 1.0f, 1.0f);
|
||||
camera.Target = new Vector3(4.0f, 1.0f, 4.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
|
@ -34,14 +52,19 @@ public class SkyboxDemo
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load skybox model
|
||||
Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f);
|
||||
Model skybox = LoadModelFromMesh(cube);
|
||||
var cube = GenMeshCube(1.0f, 1.0f, 1.0f);
|
||||
skybox = LoadModelFromMesh(cube);
|
||||
|
||||
bool useHdr = false;
|
||||
// Set this to true to use an HDR Texture
|
||||
// NOTE: raylib must be built with HDR Support for this to work: SUPPORT_FILEFORMAT_HDR
|
||||
useHdr = false;
|
||||
|
||||
// Load skybox shader and set required locations
|
||||
// NOTE: Some locations are automatically set at shader loading
|
||||
Shader shdrSkybox = LoadShader("resources/shaders/glsl330/skybox.vs", "resources/shaders/glsl330/skybox.fs");
|
||||
var shdrSkybox = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/skybox.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/skybox.fs"
|
||||
);
|
||||
|
||||
Raylib.SetShaderValue(
|
||||
shdrSkybox,
|
||||
|
|
@ -67,9 +90,9 @@ public class SkyboxDemo
|
|||
Raylib.SetMaterialShader(ref skybox, 0, ref shdrSkybox);
|
||||
|
||||
// Load cubemap shader and setup required shader locations
|
||||
Shader shdrCubemap = LoadShader(
|
||||
"resources/shaders/glsl330/cubemap.vs",
|
||||
"resources/shaders/glsl330/cubemap.fs"
|
||||
shdrCubemap = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/cubemap.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/cubemap.fs"
|
||||
);
|
||||
Raylib.SetShaderValue(
|
||||
shdrCubemap,
|
||||
|
|
@ -79,14 +102,12 @@ public class SkyboxDemo
|
|||
);
|
||||
|
||||
// Load skybox
|
||||
string skyboxFileName = "resources/dresden_square_2k.hdr";
|
||||
|
||||
Texture2D panorama;
|
||||
skyboxFileName = "resources/dresden_square_2k.hdr";
|
||||
|
||||
if (useHdr)
|
||||
{
|
||||
panorama = LoadTexture(skyboxFileName);
|
||||
Texture2D cubemap = GenTextureCubemap(
|
||||
var cubemap = GenTextureCubemap(
|
||||
shdrCubemap,
|
||||
panorama,
|
||||
1024,
|
||||
|
|
@ -97,108 +118,130 @@ public class SkyboxDemo
|
|||
}
|
||||
else
|
||||
{
|
||||
Image img = LoadImage("resources/skybox.png");
|
||||
Texture2D cubemap = LoadTextureCubemap(img, CubemapLayout.AutoDetect);
|
||||
// TODO: WARNING: On PLATFORM_WEB it requires a big amount of memory to process input image
|
||||
// and generate the required cubemap image to be passed to rlLoadTextureCubemap()
|
||||
var img = LoadImage("resources/skybox.png");
|
||||
var cubemap = LoadTextureCubemap(img, CubemapLayout.AutoDetect);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadImage(img);
|
||||
}
|
||||
}
|
||||
|
||||
DisableCursor();
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
// Load new cubemap texture on drag & drop
|
||||
if (IsFileDropped())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
var files = Raylib.GetDroppedFiles();
|
||||
|
||||
// Load new cubemap texture on drag & drop
|
||||
if (IsFileDropped())
|
||||
if (files.Length == 1)
|
||||
{
|
||||
string[] files = Raylib.GetDroppedFiles();
|
||||
|
||||
if (files.Length == 1)
|
||||
if (IsFileExtension(files[0], ".png;.jpg;.hdr;.bmp;.tga"))
|
||||
{
|
||||
if (IsFileExtension(files[0], ".png;.jpg;.hdr;.bmp;.tga"))
|
||||
// Unload cubemap texture and load new one
|
||||
UnloadTexture(Raylib.GetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap));
|
||||
|
||||
if (useHdr)
|
||||
{
|
||||
// Unload cubemap texture and load new one
|
||||
UnloadTexture(Raylib.GetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap));
|
||||
|
||||
if (useHdr)
|
||||
{
|
||||
panorama = LoadTexture(files[0]);
|
||||
Texture2D cubemap = GenTextureCubemap(
|
||||
shdrCubemap,
|
||||
panorama,
|
||||
1024,
|
||||
PixelFormat.UncompressedR8G8B8A8
|
||||
);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadTexture(panorama);
|
||||
}
|
||||
else
|
||||
{
|
||||
Image img = LoadImage(files[0]);
|
||||
Texture2D cubemap = LoadTextureCubemap(img, CubemapLayout.AutoDetect);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadImage(img);
|
||||
}
|
||||
|
||||
skyboxFileName = files[0];
|
||||
panorama = LoadTexture(files[0]);
|
||||
var cubemap = GenTextureCubemap(
|
||||
shdrCubemap,
|
||||
panorama,
|
||||
1024,
|
||||
PixelFormat.UncompressedR8G8B8A8
|
||||
);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadTexture(panorama);
|
||||
}
|
||||
else
|
||||
{
|
||||
var img = LoadImage(files[0]);
|
||||
var cubemap = LoadTextureCubemap(img, CubemapLayout.AutoDetect);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadImage(img);
|
||||
}
|
||||
|
||||
skyboxFileName = files[0];
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
BeginMode3D(camera);
|
||||
|
||||
// We are inside the cube, we need to disable backface culling!
|
||||
Rlgl.DisableBackfaceCulling();
|
||||
Rlgl.DisableDepthMask();
|
||||
DrawModel(skybox, Vector3.Zero, 1.0f, Color.White);
|
||||
Rlgl.EnableBackfaceCulling();
|
||||
Rlgl.EnableDepthMask();
|
||||
// We are inside the cube, we need to disable backface culling!
|
||||
Rlgl.DisableBackfaceCulling();
|
||||
Rlgl.DisableDepthMask();
|
||||
DrawModel(skybox, Vector3.Zero, 1.0f, Color.White);
|
||||
Rlgl.EnableBackfaceCulling();
|
||||
Rlgl.EnableDepthMask();
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
EndMode3D();
|
||||
|
||||
if (useHdr)
|
||||
{
|
||||
DrawText(
|
||||
$"Panorama image from hdrihaven.com: {skyboxFileName}",
|
||||
10,
|
||||
GetScreenHeight() - 20,
|
||||
10,
|
||||
Color.Black
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText($": {skyboxFileName}", 10, GetScreenHeight() - 20, 10, Color.Black);
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
if (useHdr)
|
||||
{
|
||||
DrawText(
|
||||
$"Panorama image from hdrihaven.com: {skyboxFileName}",
|
||||
10,
|
||||
GetScreenHeight() - 20,
|
||||
10,
|
||||
Color.Black
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText($": {skyboxFileName}", 10, GetScreenHeight() - 20, 10, Color.Black);
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(Raylib.GetMaterial(ref skybox, 0).Shader);
|
||||
UnloadTexture(Raylib.GetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap));
|
||||
|
||||
UnloadModel(skybox);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - skybox rendering");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SkyboxDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -215,10 +258,10 @@ public class SkyboxDemo
|
|||
|
||||
// STEP 1: Setup framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
uint rbo = Rlgl.LoadTextureDepth(size, size, true);
|
||||
var rbo = Rlgl.LoadTextureDepth(size, size, true);
|
||||
cubemap.Id = Rlgl.LoadTextureCubemap(null, size, format, 1);
|
||||
|
||||
uint fbo = Rlgl.LoadFramebuffer();
|
||||
var fbo = Rlgl.LoadFramebuffer();
|
||||
Rlgl.FramebufferAttach(
|
||||
fbo,
|
||||
rbo,
|
||||
|
|
@ -235,7 +278,7 @@ public class SkyboxDemo
|
|||
);
|
||||
|
||||
// Check if framebuffer is complete with attachments (valid)
|
||||
if (Rlgl.FramebufferComplete(fbo))
|
||||
if (Rlgl.FramebufferComplete(fbo) != 0)
|
||||
{
|
||||
Console.WriteLine($"FBO: [ID {fbo}] Framebuffer object created successfully");
|
||||
}
|
||||
|
|
@ -247,7 +290,7 @@ public class SkyboxDemo
|
|||
Rlgl.EnableShader(shader.Id);
|
||||
|
||||
// Define projection matrix and send it to shader
|
||||
Matrix4x4 matFboProjection = Raymath.MatrixPerspective(
|
||||
var matFboProjection = Raymath.MatrixPerspective(
|
||||
90.0f * DEG2RAD,
|
||||
1.0f,
|
||||
Rlgl.CULL_DISTANCE_NEAR,
|
||||
|
|
@ -256,14 +299,14 @@ public class SkyboxDemo
|
|||
Rlgl.SetUniformMatrix(shader.Locs[(int)ShaderLocationIndex.MatrixProjection], matFboProjection);
|
||||
|
||||
// Define view matrix for every side of the cubemap
|
||||
Matrix4x4[] fboViews = new[]
|
||||
var fboViews = new[]
|
||||
{
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3(-1.0f, 0.0f, 0.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 1.0f, 0.0f, 0.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3(-1.0f, 0.0f, 0.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, 1.0f, 0.0f), new Vector3( 0.0f, 0.0f, 1.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, -1.0f, 0.0f), new Vector3( 0.0f, 0.0f, -1.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, 0.0f, -1.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, 0.0f, 1.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, 0.0f, -1.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
};
|
||||
|
||||
// Set viewport to current fbo dimensions
|
||||
|
|
@ -273,7 +316,7 @@ public class SkyboxDemo
|
|||
Rlgl.ActiveTextureSlot(0);
|
||||
Rlgl.EnableTexture(panorama.Id);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
// Set the view matrix for the current cube face
|
||||
Rlgl.SetUniformMatrix(shader.Locs[(int)ShaderLocationIndex.MatrixView], fboViews[i]);
|
||||
|
|
|
|||
|
|
@ -1,161 +1,153 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - rlgl module usage with push/pop matrix transformations
|
||||
* raylib [models] example - rlgl solar system
|
||||
*
|
||||
* This example uses [rlgl] module funtionality (pseudo-OpenGL 1.1 style coding)
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* This example has been created using raylib 2.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* NOTE: This example uses [rlgl] module functionality (pseudo-OpenGL 1.1 style coding)
|
||||
*
|
||||
* Copyright (c) 2018 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 4.0
|
||||
*
|
||||
* 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) 2018-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class SolarSystem
|
||||
public partial class SolarSystem : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const float sunRadius = 4.0f;
|
||||
private const float earthRadius = 0.6f;
|
||||
private const float earthOrbitRadius = 8.0f;
|
||||
private const float moonRadius = 0.16f;
|
||||
private const float moonOrbitRadius = 1.5f;
|
||||
|
||||
public string Name => "Models / Solar System";
|
||||
|
||||
public string Title => "raylib [models] example - rlgl solar system";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
private float rotationSpeed;
|
||||
|
||||
private float earthRotation;
|
||||
private float earthOrbitRotation;
|
||||
private float moonRotation;
|
||||
private float moonOrbitRotation;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
const float sunRadius = 4.0f;
|
||||
const float earthRadius = 0.6f;
|
||||
const float earthOrbitRadius = 8.0f;
|
||||
const float moonRadius = 0.16f;
|
||||
const float moonOrbitRadius = 1.5f;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - rlgl module usage with push/pop matrix transformations");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(16.0f, 16.0f, 16.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(16.0f, 16.0f, 16.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// General system rotation speed
|
||||
float rotationSpeed = 0.2f;
|
||||
// Rotation of earth around itself (days) in degrees
|
||||
float earthRotation = 0.0f;
|
||||
// Rotation of earth around the Sun (years) in degrees
|
||||
float earthOrbitRotation = 0.0f;
|
||||
// Rotation of moon around itself
|
||||
float moonRotation = 0.0f;
|
||||
// Rotation of moon around earth in degrees
|
||||
float moonOrbitRotation = 0.0f;
|
||||
rotationSpeed = 0.2f; // General system rotation speed
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
earthRotation = 0.0f; // Rotation of earth around itself (days) in degrees
|
||||
earthOrbitRotation = 0.0f; // Rotation of earth around the Sun (years) in degrees
|
||||
moonRotation = 0.0f; // Rotation of moon around itself
|
||||
moonOrbitRotation = 0.0f; // Rotation of moon around earth in degrees
|
||||
}
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
earthRotation += (5.0f * rotationSpeed);
|
||||
earthOrbitRotation += (365 / 360.0f * (5.0f * rotationSpeed) * rotationSpeed);
|
||||
moonRotation += (2.0f * rotationSpeed);
|
||||
moonOrbitRotation += (8.0f * rotationSpeed);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
earthRotation += (5.0f * rotationSpeed);
|
||||
earthOrbitRotation += (365 / 360.0f * (5.0f * rotationSpeed) * rotationSpeed);
|
||||
moonRotation += (2.0f * rotationSpeed);
|
||||
moonOrbitRotation += (8.0f * rotationSpeed);
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
BeginMode3D(camera);
|
||||
|
||||
BeginMode3D(camera);
|
||||
Rlgl.PushMatrix();
|
||||
// Scale Sun
|
||||
Rlgl.Scalef(sunRadius, sunRadius, sunRadius);
|
||||
// Draw the Sun
|
||||
DrawSphereBasic(Color.Gold);
|
||||
Rlgl.PopMatrix();
|
||||
|
||||
Rlgl.PushMatrix();
|
||||
// Scale Sun
|
||||
Rlgl.Scalef(sunRadius, sunRadius, sunRadius);
|
||||
// Draw the Sun
|
||||
DrawSphereBasic(Color.Gold);
|
||||
Rlgl.PopMatrix();
|
||||
Rlgl.PushMatrix();
|
||||
// Rotation for Earth orbit around Sun
|
||||
Rlgl.Rotatef(earthOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Translation for Earth orbit
|
||||
Rlgl.Translatef(earthOrbitRadius, 0.0f, 0.0f);
|
||||
|
||||
Rlgl.PushMatrix();
|
||||
// Rotation for Earth orbit around Sun
|
||||
Rlgl.Rotatef(earthOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Translation for Earth orbit
|
||||
Rlgl.Translatef(earthOrbitRadius, 0.0f, 0.0f);
|
||||
// Rotation for Earth orbit around Sun inverted
|
||||
Rlgl.Rotatef(-earthOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
Rlgl.PushMatrix();
|
||||
// Rotation for Earth itself
|
||||
Rlgl.Rotatef(earthRotation, 0.25f, 1.0f, 0.0f);
|
||||
// Scale Earth
|
||||
Rlgl.Scalef(earthRadius, earthRadius, earthRadius);
|
||||
|
||||
Rlgl.PushMatrix();
|
||||
// Rotation for Earth itself
|
||||
Rlgl.Rotatef(earthRotation, 0.25f, 1.0f, 0.0f);
|
||||
// Scale Earth
|
||||
Rlgl.Scalef(earthRadius, earthRadius, earthRadius);
|
||||
// Draw the Earth
|
||||
DrawSphereBasic(Color.Blue);
|
||||
Rlgl.PopMatrix();
|
||||
|
||||
// Draw the Earth
|
||||
DrawSphereBasic(Color.Blue);
|
||||
Rlgl.PopMatrix();
|
||||
// Rotation for Moon orbit around Earth
|
||||
Rlgl.Rotatef(moonOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Translation for Moon orbit
|
||||
Rlgl.Translatef(moonOrbitRadius, 0.0f, 0.0f);
|
||||
// Rotation for Moon itself
|
||||
Rlgl.Rotatef(moonRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Scale Moon
|
||||
Rlgl.Scalef(moonRadius, moonRadius, moonRadius);
|
||||
|
||||
// Rotation for Moon orbit around Earth
|
||||
Rlgl.Rotatef(moonOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Translation for Moon orbit
|
||||
Rlgl.Translatef(moonOrbitRadius, 0.0f, 0.0f);
|
||||
// Rotation for Moon orbit around Earth inverted
|
||||
Rlgl.Rotatef(-moonOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Rotation for Moon itself
|
||||
Rlgl.Rotatef(moonRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Scale Moon
|
||||
Rlgl.Scalef(moonRadius, moonRadius, moonRadius);
|
||||
// Draw the Moon
|
||||
DrawSphereBasic(Color.LightGray);
|
||||
Rlgl.PopMatrix();
|
||||
|
||||
// Draw the Moon
|
||||
DrawSphereBasic(Color.LightGray);
|
||||
Rlgl.PopMatrix();
|
||||
// Some reference elements (not affected by previous matrix transformations)
|
||||
DrawCircle3D(
|
||||
new Vector3(0.0f, 0.0f, 0.0f),
|
||||
earthOrbitRadius,
|
||||
new Vector3(1, 0, 0),
|
||||
90.0f,
|
||||
Fade(Color.Red, 0.5f)
|
||||
);
|
||||
DrawGrid(20, 1.0f);
|
||||
|
||||
// Some reference elements (not affected by previous matrix transformations)
|
||||
DrawCircle3D(
|
||||
new Vector3(0.0f, 0.0f, 0.0f),
|
||||
earthOrbitRadius,
|
||||
new Vector3(1, 0, 0),
|
||||
90.0f,
|
||||
ColorAlpha(Color.Red, 0.5f)
|
||||
);
|
||||
DrawGrid(20, 1.0f);
|
||||
EndMode3D();
|
||||
|
||||
EndMode3D();
|
||||
DrawText("EARTH ORBITING AROUND THE SUN!", 400, 10, 20, Color.Maroon);
|
||||
DrawFPS(10, 10);
|
||||
|
||||
DrawText("EARTH ORBITING AROUND THE SUN!", 400, 10, 20, Color.Maroon);
|
||||
DrawFPS(10, 10);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
// Draw sphere without any matrix transformation
|
||||
// NOTE: Sphere is drawn in world position ( 0, 0, 0 ) with radius 1.0f
|
||||
static void DrawSphereBasic(Color color)
|
||||
private static void DrawSphereBasic(Color color)
|
||||
{
|
||||
int rings = 16;
|
||||
int slices = 16;
|
||||
var rings = 16;
|
||||
var slices = 16;
|
||||
|
||||
Rlgl.Begin(DrawMode.Triangles);
|
||||
Rlgl.Color4ub(color.R, color.G, color.B, color.A);
|
||||
|
||||
for (int i = 0; i < (rings + 2); i++)
|
||||
for (var i = 0; i < (rings + 2); i++)
|
||||
{
|
||||
for (int j = 0; j < slices; j++)
|
||||
for (var j = 0; j < slices; j++)
|
||||
{
|
||||
Rlgl.Vertex3f(
|
||||
MathF.Cos(DEG2RAD * (270 + (180 / (rings + 1)) * i)) * MathF.Sin(DEG2RAD * (j * 360 / slices)),
|
||||
|
|
@ -192,5 +184,32 @@ public class SolarSystem
|
|||
}
|
||||
Rlgl.End();
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - rlgl solar system");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SolarSystem();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
163
Examples/Models/TesseractView.cs
Normal file
163
Examples/Models/TesseractView.cs
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - tesseract view
|
||||
*
|
||||
* NOTE: This example only works on platforms that support drag & drop (Windows, Linux, OSX, Html5?)
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Timothy van der Valk (@arceryz) 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) 2024-2025 Timothy van der Valk (@arceryz) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class TesseractView : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Tesseract View";
|
||||
|
||||
public string Title => "raylib [models] example - tesseract view";
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
private Camera3D camera;
|
||||
|
||||
// Find the coordinates by setting XYZW to +-1
|
||||
private Vector4[] tesseract;
|
||||
|
||||
private float rotation;
|
||||
private Vector3[] transformed;
|
||||
private float[] wValues;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new Camera3D();
|
||||
camera.Position = new Vector3(4.0f, 4.0f, 4.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 0.0f, 1.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 50.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera mode type
|
||||
|
||||
// Find the coordinates by setting XYZW to +-1
|
||||
tesseract = new Vector4[16]
|
||||
{
|
||||
new( 1, 1, 1, 1 ), new( 1, 1, 1, -1 ),
|
||||
new( 1, 1, -1, 1 ), new( 1, 1, -1, -1 ),
|
||||
new( 1, -1, 1, 1 ), new( 1, -1, 1, -1 ),
|
||||
new( 1, -1, -1, 1 ), new( 1, -1, -1, -1 ),
|
||||
new(-1, 1, 1, 1 ), new(-1, 1, 1, -1 ),
|
||||
new(-1, 1, -1, 1 ), new(-1, 1, -1, -1 ),
|
||||
new(-1, -1, 1, 1 ), new(-1, -1, 1, -1 ),
|
||||
new(-1, -1, -1, 1 ), new(-1, -1, -1, -1 ),
|
||||
};
|
||||
|
||||
rotation = 0.0f;
|
||||
transformed = new Vector3[16];
|
||||
wValues = new float[16];
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
rotation = DEG2RAD * 45.0f * (float)GetTime();
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
Vector4 p = tesseract[i];
|
||||
|
||||
// Rotate the XW part of the vector
|
||||
Vector2 rotXW = Vector2Rotate(new Vector2(p.X, p.W), rotation);
|
||||
p.X = rotXW.X;
|
||||
p.W = rotXW.Y;
|
||||
|
||||
// Projection from XYZW to XYZ from perspective point (0, 0, 0, 3)
|
||||
// NOTE: Trace a ray from (0, 0, 0, 3) > p and continue until W = 0
|
||||
float c = 3.0f / (3.0f - p.W);
|
||||
p.X = c * p.X;
|
||||
p.Y = c * p.Y;
|
||||
p.Z = c * p.Z;
|
||||
|
||||
// Split XYZ coordinate and W values later for drawing
|
||||
transformed[i] = new Vector3(p.X, p.Y, p.Z);
|
||||
wValues[i] = p.W;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
// Draw spheres to indicate the W value
|
||||
DrawSphere(transformed[i], MathF.Abs(wValues[i] * 0.1f), Color.Red);
|
||||
|
||||
for (int j = 0; j < 16; j++)
|
||||
{
|
||||
// Two lines are connected if they differ by 1 coordinate
|
||||
// This way we dont have to keep an edge list
|
||||
Vector4 v1 = tesseract[i];
|
||||
Vector4 v2 = tesseract[j];
|
||||
int diff = (v1.X == v2.X ? 1 : 0) + (v1.Y == v2.Y ? 1 : 0) + (v1.Z == v2.Z ? 1 : 0) + (v1.W == v2.W ? 1 : 0);
|
||||
|
||||
// Draw only differing by 1 coordinate and the lower index only (duplicate lines)
|
||||
if (diff == 3 && i < j)
|
||||
{
|
||||
DrawLine3D(transformed[i], transformed[j], Color.Maroon);
|
||||
}
|
||||
}
|
||||
}
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - tesseract view");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new TesseractView();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,117 +1,141 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Waving cubes
|
||||
* raylib [models] example - waving cubes
|
||||
*
|
||||
* This example has been created using raylib 2.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 3.7
|
||||
*
|
||||
* Example contributed by Codecat (@codecat) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2019 Codecat (@codecat) and 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) 2019-2025 Codecat (@codecat) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class WavingCubes
|
||||
public partial class WavingCubes : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
// Specify the amount of blocks in each direction
|
||||
private const int numBlocks = 15;
|
||||
|
||||
public string Name => "Models / Waving Cubes";
|
||||
|
||||
public string Title => "raylib [models] example - waving cubes";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialize the camera
|
||||
camera = new();
|
||||
camera.Position = new Vector3(30.0f, 20.0f, 30.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 70.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var time = GetTime();
|
||||
|
||||
// Calculate time scale for cube position and size
|
||||
var scale = (2.0f + (float)Math.Sin(time)) * 0.7f;
|
||||
|
||||
// Move camera around the scene
|
||||
var cameraTime = time * 0.3;
|
||||
camera.Position.X = (float)Math.Cos(cameraTime) * 40.0f;
|
||||
camera.Position.Z = (float)Math.Sin(cameraTime) * 40.0f;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 5.0f);
|
||||
|
||||
for (var x = 0; x < numBlocks; x++)
|
||||
{
|
||||
for (var y = 0; y < numBlocks; y++)
|
||||
{
|
||||
for (var z = 0; z < numBlocks; z++)
|
||||
{
|
||||
// Scale of the blocks depends on x/y/z positions
|
||||
var blockScale = (x + y + z) / 30.0f;
|
||||
|
||||
// Scatter makes the waving effect by adding blockScale over time
|
||||
var scatter = (float)Math.Sin(blockScale * 20.0f + (float)(time * 4.0f));
|
||||
|
||||
// Calculate the cube position
|
||||
Vector3 cubePos = new(
|
||||
(float)(x - numBlocks / 2) * (scale * 3.0f) + scatter,
|
||||
(float)(y - numBlocks / 2) * (scale * 2.0f) + scatter,
|
||||
(float)(z - numBlocks / 2) * (scale * 3.0f) + scatter
|
||||
);
|
||||
|
||||
// Pick a color with a hue depending on cube position for the rainbow color effect
|
||||
// NOTE: This function is quite costly to be done per cube and frame,
|
||||
// pre-catching the results into a separate array could improve performance
|
||||
var cubeColor = ColorFromHSV((float)(((x + y + z) * 18) % 360), 0.75f, 0.9f);
|
||||
|
||||
// Calculate cube size
|
||||
var cubeSize = (2.4f - scale) * blockScale;
|
||||
|
||||
// And finally, draw the cube!
|
||||
DrawCube(cubePos, cubeSize, cubeSize, cubeSize, cubeColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - waving cubes");
|
||||
|
||||
// Initialize the camera
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(30.0f, 20.0f, 30.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 70.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Specify the amount of blocks in each direction
|
||||
const int numBlocks = 15;
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new WavingCubes();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
double time = GetTime();
|
||||
|
||||
// Calculate time scale for cube position and size
|
||||
float scale = (2.0f + (float)Math.Sin(time)) * 0.7f;
|
||||
|
||||
// Move camera around the scene
|
||||
double cameraTime = time * 0.3;
|
||||
camera.Position.X = (float)Math.Cos(cameraTime) * 40.0f;
|
||||
camera.Position.Z = (float)Math.Sin(cameraTime) * 40.0f;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 5.0f);
|
||||
|
||||
for (int x = 0; x < numBlocks; x++)
|
||||
{
|
||||
for (int y = 0; y < numBlocks; y++)
|
||||
{
|
||||
for (int z = 0; z < numBlocks; z++)
|
||||
{
|
||||
// Scale of the blocks depends on x/y/z positions
|
||||
float blockScale = (x + y + z) / 30.0f;
|
||||
|
||||
// Scatter makes the waving effect by adding blockScale over time
|
||||
float scatter = (float)Math.Sin(blockScale * 20.0f + (float)(time * 4.0f));
|
||||
|
||||
// Calculate the cube position
|
||||
Vector3 cubePos = new(
|
||||
(float)(x - numBlocks / 2) * (scale * 3.0f) + scatter,
|
||||
(float)(y - numBlocks / 2) * (scale * 2.0f) + scatter,
|
||||
(float)(z - numBlocks / 2) * (scale * 3.0f) + scatter
|
||||
);
|
||||
|
||||
// Pick a color with a hue depending on cube position for the rainbow color effect
|
||||
Color cubeColor = ColorFromHSV((float)(((x + y + z) * 18) % 360), 0.75f, 0.9f);
|
||||
|
||||
// Calculate cube size
|
||||
float cubeSize = (2.4f - scale) * blockScale;
|
||||
|
||||
// And finally, draw the cube!
|
||||
DrawCube(cubePos, cubeSize, cubeSize, cubeSize, cubeColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,162 +1,196 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Plane rotations (yaw, pitch, roll)
|
||||
* raylib [models] example - yaw pitch roll
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 1.8, last time updated with raylib 4.0
|
||||
*
|
||||
* Example contributed by Berni (@Berni8k) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2017-2021 Berni (@Berni8k) and 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-2025 Berni (@Berni8k) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class YawPitchRoll
|
||||
public partial class YawPitchRoll : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Yaw Pitch Roll";
|
||||
|
||||
public string Title => "raylib [models] example - yaw pitch roll";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
|
||||
private float pitch;
|
||||
private float roll;
|
||||
private float yaw;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 50.0f, -120.0f);// Camera position perspective
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 30.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera type
|
||||
|
||||
model = LoadModel("resources/models/obj/plane.obj"); // Load model
|
||||
texture = LoadTexture("resources/models/obj/plane_diffuse.png"); // Load model texture
|
||||
|
||||
SetTextureWrap(texture, TextureWrap.Repeat); // Force Repeat to avoid issue on Web version
|
||||
|
||||
model.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = texture; // Set map diffuse texture
|
||||
|
||||
pitch = 0.0f;
|
||||
roll = 0.0f;
|
||||
yaw = 0.0f;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Plane pitch (x-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
pitch += 0.6f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
pitch -= 0.6f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pitch > 0.3f)
|
||||
{
|
||||
pitch -= 0.3f;
|
||||
}
|
||||
else if (pitch < -0.3f)
|
||||
{
|
||||
pitch += 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
// Plane yaw (y-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
yaw += 1.0f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
yaw -= 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yaw > 0.0f)
|
||||
{
|
||||
yaw -= 0.5f;
|
||||
}
|
||||
else if (yaw < 0.0f)
|
||||
{
|
||||
yaw += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
// Plane roll (z-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
roll += 1.0f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
roll -= 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (roll > 0.0f)
|
||||
{
|
||||
roll -= 0.5f;
|
||||
}
|
||||
else if (roll < 0.0f)
|
||||
{
|
||||
roll += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
// Tranformation matrix for rotations
|
||||
model.Transform = MatrixRotateXYZ(new Vector3(DEG2RAD * pitch, DEG2RAD * yaw, DEG2RAD * roll));
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw 3D model (recomended to draw 3D always before 2D)
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw 3d model with texture
|
||||
DrawModel(model, new Vector3(0.0f, -8.0f, 0.0f), 1.0f, Color.White);
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw controls info
|
||||
DrawRectangle(30, 370, 260, 70, Fade(Color.Green, 0.5f));
|
||||
DrawRectangleLines(30, 370, 260, 70, Fade(Color.DarkGreen, 0.5f));
|
||||
DrawText("Pitch controlled with: KEY_UP / KEY_DOWN", 40, 380, 10, Color.DarkGray);
|
||||
DrawText("Roll controlled with: KEY_LEFT / KEY_RIGHT", 40, 400, 10, Color.DarkGray);
|
||||
DrawText("Yaw controlled with: KEY_A / KEY_S", 40, 420, 10, Color.DarkGray);
|
||||
|
||||
DrawText(
|
||||
"(c) WWI Plane Model created by GiaHanLam",
|
||||
screenWidth - 240,
|
||||
screenHeight - 20,
|
||||
10,
|
||||
Color.DarkGray
|
||||
);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(model);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - plane rotations (yaw, pitch, roll)");
|
||||
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(0.0f, 50.0f, -120.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 30.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Model loading
|
||||
Model model = LoadModel("resources/models/obj/plane.obj");
|
||||
Texture2D texture = LoadTexture("resources/models/obj/plane_diffuse.png");
|
||||
model.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = texture;
|
||||
|
||||
float pitch = 0.0f;
|
||||
float roll = 0.0f;
|
||||
float yaw = 0.0f;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - yaw pitch roll");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
while (!WindowShouldClose())
|
||||
var game = new YawPitchRoll();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Plane roll (x-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
pitch += 0.6f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
pitch -= 0.6f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pitch > 0.3f)
|
||||
{
|
||||
pitch -= 0.3f;
|
||||
}
|
||||
else if (pitch < -0.3f)
|
||||
{
|
||||
pitch += 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
// Plane yaw (y-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
yaw += 1.0f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
yaw -= 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yaw > 0.0f)
|
||||
{
|
||||
yaw -= 0.5f;
|
||||
}
|
||||
else if (yaw < 0.0f)
|
||||
{
|
||||
yaw += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
// Plane pitch (z-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
roll += 1.0f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
roll -= 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (roll > 0.0f)
|
||||
{
|
||||
roll -= 0.5f;
|
||||
}
|
||||
else if (roll < 0.0f)
|
||||
{
|
||||
roll += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
// Tranformation matrix for rotations
|
||||
model.Transform = MatrixRotateXYZ(new Vector3(DEG2RAD * pitch, DEG2RAD * yaw, DEG2RAD * roll));
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw 3D model (recomended to draw 3D always before 2D)
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw 3d model with texture
|
||||
DrawModel(model, new Vector3(0.0f, -8.0f, 0.0f), 1.0f, Color.White);
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw controls info
|
||||
DrawRectangle(30, 370, 260, 70, Fade(Color.Green, 0.5f));
|
||||
DrawRectangleLines(30, 370, 260, 70, Fade(Color.DarkGreen, 0.5f));
|
||||
DrawText("Pitch controlled with: KEY_UP / KEY_DOWN", 40, 380, 10, Color.DarkGray);
|
||||
DrawText("Roll controlled with: KEY_LEFT / KEY_RIGHT", 40, 400, 10, Color.DarkGray);
|
||||
DrawText("Yaw controlled with: KEY_A / KEY_S", 40, 420, 10, Color.DarkGray);
|
||||
|
||||
DrawText(
|
||||
"(c) WWI Plane Model created by GiaHanLam",
|
||||
screenWidth - 240,
|
||||
screenHeight - 20,
|
||||
10,
|
||||
Color.DarkGray
|
||||
);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue