feat: backporting existing raylib-cs examples and new official raylib examples to WASM, adopting raylib's original code style
This commit is contained in:
parent
6aa91e3097
commit
f804ab7773
35 changed files with 38997 additions and 10578 deletions
166
Examples/Shaders/AsciiRendering.cs
Normal file
166
Examples/Shaders/AsciiRendering.cs
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - ascii rendering
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Maicon Santana (@maiconpintoabreu) 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 Maicon Santana (@maiconpintoabreu)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class AsciiRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Ascii Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - ascii rendering";
|
||||
|
||||
private Texture2D fudesumi;
|
||||
private Texture2D raysan;
|
||||
private Shader shader;
|
||||
private int resolutionLoc;
|
||||
private int fontSizeLoc;
|
||||
private float fontSize;
|
||||
private Vector2 circlePos;
|
||||
private float circleSpeed;
|
||||
private RenderTexture2D target;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Texture to test static drawing
|
||||
fudesumi = LoadTexture("resources/fudesumi.png");
|
||||
// Texture to test moving drawing
|
||||
raysan = LoadTexture("resources/raysan.png");
|
||||
|
||||
// Load shader to be used on postprocessing
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/ascii.fs");
|
||||
|
||||
// These locations are used to send data to the GPU
|
||||
resolutionLoc = GetShaderLocation(shader, "resolution");
|
||||
fontSizeLoc = GetShaderLocation(shader, "fontSize");
|
||||
|
||||
// Set the character size for the ASCII effect
|
||||
// Fontsize should be 9 or more
|
||||
fontSize = 9.0f;
|
||||
|
||||
// Send the updated values to the shader
|
||||
var resolution = new[] { (float)screenWidth, (float)screenHeight };
|
||||
Raylib.SetShaderValue(shader, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
|
||||
|
||||
circlePos = new Vector2(40.0f, screenHeight * 0.5f);
|
||||
circleSpeed = 1.0f;
|
||||
|
||||
// RenderTexture to apply the postprocessing later
|
||||
target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
circlePos.X += circleSpeed;
|
||||
if ((circlePos.X > 200.0f) || (circlePos.X < 40.0f))
|
||||
{
|
||||
circleSpeed *= -1; // Revert speed
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Left) && (fontSize > 9.0))
|
||||
{
|
||||
fontSize -= 1; // Reduce fontSize
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Right) && (fontSize < 15.0))
|
||||
{
|
||||
fontSize += 1; // Increase fontSize
|
||||
}
|
||||
|
||||
// Set fontsize for the shader
|
||||
Raylib.SetShaderValue(shader, fontSizeLoc, fontSize, ShaderUniformDataType.Float);
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.White);
|
||||
|
||||
// Draw scene in our render texture
|
||||
DrawTexture(fudesumi, 500, -30, Color.White);
|
||||
DrawTextureV(raysan, circlePos, Color.White);
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginShaderMode(shader);
|
||||
// Draw the scene texture (that we rendered earlier) to the screen
|
||||
// The shader will process every pixel of this texture
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, target.Texture.Width, -target.Texture.Height),
|
||||
new Vector2(0, 0),
|
||||
Color.White
|
||||
);
|
||||
EndShaderMode();
|
||||
|
||||
DrawRectangle(0, 0, screenWidth, 40, Color.Black);
|
||||
DrawText($"Ascii effect - FontSize:{fontSize,2:F0} - [Left] -1 [Right] +1 ", 120, 10, 20, Color.LightGray);
|
||||
DrawFPS(10, 10);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTexture(target); // Unload render texture
|
||||
|
||||
UnloadShader(shader); // Unload shader
|
||||
UnloadTexture(fudesumi); // Unload texture
|
||||
UnloadTexture(raysan); // Unload texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - ascii rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AsciiRendering();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,26 +2,21 @@
|
|||
*
|
||||
* raylib [shaders] example - basic lighting
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3).
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* 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 originally created with raylib 3.0, last time updated with raylib 4.2
|
||||
*
|
||||
* Example contributed by Chris Camacho (@codifies) and reviewed by Ramon Santamaria (@raysan5)
|
||||
* Example contributed by Chris Camacho (@chriscamacho) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Chris Camacho (@codifies - http://bedroomcoders.co.uk/) notes:
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* This is based on the PBR lighting example, but greatly simplified to aid learning...
|
||||
* actually there is very little of the PBR example left!
|
||||
* When I first looked at the bewildering complexity of the PBR example I feared
|
||||
* I would never understand how I could do simple lighting with raylib however its
|
||||
* a testement to the authors of raylib (including rlights.h) that the example
|
||||
* came together fairly quickly.
|
||||
*
|
||||
* Copyright (c) 2019 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2019-2025 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -31,52 +26,55 @@ using Examples.Shared;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class BasicLighting
|
||||
public class BasicLighting : IExample
|
||||
{
|
||||
const int GLSL_VERSION = 330;
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public unsafe static int Main()
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Basic Lighting";
|
||||
|
||||
public string Title => "raylib [shaders] example - basic lighting";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Shader shader;
|
||||
private Light[] lights;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(2.0f, 4.0f, 6.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 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(2.0f, 4.0f, 6.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 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 plane model from a generated mesh
|
||||
Model model = LoadModelFromMesh(GenMeshPlane(10.0f, 10.0f, 3, 3));
|
||||
Model cube = LoadModelFromMesh(GenMeshCube(2.0f, 4.0f, 2.0f));
|
||||
|
||||
Shader shader = LoadShader(
|
||||
"resources/shaders/glsl330/lighting.vs",
|
||||
"resources/shaders/glsl330/lighting.fs"
|
||||
// Load basic lighting shader
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/lighting.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/lighting.fs"
|
||||
);
|
||||
|
||||
// Get some required shader loactions
|
||||
// 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
|
||||
int ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
float[] ambient = new[] { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||
// Ambient light level (some basic lighting)
|
||||
var ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
var ambient = new[] { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||
Raylib.SetShaderValue(shader, ambientLoc, ambient, ShaderUniformDataType.Vec4);
|
||||
|
||||
// Assign out lighting shader to model
|
||||
model.Materials[0].Shader = shader;
|
||||
cube.Materials[0].Shader = shader;
|
||||
|
||||
// Using 4 point lights: Color.gold, Color.red, Color.green and Color.blue
|
||||
Light[] lights = new Light[4];
|
||||
// Create lights
|
||||
lights = new Light[4];
|
||||
lights[0] = Rlights.CreateLight(
|
||||
0,
|
||||
LightType.Point,
|
||||
|
|
@ -109,114 +107,116 @@ public class BasicLighting
|
|||
Color.Blue,
|
||||
shader
|
||||
);
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// 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
|
||||
);
|
||||
|
||||
// Check key inputs to enable/disable lights
|
||||
if (IsKeyPressed(KeyboardKey.Y))
|
||||
{
|
||||
lights[0].Enabled = !lights[0].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
lights[1].Enabled = !lights[1].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.G))
|
||||
{
|
||||
lights[2].Enabled = !lights[2].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.B))
|
||||
{
|
||||
lights[3].Enabled = !lights[3].Enabled;
|
||||
}
|
||||
|
||||
// Update light values (actually, only enable/disable them)
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
Rlights.UpdateLightValues(shader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
BeginShaderMode(shader);
|
||||
|
||||
DrawPlane(Vector3.Zero, new Vector2(10.0f, 10.0f), Color.White);
|
||||
DrawCube(Vector3.Zero, 2.0f, 4.0f, 2.0f, Color.White);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
// Draw spheres to show where the lights are
|
||||
for (var i = 0; i < 4; 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));
|
||||
}
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
DrawText("Use keys [Y][R][G][B] to toggle lights", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader); // Unload shader
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BasicLighting();
|
||||
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.Y))
|
||||
{
|
||||
lights[0].Enabled = !lights[0].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
lights[1].Enabled = !lights[1].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.G))
|
||||
{
|
||||
lights[2].Enabled = !lights[2].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.B))
|
||||
{
|
||||
lights[3].Enabled = !lights[3].Enabled;
|
||||
}
|
||||
|
||||
// Update light values (actually, only enable/disable them)
|
||||
Rlights.UpdateLightValues(shader, lights[0]);
|
||||
Rlights.UpdateLightValues(shader, lights[1]);
|
||||
Rlights.UpdateLightValues(shader, lights[2]);
|
||||
Rlights.UpdateLightValues(shader, lights[3]);
|
||||
|
||||
// Update the light shader with the camera view position
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, Vector3.Zero, 1.0f, Color.White);
|
||||
DrawModel(cube, Vector3.Zero, 1.0f, Color.White);
|
||||
|
||||
// Draw markers to show where the lights are
|
||||
if (lights[0].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[0].Position, 0.2f, 8, 8, Color.Yellow);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[0].Position, 0.2f, 8, 8, ColorAlpha(Color.Yellow, 0.3f));
|
||||
}
|
||||
|
||||
if (lights[1].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[1].Position, 0.2f, 8, 8, Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[1].Position, 0.2f, 8, 8, ColorAlpha(Color.Red, 0.3f));
|
||||
}
|
||||
|
||||
if (lights[2].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[2].Position, 0.2f, 8, 8, Color.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[2].Position, 0.2f, 8, 8, ColorAlpha(Color.Green, 0.3f));
|
||||
}
|
||||
|
||||
if (lights[3].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[3].Position, 0.2f, 8, 8, Color.Blue);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[3].Position, 0.2f, 8, 8, ColorAlpha(Color.Blue, 0.3f));
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
DrawText("Use keys [Y][R][G][B] to toggle lights", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadModel(model);
|
||||
UnloadModel(cube);
|
||||
UnloadShader(shader);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - Basic PBR
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.1-dev
|
||||
*
|
||||
* Example contributed by Afan OLOVCIC (@_DevDad) 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) 2023-2024 Afan OLOVCIC (@_DevDad)
|
||||
*
|
||||
* Model: "Old Rusty Car" (https://skfb.ly/LxRy) by Renafox,
|
||||
* licensed under Creative Commons Attribution-NonCommercial
|
||||
* (http://creativecommons.org/licenses/by-nc/4.0/)
|
||||
*
|
||||
********************************************************************************************/
|
||||
*
|
||||
* raylib [shaders] example - basic pbr
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Afan OLOVCIC (@_DevDad) 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) 2023-2025 Afan OLOVCIC (@_DevDad)
|
||||
*
|
||||
* Model: "Old Rusty Car" (https://skfb.ly/LxRy) by Renafox,
|
||||
* licensed under Creative Commons Attribution-NonCommercial
|
||||
* (http://creativecommons.org/licenses/by-nc/4.0/)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using Examples.Shared;
|
||||
|
|
@ -23,31 +25,50 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class BasicPbr
|
||||
public class BasicPbr : IExample
|
||||
{
|
||||
private const int GLSL_VERSION = 330;
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public static unsafe int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Shaders / Basic PBR";
|
||||
|
||||
public string Title => "raylib [shaders] example - basic pbr";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Shader shader;
|
||||
private Model car;
|
||||
private Model floor;
|
||||
private PbrLight[] lights;
|
||||
|
||||
private int metallicValueLoc;
|
||||
private int roughnessValueLoc;
|
||||
private int emissiveIntensityLoc;
|
||||
private int emissiveColorLoc;
|
||||
private int textureTilingLoc;
|
||||
|
||||
private Vector2 carTextureTiling;
|
||||
private Vector2 floorTextureTiling;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic pbr");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(2.0f, 4.0f, 6.0f);
|
||||
camera = new();
|
||||
camera.Position = new Vector3(2.0f, 2.0f, 6.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load PBR shader and setup all required locations
|
||||
var shader = LoadShader("resources/shaders/glsl330/pbr.vs", "resources/shaders/glsl330/pbr.fs");
|
||||
shader = LoadShader($"resources/shaders/glsl{GlslVersion}/pbr.vs", $"resources/shaders/glsl{GlslVersion}/pbr.fs");
|
||||
|
||||
shader.Locs[(int)ShaderLocationIndex.MapAlbedo] = GetShaderLocation(shader, "albedoMap");
|
||||
// WARNING: Metalness, roughness, and ambient occlusion are all packed into a MRA texture
|
||||
|
|
@ -75,23 +96,25 @@ public class BasicPbr
|
|||
SetShaderValue(shader, GetShaderLocation(shader, "ambient"), &ambientIntensity, ShaderUniformDataType.Float);
|
||||
|
||||
// Get location for shader parameters that can be modified in real time
|
||||
var emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower");
|
||||
var emissiveColorLoc = GetShaderLocation(shader, "emissiveColor");
|
||||
var textureTilingLoc = GetShaderLocation(shader, "tiling");
|
||||
metallicValueLoc = GetShaderLocation(shader, "metallicValue");
|
||||
roughnessValueLoc = GetShaderLocation(shader, "roughnessValue");
|
||||
emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower");
|
||||
emissiveColorLoc = GetShaderLocation(shader, "emissiveColor");
|
||||
textureTilingLoc = GetShaderLocation(shader, "tiling");
|
||||
|
||||
// Load old car model using PBR maps and shader
|
||||
// WARNING: We know this model consists of a single model.meshes[0] and
|
||||
// that model.materials[0] is by default assigned to that mesh
|
||||
// There could be more complex models consisting of multiple meshes and
|
||||
// multiple materials defined for those meshes... but always 1 mesh = 1 material
|
||||
var car = LoadModel("resources/models/gltf/old_car_new.glb");
|
||||
car = LoadModel("resources/models/gltf/old_car_new.glb");
|
||||
|
||||
// Assign already setup PBR shader to model.materials[0], used by models.meshes[0]
|
||||
car.Materials[0].Shader = shader;
|
||||
|
||||
// Setup materials[0].maps default parameters
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Albedo].Color = Color.White;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value = 0.0f;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value = 1.0f;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value = 0.0f;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Occlusion].Value = 1.0f;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color = new Color(255, 162, 0, 255);
|
||||
|
|
@ -104,7 +127,7 @@ public class BasicPbr
|
|||
|
||||
// Load floor model mesh and assign material parameters
|
||||
// NOTE: A basic plane shape can be generated instead of being loaded from a model file
|
||||
var floor = LoadModel("resources/models/gltf/plane.glb");
|
||||
floor = LoadModel("resources/models/gltf/plane.glb");
|
||||
//Mesh floorMesh = GenMeshPlane(10, 10, 10, 10);
|
||||
//GenMeshTangents(&floorMesh); // TODO: Review tangents generation
|
||||
//Model floor = LoadModelFromMesh(floorMesh);
|
||||
|
|
@ -113,8 +136,8 @@ public class BasicPbr
|
|||
floor.Materials[0].Shader = shader;
|
||||
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Albedo].Color = Color.White;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value = 0.0f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value = 0.0f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value = 0.8f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value = 0.1f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Occlusion].Value = 1.0f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color = Color.Black;
|
||||
|
||||
|
|
@ -124,11 +147,11 @@ public class BasicPbr
|
|||
|
||||
// Models texture tiling parameter can be stored in the Material struct if required (CURRENTLY NOT USED)
|
||||
// NOTE: Material.params[4] are available for generic parameters storage (float)
|
||||
var carTextureTiling = new Vector2(0.5f, 0.5f);
|
||||
var floorTextureTiling = new Vector2(0.5f, 0.5f);
|
||||
carTextureTiling = new Vector2(0.5f, 0.5f);
|
||||
floorTextureTiling = new Vector2(0.5f, 0.5f);
|
||||
|
||||
// Create some lights
|
||||
var lights = new PbrLight[4];
|
||||
lights = new PbrLight[4];
|
||||
lights[0] = PbrLights.CreateLight(
|
||||
0,
|
||||
PbrLightType.Point,
|
||||
|
|
@ -167,104 +190,113 @@ public class BasicPbr
|
|||
SetShaderValue(shader, GetShaderLocation(shader, "useTexNormal"), &usage, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, GetShaderLocation(shader, "useTexMRA"), &usage, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, GetShaderLocation(shader, "useTexEmissive"), &usage, ShaderUniformDataType.Int);
|
||||
}
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//---------------------------------------------------------------------------------------
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
|
||||
var cameraPos = camera.Position;
|
||||
SetShaderValue(shader, shader.Locs[(int)ShaderLocationIndex.VectorView], cameraPos, ShaderUniformDataType.Vec3);
|
||||
|
||||
// Check key inputs to enable/disable lights
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera, CameraMode.Orbital);
|
||||
|
||||
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
|
||||
var cameraPos = camera.Position;
|
||||
SetShaderValue(shader, shader.Locs[(int)ShaderLocationIndex.VectorView], cameraPos, ShaderUniformDataType.Vec3);
|
||||
|
||||
// Check key inputs to enable/disable lights
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
lights[2].Enabled = !lights[2].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
lights[1].Enabled = !lights[1].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
lights[3].Enabled = !lights[3].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
lights[0].Enabled = !lights[0].Enabled;
|
||||
}
|
||||
|
||||
// Update light values on shader (actually, only enable/disable them)
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
UpdateLight(shader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Set floor model texture tiling and emissive color parameters on shader
|
||||
SetShaderValue(shader, textureTilingLoc, &floorTextureTiling, ShaderUniformDataType.Vec2);
|
||||
var floorEmissiveColor = ColorNormalize(floor.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color);
|
||||
SetShaderValue(shader, emissiveColorLoc, &floorEmissiveColor, ShaderUniformDataType.Vec4);
|
||||
|
||||
DrawModel(floor, Vector3.Zero, 5.0f, Color.White); // Draw floor model
|
||||
|
||||
// Set old car model texture tiling, emissive color and emissive intensity parameters on shader
|
||||
SetShaderValue(shader, textureTilingLoc, &carTextureTiling, ShaderUniformDataType.Vec2);
|
||||
var carEmissiveColor = ColorNormalize(car.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color);
|
||||
SetShaderValue(shader, emissiveColorLoc, &carEmissiveColor, ShaderUniformDataType.Vec4);
|
||||
var emissiveIntensity = 0.01f;
|
||||
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, ShaderUniformDataType.Float);
|
||||
|
||||
DrawModel(car, Vector3.Zero, 0.25f, Color.White); // Draw car model
|
||||
|
||||
// Draw spheres to show the lights positions
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var color = lights[i].Color;
|
||||
var lightColor = new Color((byte)(color.X * 255), (byte)(color.Y * 255), (byte)(color.Z * 255),
|
||||
(byte)(color.W * 255));
|
||||
|
||||
if (lights[i].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[i].Position, 0.2f, 8, 8, lightColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[i].Position, 0.2f, 8, 8, ColorAlpha(lightColor, 0.3f));
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Toggle lights: [1][2][3][4]", 10, 40, 20, Color.LightGray);
|
||||
|
||||
DrawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)", screenWidth - 320, screenHeight - 20, 10, Color.LightGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
lights[2].Enabled = !lights[2].Enabled;
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
lights[1].Enabled = !lights[1].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
lights[3].Enabled = !lights[3].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
lights[0].Enabled = !lights[0].Enabled;
|
||||
}
|
||||
|
||||
// Update light values on shader (actually, only enable/disable them)
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
UpdateLight(shader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Set floor model texture tiling and emissive color parameters on shader
|
||||
SetShaderValue(shader, textureTilingLoc, floorTextureTiling, ShaderUniformDataType.Vec2);
|
||||
var floorEmissiveColor = ColorNormalize(floor.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color);
|
||||
SetShaderValue(shader, emissiveColorLoc, &floorEmissiveColor, ShaderUniformDataType.Vec4);
|
||||
|
||||
// Set floor metallic and roughness values
|
||||
var floorMetallicValue = floor.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value;
|
||||
SetShaderValue(shader, metallicValueLoc, &floorMetallicValue, ShaderUniformDataType.Float);
|
||||
var floorRoughnessValue = floor.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value;
|
||||
SetShaderValue(shader, roughnessValueLoc, &floorRoughnessValue, ShaderUniformDataType.Float);
|
||||
|
||||
DrawModel(floor, Vector3.Zero, 5.0f, Color.White); // Draw floor model
|
||||
|
||||
// Set old car model texture tiling, emissive color and emissive intensity parameters on shader
|
||||
SetShaderValue(shader, textureTilingLoc, carTextureTiling, ShaderUniformDataType.Vec2);
|
||||
var carEmissiveColor = ColorNormalize(car.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color);
|
||||
SetShaderValue(shader, emissiveColorLoc, &carEmissiveColor, ShaderUniformDataType.Vec4);
|
||||
var emissiveIntensity = 0.01f;
|
||||
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, ShaderUniformDataType.Float);
|
||||
|
||||
// Set old car metallic and roughness values
|
||||
var carMetallicValue = car.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value;
|
||||
SetShaderValue(shader, metallicValueLoc, &carMetallicValue, ShaderUniformDataType.Float);
|
||||
var carRoughnessValue = car.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value;
|
||||
SetShaderValue(shader, roughnessValueLoc, &carRoughnessValue, ShaderUniformDataType.Float);
|
||||
|
||||
DrawModel(car, Vector3.Zero, 0.25f, Color.White); // Draw car model
|
||||
|
||||
// Draw spheres to show the lights positions
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var color = lights[i].Color;
|
||||
var lightColor = new Color((byte)(color.X * 255), (byte)(color.Y * 255), (byte)(color.Z * 255),
|
||||
(byte)(color.W * 255));
|
||||
|
||||
if (lights[i].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[i].Position, 0.2f, 8, 8, lightColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[i].Position, 0.2f, 8, 8, ColorAlpha(lightColor, 0.3f));
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Toggle lights: [1][2][3][4]", 10, 40, 20, Color.LightGray);
|
||||
|
||||
DrawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)", screenWidth - 320, screenHeight - 20, 10, Color.LightGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
// Unbind (disconnect) shader from car.material[0]
|
||||
// to avoid UnloadMaterial() trying to unload it automatically
|
||||
car.Materials[0].Shader = new();
|
||||
|
|
@ -278,7 +310,32 @@ public class BasicPbr
|
|||
UnloadModel(floor);
|
||||
|
||||
UnloadShader(shader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic pbr");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BasicPbr();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -287,8 +344,8 @@ public class BasicPbr
|
|||
|
||||
private static void UpdateLight(Shader shader, PbrLight light)
|
||||
{
|
||||
SetShaderValue(shader, light.EnabledLoc, light.Enabled, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, light.TypeLoc, light.Type, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, light.EnabledLoc, light.Enabled ? 1 : 0, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, light.TypeLoc, (int)light.Type, ShaderUniformDataType.Int);
|
||||
|
||||
// Send to shader light position values
|
||||
SetShaderValue(shader, light.PositionLoc, light.Position, ShaderUniformDataType.Vec3);
|
||||
|
|
|
|||
252
Examples/Shaders/CelShading.cs
Normal file
252
Examples/Shaders/CelShading.cs
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - cel shading
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* Example contributed by Gleb A (@ggrizzly) 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) 2026 Gleb A (@ggrizzly)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
using static Raylib_cs.Rlgl;
|
||||
using Examples.Shared;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class CelShading : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxLights = 4;
|
||||
|
||||
// rlgl cull face modes (rlgl.h: RL_CULL_FACE_FRONT = 0, RL_CULL_FACE_BACK = 1)
|
||||
private const int CullFaceFront = 0;
|
||||
private const int CullFaceBack = 1;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Cel Shading";
|
||||
|
||||
public string Title => "raylib [shaders] example - cel shading";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Shader celShader;
|
||||
private Shader defaultShader;
|
||||
private Shader outlineShader;
|
||||
private float numBands;
|
||||
private int numBandsLoc;
|
||||
private int outlineThicknessLoc;
|
||||
private Light[] lights;
|
||||
private bool celEnabled;
|
||||
private bool outlineEnabled;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
camera = new();
|
||||
camera.Position = new Vector3(9.0f, 6.0f, 9.0f);
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/old_car_new.glb");
|
||||
|
||||
// Load cel shader
|
||||
celShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/cel.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/cel.fs"
|
||||
);
|
||||
celShader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(celShader, "viewPos");
|
||||
|
||||
// Apply cel shader to model, keep copy of default shader
|
||||
defaultShader = model.Materials[0].Shader;
|
||||
model.Materials[0].Shader = celShader;
|
||||
|
||||
// numBands: controls toon quantization steps (2 = hard binary, 20 = near-smooth)
|
||||
numBands = 10.0f;
|
||||
numBandsLoc = GetShaderLocation(celShader, "numBands");
|
||||
Raylib.SetShaderValue(celShader, numBandsLoc, numBands, ShaderUniformDataType.Float);
|
||||
|
||||
// Inverted-hull outline shader: draws back faces extruded along normals
|
||||
outlineShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/outline_hull.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/outline_hull.fs"
|
||||
);
|
||||
outlineThicknessLoc = GetShaderLocation(outlineShader, "outlineThickness");
|
||||
|
||||
// Single directional white light, angled so toon bands are visible on the model sides.
|
||||
// Spins opposite to CAMERA_ORBITAL (0.5 rad/s) so lighting changes as you watch.
|
||||
lights = new Light[MaxLights];
|
||||
lights[0] = Rlights.CreateLight(
|
||||
0,
|
||||
LightType.Directorional,
|
||||
new Vector3(50.0f, 50.0f, 50.0f),
|
||||
Vector3.Zero,
|
||||
Color.White,
|
||||
celShader
|
||||
);
|
||||
|
||||
celEnabled = true;
|
||||
outlineEnabled = true;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
Raylib.SetShaderValue(
|
||||
celShader,
|
||||
celShader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
// [Z] Toggle cel shading on/off
|
||||
if (IsKeyPressed(KeyboardKey.Z))
|
||||
{
|
||||
celEnabled = !celEnabled;
|
||||
if (celEnabled)
|
||||
{
|
||||
model.Materials[0].Shader = celShader; // Apply cel shader to model
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Materials[0].Shader = defaultShader; // Apply default shader to model
|
||||
}
|
||||
}
|
||||
|
||||
// [C] Toggle outline on/off
|
||||
if (IsKeyPressed(KeyboardKey.C))
|
||||
{
|
||||
outlineEnabled = !outlineEnabled;
|
||||
}
|
||||
|
||||
// [Q/E] Decrease/increase toon band count (press or hold to repeat)
|
||||
if (IsKeyPressed(KeyboardKey.E) || IsKeyPressedRepeat(KeyboardKey.E))
|
||||
{
|
||||
numBands = Clamp(numBands + 1.0f, 2.0f, 20.0f);
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Q) || IsKeyPressedRepeat(KeyboardKey.Q))
|
||||
{
|
||||
numBands = Clamp(numBands - 1.0f, 2.0f, 20.0f);
|
||||
}
|
||||
Raylib.SetShaderValue(celShader, numBandsLoc, numBands, ShaderUniformDataType.Float);
|
||||
|
||||
// Spin light opposite to CAMERA_ORBITAL (0.5 rad/s), angled 45 degrees off vertical
|
||||
float t = (float)GetTime();
|
||||
lights[0].Position = new Vector3(MathF.Sin(-t * 0.3f) * 5.0f, 5.0f, MathF.Cos(-t * 0.3f) * 5.0f);
|
||||
|
||||
for (var i = 0; i < MaxLights; i++)
|
||||
{
|
||||
Rlights.UpdateLightValues(celShader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
if (outlineEnabled)
|
||||
{
|
||||
// Outline pass: cull front faces, draw extruded back faces as silhouette
|
||||
float thickness = 0.005f;
|
||||
Raylib.SetShaderValue(outlineShader, outlineThicknessLoc, thickness, ShaderUniformDataType.Float);
|
||||
|
||||
SetCullFace(CullFaceFront);
|
||||
|
||||
model.Materials[0].Shader = outlineShader;
|
||||
|
||||
DrawModel(model, Vector3.Zero, 0.75f, Color.White);
|
||||
|
||||
if (celEnabled)
|
||||
{
|
||||
model.Materials[0].Shader = celShader; // Apply cel shader to model
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Materials[0].Shader = defaultShader; // Apply default shader to model
|
||||
}
|
||||
|
||||
SetCullFace(CullFaceBack);
|
||||
}
|
||||
|
||||
DrawModel(model, Vector3.Zero, 0.75f, Color.White);
|
||||
DrawSphereEx(lights[0].Position, 0.2f, 50, 50, Color.Yellow); // Light position indicator
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
DrawText($"Cel: {(celEnabled ? "ON" : "OFF")} [Z]", 10, 65, 20, celEnabled ? Color.DarkGreen : Color.DarkGray);
|
||||
DrawText($"Outline: {(outlineEnabled ? "ON" : "OFF")} [C]", 10, 90, 20, outlineEnabled ? Color.DarkGreen : Color.DarkGray);
|
||||
DrawText($"Bands: {numBands:0} [Q/E]", 10, 115, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(model);
|
||||
UnloadShader(celShader);
|
||||
UnloadShader(outlineShader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - cel shading");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new CelShading();
|
||||
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;
|
||||
}
|
||||
}
|
||||
184
Examples/Shaders/ColorCorrection.cs
Normal file
184
Examples/Shaders/ColorCorrection.cs
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - color correction
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jordi Santonja (@JordSant) 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 Jordi Santonja (@JordSant)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class ColorCorrection : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
private const int MaxTextures = 4;
|
||||
|
||||
public string Name => "Shaders / Color Correction";
|
||||
|
||||
public string Title => "raylib [shaders] example - color correction";
|
||||
|
||||
private Texture2D[] texture;
|
||||
private Shader shdrColorCorrection;
|
||||
private int imageIndex;
|
||||
private int resetButtonClicked;
|
||||
private float contrast;
|
||||
private float saturation;
|
||||
private float brightness;
|
||||
private int contrastLoc;
|
||||
private int saturationLoc;
|
||||
private int brightnessLoc;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
texture = new[]
|
||||
{
|
||||
LoadTexture("resources/parrots.png"),
|
||||
LoadTexture("resources/cat.png"),
|
||||
LoadTexture("resources/mandrill.png"),
|
||||
LoadTexture("resources/fudesumi.png")
|
||||
};
|
||||
|
||||
shdrColorCorrection = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/color_correction.fs");
|
||||
|
||||
imageIndex = 0;
|
||||
resetButtonClicked = 0;
|
||||
|
||||
contrast = 0.0f;
|
||||
saturation = 0.0f;
|
||||
brightness = 0.0f;
|
||||
|
||||
// Get shader locations
|
||||
contrastLoc = GetShaderLocation(shdrColorCorrection, "contrast");
|
||||
saturationLoc = GetShaderLocation(shdrColorCorrection, "saturation");
|
||||
brightnessLoc = GetShaderLocation(shdrColorCorrection, "brightness");
|
||||
|
||||
// Set shader values (they can be changed later)
|
||||
Raylib.SetShaderValue(shdrColorCorrection, contrastLoc, contrast, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shdrColorCorrection, saturationLoc, saturation, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shdrColorCorrection, brightnessLoc, brightness, ShaderUniformDataType.Float);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Select texture to draw
|
||||
if (IsKeyPressed(KeyboardKey.One)) imageIndex = 0;
|
||||
else if (IsKeyPressed(KeyboardKey.Two)) imageIndex = 1;
|
||||
else if (IsKeyPressed(KeyboardKey.Three)) imageIndex = 2;
|
||||
else if (IsKeyPressed(KeyboardKey.Four)) imageIndex = 3;
|
||||
|
||||
// Reset values to 0
|
||||
if (IsKeyPressed(KeyboardKey.R) || resetButtonClicked != 0)
|
||||
{
|
||||
contrast = 0.0f;
|
||||
saturation = 0.0f;
|
||||
brightness = 0.0f;
|
||||
}
|
||||
|
||||
// Send the values to the shader
|
||||
Raylib.SetShaderValue(shdrColorCorrection, contrastLoc, contrast, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shdrColorCorrection, saturationLoc, saturation, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shdrColorCorrection, brightnessLoc, brightness, ShaderUniformDataType.Float);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginShaderMode(shdrColorCorrection);
|
||||
|
||||
DrawTexture(texture[imageIndex], 580 / 2 - texture[imageIndex].Width / 2, GetScreenHeight() / 2 - texture[imageIndex].Height / 2, Color.White);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
DrawLine(580, 0, 580, GetScreenHeight(), new Color(218, 218, 218, 255));
|
||||
DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), new Color(232, 232, 232, 255));
|
||||
|
||||
// Draw UI info text
|
||||
DrawText("Color Correction", 585, 40, 20, Color.Gray);
|
||||
|
||||
DrawText("Picture", 602, 75, 10, Color.Gray);
|
||||
DrawText("Press [1] - [4] to Change Picture", 600, 230, 8, Color.Gray);
|
||||
DrawText("Press [R] to Reset Values", 600, 250, 8, Color.Gray);
|
||||
|
||||
// Draw GUI controls
|
||||
//------------------------------------------------------------------------------
|
||||
// NOTE: raygui is not bound in raylib-cs; controls are kept for reference. Use
|
||||
// keyboard shortcuts ([1]-[4], [R]) to interact with the example.
|
||||
/*GuiToggleGroup(new Rectangle( 645, 70, 20, 20 ), "1;2;3;4", ref imageIndex);
|
||||
|
||||
GuiSliderBar(new Rectangle( 645, 100, 120, 20 ), "Contrast", TextFormat("%.0f", contrast), ref contrast, -100.0f, 100.0f);
|
||||
GuiSliderBar(new Rectangle( 645, 130, 120, 20 ), "Saturation", TextFormat("%.0f", saturation), ref saturation, -100.0f, 100.0f);
|
||||
GuiSliderBar(new Rectangle( 645, 160, 120, 20 ), "Brightness", TextFormat("%.0f", brightness), ref brightness, -100.0f, 100.0f);
|
||||
|
||||
resetButtonClicked = GuiButton(new Rectangle( 645, 190, 40, 20 ), "Reset");*/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DrawFPS(710, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
for (var i = 0; i < MaxTextures; i++)
|
||||
{
|
||||
UnloadTexture(texture[i]);
|
||||
}
|
||||
UnloadShader(shdrColorCorrection);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - color correction");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ColorCorrection();
|
||||
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,18 +1,22 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - Apply a postprocessing shader and connect a custom uniform variable
|
||||
* raylib [shaders] example - custom uniform
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3), to test this example
|
||||
* on OpenGL ES 2.0 platforms (Android, Raspberry Pi, HTML5), use #version 100 shaders
|
||||
* raylib comes with shaders ready for both versions, check raylib/shaders install folder
|
||||
*
|
||||
* 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 originally created with raylib 1.3, last time updated with raylib 4.0
|
||||
*
|
||||
* Copyright (c) 2015 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -21,123 +25,156 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class CustomUniform
|
||||
public class CustomUniform : IExample
|
||||
{
|
||||
public static int Main()
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Shaders / Custom Uniform";
|
||||
|
||||
public string Title => "raylib [shaders] example - custom uniform";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private Vector3 position;
|
||||
private Shader shader;
|
||||
private int swirlCenterLoc;
|
||||
private float[] swirlCenter;
|
||||
private RenderTexture2D target;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - custom uniform variable");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(8.0f, 8.0f, 8.0f);
|
||||
camera.Target = new Vector3(0.0f, 1.5f, 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(8.0f, 8.0f, 8.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 1.5f, 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
|
||||
|
||||
Model model = LoadModel("resources/models/obj/barracks.obj");
|
||||
Texture2D texture = LoadTexture("resources/models/obj/barracks_diffuse.png");
|
||||
model = LoadModel("resources/models/obj/barracks.obj"); // Load OBJ model
|
||||
texture = LoadTexture("resources/models/obj/barracks_diffuse.png"); // Load model texture (diffuse map)
|
||||
|
||||
// Set model diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
position = new(0.0f, 0.0f, 0.0f); // Set model position
|
||||
|
||||
// Load postpro shader
|
||||
Shader shader = LoadShader("resources/shaders/glsl330/base.vs",
|
||||
"resources/shaders/glsl330/swirl.fs");
|
||||
// Load postprocessing shader
|
||||
// NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/swirl.fs");
|
||||
|
||||
// Get variable (uniform) location on the shader to connect with the program
|
||||
// NOTE: If uniform variable could not be found in the shader, function returns -1
|
||||
int swirlCenterLoc = GetShaderLocation(shader, "center");
|
||||
swirlCenterLoc = GetShaderLocation(shader, "center");
|
||||
|
||||
float[] swirlCenter = new float[2] { (float)screenWidth / 2, (float)screenHeight / 2 };
|
||||
swirlCenter = new float[2] { (float)screenWidth / 2, (float)screenHeight / 2 };
|
||||
|
||||
// Create a RenderTexture2D to be used for render to texture
|
||||
RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
var mousePosition = GetMousePosition();
|
||||
|
||||
swirlCenter[0] = mousePosition.X;
|
||||
swirlCenter[1] = screenHeight - mousePosition.Y;
|
||||
|
||||
// Send new value to the shader to be used on drawing
|
||||
Raylib.SetShaderValue(shader, swirlCenterLoc, swirlCenter, ShaderUniformDataType.Vec2);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target); // Enable drawing to texture
|
||||
ClearBackground(Color.RayWhite); // Clear texture background
|
||||
|
||||
BeginMode3D(camera); // Begin 3d mode drawing
|
||||
DrawModel(model, position, 0.5f, Color.White); // Draw 3d model with texture
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
EndMode3D(); // End 3d mode drawing, returns to orthographic 2d mode
|
||||
|
||||
DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, Color.Red);
|
||||
EndTextureMode(); // End drawing to texture (now we have a texture available for next passes)
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite); // Clear screen background
|
||||
|
||||
// Enable shader using the custom uniform
|
||||
BeginShaderMode(shader);
|
||||
|
||||
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, target.Texture.Width, -target.Texture.Height),
|
||||
new Vector2(0, 0),
|
||||
Color.White
|
||||
);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
// Draw some 2d text over drawn texture
|
||||
DrawText(
|
||||
"(c) Barracks 3D model by Alberto Cano",
|
||||
screenWidth - 220,
|
||||
screenHeight - 20,
|
||||
10,
|
||||
Color.Gray
|
||||
);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader); // Unload shader
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadModel(model); // Unload model
|
||||
UnloadRenderTexture(target); // Unload render texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - custom uniform");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new CustomUniform();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
Vector2 mousePosition = GetMousePosition();
|
||||
|
||||
swirlCenter[0] = mousePosition.X;
|
||||
swirlCenter[1] = screenHeight - mousePosition.Y;
|
||||
|
||||
// Send new value to the shader to be used on drawing
|
||||
Raylib.SetShaderValue(shader, swirlCenterLoc, swirlCenter, ShaderUniformDataType.Vec2);
|
||||
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Enable drawing to texture
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 0.5f, Color.White);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, Color.Red);
|
||||
|
||||
// End drawing to texture (now we have a texture available for next passes)
|
||||
EndTextureMode();
|
||||
|
||||
BeginShaderMode(shader);
|
||||
|
||||
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, target.Texture.Width, -target.Texture.Height),
|
||||
new Vector2(0, 0),
|
||||
Color.White
|
||||
);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
DrawText(
|
||||
"(c) Barracks 3D model by Alberto Cano",
|
||||
screenWidth - 220,
|
||||
screenHeight - 20,
|
||||
10,
|
||||
Color.Gray
|
||||
);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadShader(shader);
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
UnloadRenderTexture(target);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
400
Examples/Shaders/DeferredRendering.cs
Normal file
400
Examples/Shaders/DeferredRendering.cs
Normal file
|
|
@ -0,0 +1,400 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - deferred rendering
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or OpenGL ES 3.0
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by Justin Andreas Lacoste (@27justin) 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) 2023-2025 Justin Andreas Lacoste (@27justin)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using Examples.Shared;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
[ExcludeFromBrowser("multiple-render-target G-buffer, unsupported on WebGL1/GLSL100")]
|
||||
public partial class DeferredRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
private const int MaxCubes = 30;
|
||||
private const int MaxLights = 4;
|
||||
private const float CubeScale = 0.25f;
|
||||
|
||||
// GL_READ_FRAMEBUFFER / GL_DRAW_FRAMEBUFFER / GL_DEPTH_BUFFER_BIT
|
||||
private const uint RlReadFramebuffer = 0x8CA8;
|
||||
private const uint RlDrawFramebuffer = 0x8CA9;
|
||||
private const int GlDepthBufferBit = 0x00000100;
|
||||
|
||||
public string Name => "Shaders / Deferred Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - deferred rendering";
|
||||
|
||||
// GBuffer data
|
||||
private struct GBuffer
|
||||
{
|
||||
public uint FramebufferId;
|
||||
|
||||
public uint PositionTextureId;
|
||||
public uint NormalTextureId;
|
||||
public uint AlbedoSpecTextureId;
|
||||
|
||||
public uint DepthRenderbufferId;
|
||||
}
|
||||
|
||||
// Deferred mode passes
|
||||
private enum DeferredMode
|
||||
{
|
||||
Position,
|
||||
Normal,
|
||||
Albedo,
|
||||
Shading
|
||||
}
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Model cube;
|
||||
private Shader gbufferShader;
|
||||
private Shader deferredShader;
|
||||
private GBuffer gBuffer;
|
||||
private Light[] lights;
|
||||
private Vector3[] cubePositions;
|
||||
private float[] cubeRotations;
|
||||
private DeferredMode mode;
|
||||
|
||||
// Texture units our g-buffer textures are bound to
|
||||
private const int TexUnitPosition = 0;
|
||||
private const int TexUnitNormal = 1;
|
||||
private const int TexUnitAlbedoSpec = 2;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 4.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 = 60.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load plane model from a generated mesh
|
||||
model = LoadModelFromMesh(GenMeshPlane(10.0f, 10.0f, 3, 3));
|
||||
cube = LoadModelFromMesh(GenMeshCube(2.0f, 2.0f, 2.0f));
|
||||
|
||||
// Load geometry buffer (G-buffer) shader and deferred shader
|
||||
gbufferShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/gbuffer.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/gbuffer.fs"
|
||||
);
|
||||
|
||||
deferredShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/deferred_shading.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/deferred_shading.fs"
|
||||
);
|
||||
deferredShader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(deferredShader, "viewPosition");
|
||||
|
||||
// Initialize the G-buffer
|
||||
gBuffer = new();
|
||||
gBuffer.FramebufferId = Rlgl.LoadFramebuffer();
|
||||
if (gBuffer.FramebufferId == 0)
|
||||
{
|
||||
TraceLog(TraceLogLevel.Warning, "Failed to create framebufferId");
|
||||
}
|
||||
|
||||
Rlgl.EnableFramebuffer(gBuffer.FramebufferId);
|
||||
|
||||
// NOTE: Vertex positions are stored in a texture for simplicity. A better approach would use a depth texture
|
||||
// (instead of a detph renderbuffer) to reconstruct world positions in the final render shader via clip-space position,
|
||||
// depth, and the inverse view/projection matrices
|
||||
|
||||
// 16-bit precision ensures OpenGL ES 3 compatibility, though it may lack precision for real scenarios
|
||||
gBuffer.PositionTextureId = Rlgl.LoadTexture(null, screenWidth, screenHeight, PixelFormat.UncompressedR16G16B16, 1);
|
||||
|
||||
// Similarly, 16-bit precision is used for normals ensures OpenGL ES 3 compatibility
|
||||
gBuffer.NormalTextureId = Rlgl.LoadTexture(null, screenWidth, screenHeight, PixelFormat.UncompressedR16G16B16, 1);
|
||||
|
||||
// Albedo (diffuse color) and specular strength can be combined into one texture
|
||||
// The color in RGB, and the specular strength in the alpha channel
|
||||
gBuffer.AlbedoSpecTextureId = Rlgl.LoadTexture(null, screenWidth, screenHeight, PixelFormat.UncompressedR8G8B8A8, 1);
|
||||
|
||||
// Activate the draw buffers for our framebufferId
|
||||
Rlgl.ActiveDrawBuffers(3);
|
||||
|
||||
// Now we attach our textures to the framebufferId
|
||||
Rlgl.FramebufferAttach(gBuffer.FramebufferId, gBuffer.PositionTextureId, FramebufferAttachType.ColorChannel0, FramebufferAttachTextureType.Texture2D, 0);
|
||||
Rlgl.FramebufferAttach(gBuffer.FramebufferId, gBuffer.NormalTextureId, FramebufferAttachType.ColorChannel1, FramebufferAttachTextureType.Texture2D, 0);
|
||||
Rlgl.FramebufferAttach(gBuffer.FramebufferId, gBuffer.AlbedoSpecTextureId, FramebufferAttachType.ColorChannel2, FramebufferAttachTextureType.Texture2D, 0);
|
||||
|
||||
// Finally we attach the depth buffer
|
||||
gBuffer.DepthRenderbufferId = Rlgl.LoadTextureDepth(screenWidth, screenHeight, true);
|
||||
Rlgl.FramebufferAttach(gBuffer.FramebufferId, gBuffer.DepthRenderbufferId, FramebufferAttachType.Depth, FramebufferAttachTextureType.Renderbuffer, 0);
|
||||
|
||||
// Make sure our framebufferId is complete
|
||||
// NOTE: rlFramebufferComplete() automatically unbinds the framebufferId, so we don't have to rlDisableFramebuffer() here
|
||||
if (Rlgl.FramebufferComplete(gBuffer.FramebufferId) == 0)
|
||||
{
|
||||
TraceLog(TraceLogLevel.Warning, "Framebuffer is not complete");
|
||||
}
|
||||
|
||||
// Now we initialize the sampler2D uniform's in the deferred shader
|
||||
// We do this by setting the uniform's values to the texture units that
|
||||
// we later bind our g-buffer textures to
|
||||
Rlgl.EnableShader(deferredShader.Id);
|
||||
int texUnitPosition = TexUnitPosition;
|
||||
int texUnitNormal = TexUnitNormal;
|
||||
int texUnitAlbedoSpec = TexUnitAlbedoSpec;
|
||||
Raylib.SetShaderValue(deferredShader, GetShaderLocation(deferredShader, "gPosition"), texUnitPosition, ShaderUniformDataType.Sampler2D);
|
||||
Raylib.SetShaderValue(deferredShader, GetShaderLocation(deferredShader, "gNormal"), texUnitNormal, ShaderUniformDataType.Sampler2D);
|
||||
Raylib.SetShaderValue(deferredShader, GetShaderLocation(deferredShader, "gAlbedoSpec"), texUnitAlbedoSpec, ShaderUniformDataType.Sampler2D);
|
||||
Rlgl.DisableShader();
|
||||
|
||||
// Assign out lighting shader to model
|
||||
model.Materials[0].Shader = gbufferShader;
|
||||
cube.Materials[0].Shader = gbufferShader;
|
||||
|
||||
// Create lights
|
||||
lights = new Light[MaxLights];
|
||||
lights[0] = Rlights.CreateLight(0, LightType.Point, new Vector3(-2, 1, -2), Vector3.Zero, Color.Yellow, deferredShader);
|
||||
lights[1] = Rlights.CreateLight(1, LightType.Point, new Vector3(2, 1, 2), Vector3.Zero, Color.Red, deferredShader);
|
||||
lights[2] = Rlights.CreateLight(2, LightType.Point, new Vector3(-2, 1, 2), Vector3.Zero, Color.Green, deferredShader);
|
||||
lights[3] = Rlights.CreateLight(3, LightType.Point, new Vector3(2, 1, -2), Vector3.Zero, Color.Blue, deferredShader);
|
||||
|
||||
var rand = new Random();
|
||||
cubePositions = new Vector3[MaxCubes];
|
||||
cubeRotations = new float[MaxCubes];
|
||||
|
||||
for (var i = 0; i < MaxCubes; i++)
|
||||
{
|
||||
cubePositions[i] = new Vector3(
|
||||
(float)(rand.Next() % 10) - 5,
|
||||
(float)(rand.Next() % 5),
|
||||
(float)(rand.Next() % 10) - 5
|
||||
);
|
||||
|
||||
cubeRotations[i] = (float)(rand.Next() % 360);
|
||||
}
|
||||
|
||||
mode = DeferredMode.Shading;
|
||||
|
||||
Rlgl.EnableDepthTest();
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
|
||||
Raylib.SetShaderValue(
|
||||
deferredShader,
|
||||
deferredShader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
// Check key inputs to enable/disable lights
|
||||
if (IsKeyPressed(KeyboardKey.Y)) { lights[0].Enabled = !lights[0].Enabled; }
|
||||
if (IsKeyPressed(KeyboardKey.R)) { lights[1].Enabled = !lights[1].Enabled; }
|
||||
if (IsKeyPressed(KeyboardKey.G)) { lights[2].Enabled = !lights[2].Enabled; }
|
||||
if (IsKeyPressed(KeyboardKey.B)) { lights[3].Enabled = !lights[3].Enabled; }
|
||||
|
||||
// Check key inputs to switch between G-buffer textures
|
||||
if (IsKeyPressed(KeyboardKey.One)) mode = DeferredMode.Position;
|
||||
if (IsKeyPressed(KeyboardKey.Two)) mode = DeferredMode.Normal;
|
||||
if (IsKeyPressed(KeyboardKey.Three)) mode = DeferredMode.Albedo;
|
||||
if (IsKeyPressed(KeyboardKey.Four)) mode = DeferredMode.Shading;
|
||||
|
||||
// Update light values (actually, only enable/disable them)
|
||||
for (var i = 0; i < MaxLights; i++) Rlights.UpdateLightValues(deferredShader, lights[i]);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
// Draw to the geometry buffer by first activating it
|
||||
Rlgl.EnableFramebuffer(gBuffer.FramebufferId);
|
||||
Rlgl.ClearColor(0, 0, 0, 0);
|
||||
Rlgl.ClearScreenBuffers(); // Clear color and depth buffer
|
||||
Rlgl.DisableColorBlend();
|
||||
|
||||
BeginMode3D(camera);
|
||||
// NOTE: We have to use rlEnableShader here. `BeginShaderMode` or thus `rlSetShader`
|
||||
// will not work, as they won't immediately load the shader program
|
||||
Rlgl.EnableShader(gbufferShader.Id);
|
||||
// When drawing a model here, make sure that the material's shaders are set to the gbuffer shader!
|
||||
DrawModel(model, Vector3.Zero, 1.0f, Color.White);
|
||||
DrawModel(cube, new Vector3(0.0f, 1.0f, 0.0f), 1.0f, Color.White);
|
||||
|
||||
for (var i = 0; i < MaxCubes; i++)
|
||||
{
|
||||
var position = cubePositions[i];
|
||||
DrawModelEx(cube, position, new Vector3(1, 1, 1), cubeRotations[i], new Vector3(CubeScale, CubeScale, CubeScale), Color.White);
|
||||
}
|
||||
Rlgl.DisableShader();
|
||||
EndMode3D();
|
||||
|
||||
Rlgl.EnableColorBlend();
|
||||
|
||||
// Go back to the default framebufferId (0) and draw our deferred shading
|
||||
Rlgl.DisableFramebuffer();
|
||||
Rlgl.ClearScreenBuffers(); // Clear color & depth buffer
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case DeferredMode.Shading:
|
||||
{
|
||||
BeginMode3D(camera);
|
||||
Rlgl.DisableColorBlend();
|
||||
Rlgl.EnableShader(deferredShader.Id);
|
||||
// Bind our g-buffer textures
|
||||
// We are binding them to locations that we earlier set in sampler2D uniforms `gPosition`, `gNormal`,
|
||||
// and `gAlbedoSpec`
|
||||
Rlgl.ActiveTextureSlot(TexUnitPosition);
|
||||
Rlgl.EnableTexture(gBuffer.PositionTextureId);
|
||||
Rlgl.ActiveTextureSlot(TexUnitNormal);
|
||||
Rlgl.EnableTexture(gBuffer.NormalTextureId);
|
||||
Rlgl.ActiveTextureSlot(TexUnitAlbedoSpec);
|
||||
Rlgl.EnableTexture(gBuffer.AlbedoSpecTextureId);
|
||||
|
||||
// Finally, we draw a fullscreen quad to our default framebufferId
|
||||
// This will now be shaded using our deferred shader
|
||||
Rlgl.LoadDrawQuad();
|
||||
Rlgl.DisableShader();
|
||||
Rlgl.EnableColorBlend();
|
||||
EndMode3D();
|
||||
|
||||
// As a last step, we now copy over the depth buffer from our g-buffer to the default framebufferId
|
||||
Rlgl.BindFramebuffer(RlReadFramebuffer, gBuffer.FramebufferId);
|
||||
Rlgl.BindFramebuffer(RlDrawFramebuffer, 0);
|
||||
Rlgl.BlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, GlDepthBufferBit);
|
||||
Rlgl.DisableFramebuffer();
|
||||
|
||||
// Since our shader is now done and disabled, we can draw spheres
|
||||
// that represent light positions in default forward rendering
|
||||
BeginMode3D(camera);
|
||||
Rlgl.EnableShader(Rlgl.GetShaderIdDefault());
|
||||
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));
|
||||
}
|
||||
Rlgl.DisableShader();
|
||||
EndMode3D();
|
||||
|
||||
DrawText("FINAL RESULT", 10, screenHeight - 30, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
case DeferredMode.Position:
|
||||
{
|
||||
DrawTextureRec(
|
||||
new Texture2D { Id = gBuffer.PositionTextureId, Width = screenWidth, Height = screenHeight },
|
||||
new Rectangle(0, 0, screenWidth, -screenHeight),
|
||||
Vector2.Zero,
|
||||
Color.RayWhite
|
||||
);
|
||||
|
||||
DrawText("POSITION TEXTURE", 10, screenHeight - 30, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
case DeferredMode.Normal:
|
||||
{
|
||||
DrawTextureRec(
|
||||
new Texture2D { Id = gBuffer.NormalTextureId, Width = screenWidth, Height = screenHeight },
|
||||
new Rectangle(0, 0, screenWidth, -screenHeight),
|
||||
Vector2.Zero,
|
||||
Color.RayWhite
|
||||
);
|
||||
|
||||
DrawText("NORMAL TEXTURE", 10, screenHeight - 30, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
case DeferredMode.Albedo:
|
||||
{
|
||||
DrawTextureRec(
|
||||
new Texture2D { Id = gBuffer.AlbedoSpecTextureId, Width = screenWidth, Height = screenHeight },
|
||||
new Rectangle(0, 0, screenWidth, -screenHeight),
|
||||
Vector2.Zero,
|
||||
Color.RayWhite
|
||||
);
|
||||
|
||||
DrawText("ALBEDO TEXTURE", 10, screenHeight - 30, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
DrawText("Toggle lights keys: [Y][R][G][B]", 10, 40, 20, Color.DarkGray);
|
||||
DrawText("Switch G-buffer textures: [1][2][3][4]", 10, 70, 20, Color.DarkGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// Unload the models
|
||||
UnloadModel(model);
|
||||
UnloadModel(cube);
|
||||
|
||||
// Unload shaders
|
||||
UnloadShader(deferredShader);
|
||||
UnloadShader(gbufferShader);
|
||||
|
||||
// Unload geometry buffer and all attached textures
|
||||
Rlgl.UnloadFramebuffer(gBuffer.FramebufferId);
|
||||
Rlgl.UnloadTexture(gBuffer.PositionTextureId);
|
||||
Rlgl.UnloadTexture(gBuffer.NormalTextureId);
|
||||
Rlgl.UnloadTexture(gBuffer.AlbedoSpecTextureId);
|
||||
Rlgl.UnloadTexture(gBuffer.DepthRenderbufferId);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - deferred rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DeferredRendering();
|
||||
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;
|
||||
}
|
||||
}
|
||||
226
Examples/Shaders/DepthRendering.cs
Normal file
226
Examples/Shaders/DepthRendering.cs
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - depth rendering
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Luís Almeida (@luis605) 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 Luís Almeida (@luis605)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class DepthRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Depth Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - depth rendering";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private RenderTexture2D target;
|
||||
private Shader depthShader;
|
||||
private int depthLoc;
|
||||
private Model cube;
|
||||
private Model floor;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(4.0f, 1.0f, 5.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 render texture with a depth texture attached
|
||||
target = LoadRenderTextureDepthTex(screenWidth, screenHeight);
|
||||
|
||||
// Load depth shader and get depth texture shader location
|
||||
depthShader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/depth_render.fs");
|
||||
depthLoc = GetShaderLocation(depthShader, "depthTexture");
|
||||
var flipTextureLoc = GetShaderLocation(depthShader, "flipY");
|
||||
Raylib.SetShaderValue(depthShader, flipTextureLoc, 1, ShaderUniformDataType.Int); // Flip Y texture
|
||||
|
||||
// Load scene models
|
||||
cube = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
|
||||
floor = LoadModelFromMesh(GenMeshPlane(20.0f, 20.0f, 1, 1));
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.White);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawModel(cube, new Vector3(0.0f, 0.0f, 0.0f), 3.0f, Color.Yellow);
|
||||
DrawModel(floor, new Vector3(10.0f, 0.0f, 2.0f), 2.0f, Color.Red);
|
||||
EndMode3D();
|
||||
EndTextureMode();
|
||||
|
||||
// Draw into screen (main framebuffer)
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginShaderMode(depthShader);
|
||||
SetShaderValueTexture(depthShader, depthLoc, target.Depth);
|
||||
DrawTexture(target.Depth, 0, 0, Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
DrawRectangle(10, 10, 320, 93, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 320, 93, Color.Blue);
|
||||
|
||||
DrawText("Camera Controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- WASD to move", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Z to zoom to (0, 0, 0)", 40, 80, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(cube); // Unload model
|
||||
UnloadModel(floor); // Unload model
|
||||
UnloadRenderTextureDepthTex(target);
|
||||
UnloadShader(depthShader); // Unload shader
|
||||
}
|
||||
|
||||
// Load custom render texture, create a writable depth texture buffer
|
||||
private static unsafe RenderTexture2D LoadRenderTextureDepthTex(int width, int height)
|
||||
{
|
||||
RenderTexture2D target = new();
|
||||
|
||||
// Load an empty framebuffer
|
||||
target.Id = Rlgl.LoadFramebuffer();
|
||||
|
||||
if (target.Id > 0)
|
||||
{
|
||||
Rlgl.EnableFramebuffer(target.Id);
|
||||
|
||||
// Create color texture (default to RGBA)
|
||||
target.Texture.Id = Rlgl.LoadTexture(
|
||||
null,
|
||||
width,
|
||||
height,
|
||||
PixelFormat.UncompressedR8G8B8A8,
|
||||
1
|
||||
);
|
||||
target.Texture.Width = width;
|
||||
target.Texture.Height = height;
|
||||
target.Texture.Format = PixelFormat.UncompressedR8G8B8A8;
|
||||
target.Texture.Mipmaps = 1;
|
||||
|
||||
// Create depth texture buffer (instead of raylib default renderbuffer)
|
||||
target.Depth.Id = Rlgl.LoadTextureDepth(width, height, false);
|
||||
target.Depth.Width = width;
|
||||
target.Depth.Height = height;
|
||||
target.Depth.Format = PixelFormat.CompressedPvrtRgba; // DEPTH_COMPONENT_24BIT: Not defined in raylib
|
||||
target.Depth.Mipmaps = 1;
|
||||
|
||||
// Attach color texture and depth texture to FBO
|
||||
Rlgl.FramebufferAttach(
|
||||
target.Id,
|
||||
target.Texture.Id,
|
||||
FramebufferAttachType.ColorChannel0,
|
||||
FramebufferAttachTextureType.Texture2D,
|
||||
0
|
||||
);
|
||||
Rlgl.FramebufferAttach(
|
||||
target.Id,
|
||||
target.Depth.Id,
|
||||
FramebufferAttachType.Depth,
|
||||
FramebufferAttachTextureType.Texture2D,
|
||||
0
|
||||
);
|
||||
|
||||
// Check if fbo is complete with attachments (valid)
|
||||
if (Rlgl.FramebufferComplete(target.Id) != 0)
|
||||
{
|
||||
TraceLog(TraceLogLevel.Info, $"FBO: [ID {target.Id}] Framebuffer object created successfully");
|
||||
}
|
||||
|
||||
Rlgl.DisableFramebuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLog(TraceLogLevel.Warning, "FBO: Framebuffer object can not be created");
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// Unload render texture from GPU memory (VRAM)
|
||||
private static void UnloadRenderTextureDepthTex(RenderTexture2D target)
|
||||
{
|
||||
if (target.Id > 0)
|
||||
{
|
||||
// Color texture attached to FBO is deleted
|
||||
Rlgl.UnloadTexture(target.Texture.Id);
|
||||
Rlgl.UnloadTexture(target.Depth.Id);
|
||||
|
||||
// NOTE: Depth texture is automatically
|
||||
// queried and deleted before deleting framebuffer
|
||||
Rlgl.UnloadFramebuffer(target.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - depth rendering");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DepthRendering();
|
||||
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,25 +1,29 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - Sieve of Eratosthenes
|
||||
* raylib [shaders] example - eratosthenes sieve
|
||||
*
|
||||
* Sieve of Eratosthenes, the earliest known (ancient Greek) prime number sieve.
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* "Sift the twos and sift the threes,
|
||||
* The Sieve of Eratosthenes.
|
||||
* When the multiples sublime,
|
||||
* the numbers that are left are prime."
|
||||
* NOTE: Sieve of Eratosthenes, the earliest known (ancient Greek) prime number sieve
|
||||
*
|
||||
* "Sift the twos and sift the threes,
|
||||
* The Sieve of Eratosthenes.
|
||||
* When the multiples sublime,
|
||||
* the numbers that are left are prime."
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3).
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* 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 originally created with raylib 2.5, last time updated with raylib 4.0
|
||||
*
|
||||
* Example contributed by ProfJski and reviewed by Ramon Santamaria (@raysan5)
|
||||
* Example contributed by ProfJski (@ProfJski) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2019 ProfJski 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 ProfJski (@ProfJski) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -28,73 +32,97 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class Eratosthenes
|
||||
public class Eratosthenes : IExample
|
||||
{
|
||||
const int GlslVersion = 330;
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Shaders / Eratosthenes";
|
||||
|
||||
public string Title => "raylib [shaders] example - eratosthenes sieve";
|
||||
|
||||
private RenderTexture2D target;
|
||||
private Shader shader;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
|
||||
// Load Eratosthenes shader
|
||||
// NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/eratosthenes.fs");
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Nothing to do here, everything is happening in the shader
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target); // Enable drawing to texture
|
||||
ClearBackground(Color.Black); // Clear the render texture
|
||||
|
||||
// Draw a rectangle in shader mode to be used as shader canvas
|
||||
// NOTE: Rectangle uses font white character texture coordinates,
|
||||
// so shader can not be applied here directly because input vertexTexCoord
|
||||
// do not represent full screen coordinates (space where want to apply shader)
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Black);
|
||||
EndTextureMode(); // End drawing to texture (now we have a blank texture available for the shader)
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite); // Clear screen background
|
||||
|
||||
BeginShaderMode(shader);
|
||||
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, target.Texture.Width, -target.Texture.Height),
|
||||
new Vector2(0.0f, 0.0f),
|
||||
Color.White
|
||||
);
|
||||
EndShaderMode();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader);
|
||||
UnloadRenderTexture(target);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - Sieve of Eratosthenes");
|
||||
|
||||
RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
|
||||
// Load Eratosthenes shader
|
||||
// NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
|
||||
Shader shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/eratosthenes.fs");
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - eratosthenes sieve");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Eratosthenes();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Nothing to do here, everything is happening in the shader
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Enable drawing to texture
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
// Draw a rectangle in shader mode to be used as shader canvas
|
||||
// NOTE: Rectangle uses font white character texture coordinates,
|
||||
// so shader can not be applied here directly because input vertexTexCoord
|
||||
// do not represent full screen coordinates (space where want to apply shader)
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Black);
|
||||
|
||||
// End drawing to texture (now we have a blank texture available for the shader)
|
||||
EndTextureMode();
|
||||
|
||||
BeginShaderMode(shader);
|
||||
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, target.Texture.Width, -target.Texture.Height),
|
||||
new Vector2(0.0f, 0.0f),
|
||||
Color.White
|
||||
);
|
||||
EndShaderMode();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadShader(shader);
|
||||
UnloadRenderTexture(target);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,22 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - fog
|
||||
* raylib [shaders] example - fog rendering
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3).
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* 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 originally created with raylib 2.5, last time updated with raylib 3.7
|
||||
*
|
||||
* Example contributed by Chris Camacho (@codifies) and reviewed by Ramon Santamaria (@raysan5)
|
||||
* Example contributed by Chris Camacho (@chriscamacho) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Chris Camacho (@codifies - http://bedroomcoders.co.uk/) notes:
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* This is based on the PBR lighting example, but greatly simplified to aid learning...
|
||||
* actually there is very little of the PBR example left!
|
||||
* When I first looked at the bewildering complexity of the PBR example I feared
|
||||
* I would never understand how I could do simple lighting with raylib however its
|
||||
* a testement to the authors of raylib (including rlights.h) that the example
|
||||
* came together fairly quickly.
|
||||
*
|
||||
* Copyright (c) 2019 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2019-2025 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -32,21 +27,36 @@ using Examples.Shared;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class Fog
|
||||
public class Fog : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Shaders / Fog";
|
||||
|
||||
public string Title => "raylib [shaders] example - fog rendering";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model modelA;
|
||||
private Model modelB;
|
||||
private Model modelC;
|
||||
private Texture2D texture;
|
||||
private Shader shader;
|
||||
private int fogDensityLoc;
|
||||
private float fogDensity;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - fog");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(2.0f, 2.0f, 6.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
|
@ -54,10 +64,10 @@ public class Fog
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load models and texture
|
||||
Model modelA = LoadModelFromMesh(GenMeshTorus(0.4f, 1.0f, 16, 32));
|
||||
Model modelB = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
|
||||
Model modelC = LoadModelFromMesh(GenMeshSphere(0.5f, 32, 32));
|
||||
Texture2D texture = LoadTexture("resources/texel_checker.png");
|
||||
modelA = LoadModelFromMesh(GenMeshTorus(0.4f, 1.0f, 16, 32));
|
||||
modelB = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
|
||||
modelC = LoadModelFromMesh(GenMeshSphere(0.5f, 32, 32));
|
||||
texture = LoadTexture("resources/texel_checker.png");
|
||||
|
||||
// Assign texture to default model material
|
||||
Raylib.SetMaterialTexture(ref modelA, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
|
@ -65,12 +75,15 @@ public class Fog
|
|||
Raylib.SetMaterialTexture(ref modelC, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
// Load shader and set up some uniforms
|
||||
Shader shader = LoadShader("resources/shaders/glsl330/lighting.vs", "resources/shaders/glsl330/fog.fs");
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/lighting.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/fog.fs"
|
||||
);
|
||||
shader.Locs[(int)ShaderLocationIndex.MatrixModel] = GetShaderLocation(shader, "matModel");
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(shader, "viewPos");
|
||||
|
||||
// Ambient light level
|
||||
int ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
var ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
ambientLoc,
|
||||
|
|
@ -78,8 +91,12 @@ public class Fog
|
|||
ShaderUniformDataType.Vec4
|
||||
);
|
||||
|
||||
float fogDensity = 0.15f;
|
||||
int fogDensityLoc = GetShaderLocation(shader, "fogDensity");
|
||||
var fogColor = ColorNormalize(Color.Gray);
|
||||
var fogColorLoc = GetShaderLocation(shader, "fogColor");
|
||||
Raylib.SetShaderValue(shader, fogColorLoc, fogColor, ShaderUniformDataType.Vec4);
|
||||
|
||||
fogDensity = 0.15f;
|
||||
fogDensityLoc = GetShaderLocation(shader, "fogDensity");
|
||||
Raylib.SetShaderValue(shader, fogDensityLoc, fogDensity, ShaderUniformDataType.Float);
|
||||
|
||||
// NOTE: All models share the same shader
|
||||
|
|
@ -89,90 +106,112 @@ public class Fog
|
|||
|
||||
// Using just 1 point lights
|
||||
Rlights.CreateLight(0, LightType.Point, new Vector3(0, 2, 6), Vector3.Zero, Color.White, shader);
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
fogDensity += 0.001f;
|
||||
if (fogDensity > 1.0f)
|
||||
{
|
||||
fogDensity += 0.001f;
|
||||
if (fogDensity > 1.0f)
|
||||
{
|
||||
fogDensity = 1.0f;
|
||||
}
|
||||
fogDensity = 1.0f;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
fogDensity -= 0.001f;
|
||||
if (fogDensity < 0.0f)
|
||||
{
|
||||
fogDensity = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
Raylib.SetShaderValue(shader, fogDensityLoc, fogDensity, ShaderUniformDataType.Float);
|
||||
|
||||
// Rotate the torus
|
||||
modelA.Transform = MatrixMultiply(modelA.Transform, MatrixRotateX(-0.025f));
|
||||
modelA.Transform = MatrixMultiply(modelA.Transform, MatrixRotateZ(0.012f));
|
||||
|
||||
// Update the light shader with the camera view position
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Gray);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw the three models
|
||||
DrawModel(modelA, Vector3.Zero, 1.0f, Color.White);
|
||||
DrawModel(modelB, new Vector3(-2.6f, 0, 0), 1.0f, Color.White);
|
||||
DrawModel(modelC, new Vector3(2.6f, 0, 0), 1.0f, Color.White);
|
||||
|
||||
for (int i = -20; i < 20; i += 2)
|
||||
{
|
||||
DrawModel(modelA, new Vector3(i, 0, 2), 1.0f, Color.White);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText(
|
||||
$"Use up/down to change fog density [{fogDensity:F2}]",
|
||||
10,
|
||||
10,
|
||||
20,
|
||||
Color.RayWhite
|
||||
);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
fogDensity -= 0.001f;
|
||||
if (fogDensity < 0.0f)
|
||||
{
|
||||
fogDensity = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
Raylib.SetShaderValue(shader, fogDensityLoc, fogDensity, ShaderUniformDataType.Float);
|
||||
|
||||
// Rotate the torus
|
||||
modelA.Transform = MatrixMultiply(modelA.Transform, MatrixRotateX(-0.025f));
|
||||
modelA.Transform = MatrixMultiply(modelA.Transform, MatrixRotateZ(0.012f));
|
||||
|
||||
// Update the light shader with the camera view position
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Gray);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw the three models
|
||||
DrawModel(modelA, Vector3.Zero, 1.0f, Color.White);
|
||||
DrawModel(modelB, new Vector3(-2.6f, 0, 0), 1.0f, Color.White);
|
||||
DrawModel(modelC, new Vector3(2.6f, 0, 0), 1.0f, Color.White);
|
||||
|
||||
for (var i = -20; i < 20; i += 2)
|
||||
{
|
||||
DrawModel(modelA, new Vector3(i, 0, 2), 1.0f, Color.White);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText(
|
||||
$"Use KEY_UP/KEY_DOWN to change fog density [{fogDensity:F2}]",
|
||||
10,
|
||||
10,
|
||||
20,
|
||||
Color.RayWhite
|
||||
);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(modelA);
|
||||
UnloadModel(modelB);
|
||||
UnloadModel(modelC);
|
||||
|
||||
UnloadTexture(texture);
|
||||
UnloadShader(shader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - fog rendering");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Fog();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
433
Examples/Shaders/GameOfLife.cs
Normal file
433
Examples/Shaders/GameOfLife.cs
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - game of life
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jordi Santonja (@JordSant) 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 Jordi Santonja (@JordSant)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class GameOfLife : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Game of Life";
|
||||
|
||||
public string Title => "raylib [shaders] example - game of life";
|
||||
|
||||
// Interaction mode
|
||||
private enum InteractionMode
|
||||
{
|
||||
Run = 0,
|
||||
Pause,
|
||||
Draw,
|
||||
}
|
||||
|
||||
// Struct to store example preset patterns
|
||||
private struct PresetPattern
|
||||
{
|
||||
public string Name;
|
||||
public Vector2 Position;
|
||||
|
||||
public PresetPattern(string name, Vector2 position)
|
||||
{
|
||||
Name = name;
|
||||
Position = position;
|
||||
}
|
||||
}
|
||||
|
||||
private const int menuWidth = 100;
|
||||
private const int windowWidth = screenWidth - menuWidth;
|
||||
private const int windowHeight = screenHeight;
|
||||
|
||||
private const int worldWidth = 2048;
|
||||
private const int worldHeight = 2048;
|
||||
|
||||
private const int randomTiles = 8; // Random preset: divide the world to compute random points in each tile
|
||||
|
||||
private static readonly PresetPattern[] presetPatterns =
|
||||
{
|
||||
new("Glider", new Vector2(0.5f, 0.5f)), new("R-pentomino", new Vector2(0.5f, 0.5f)), new("Acorn", new Vector2(0.5f, 0.5f)),
|
||||
new("Spaceships", new Vector2(0.1f, 0.5f)), new("Still lifes", new Vector2(0.5f, 0.5f)), new("Oscillators", new Vector2(0.5f, 0.5f)),
|
||||
new("Puffer train", new Vector2(0.1f, 0.5f)), new("Glider Gun", new Vector2(0.2f, 0.2f)), new("Breeder", new Vector2(0.1f, 0.5f)),
|
||||
new("Random", new Vector2(0.5f, 0.5f))
|
||||
};
|
||||
|
||||
private static readonly int numberOfPresets = presetPatterns.Length;
|
||||
|
||||
private Rectangle worldRectSource;
|
||||
private Rectangle worldRectDest;
|
||||
private Rectangle textureOnScreen;
|
||||
|
||||
private int zoom;
|
||||
private float offsetX;
|
||||
private float offsetY;
|
||||
private int framesPerStep;
|
||||
private int frame;
|
||||
|
||||
private int preset;
|
||||
private InteractionMode mode;
|
||||
private bool buttonZoomIn;
|
||||
private bool buttonZomOut;
|
||||
private bool buttonFaster;
|
||||
private bool buttonSlower;
|
||||
|
||||
private Shader shdrGameOfLife;
|
||||
private int resolutionLoc;
|
||||
|
||||
private RenderTexture2D world1;
|
||||
private RenderTexture2D world2;
|
||||
private RenderTexture2D currentWorld;
|
||||
private RenderTexture2D previousWorld;
|
||||
|
||||
// Image to be used in DRAW mode, to be changed with mouse input
|
||||
private Image imageToDraw;
|
||||
private bool imageToDrawValid;
|
||||
|
||||
// Static locals in the original loop, promoted to fields
|
||||
private Vector2 previousMousePosition;
|
||||
private int firstColor;
|
||||
|
||||
private void FreeImageToDraw()
|
||||
{
|
||||
if (imageToDrawValid)
|
||||
{
|
||||
UnloadImage(imageToDraw);
|
||||
imageToDrawValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
worldRectSource = new Rectangle(0, 0, worldWidth, -worldHeight);
|
||||
worldRectDest = new Rectangle(0, 0, worldWidth, worldHeight);
|
||||
textureOnScreen = new Rectangle(0, 0, windowWidth, windowHeight);
|
||||
|
||||
zoom = 1;
|
||||
offsetX = (worldWidth - windowWidth) / 2.0f; // Centered on window
|
||||
offsetY = (worldHeight - windowHeight) / 2.0f; // Centered on window
|
||||
framesPerStep = 1;
|
||||
frame = 0;
|
||||
|
||||
preset = -1; // No button pressed for preset
|
||||
mode = InteractionMode.Run; // Starting mode: running
|
||||
buttonZoomIn = false; // Button states: false not pressed
|
||||
buttonZomOut = false;
|
||||
buttonFaster = false;
|
||||
buttonSlower = false;
|
||||
|
||||
previousMousePosition = new Vector2(0.0f, 0.0f);
|
||||
firstColor = -1;
|
||||
imageToDrawValid = false;
|
||||
|
||||
// Load shader
|
||||
shdrGameOfLife = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/game_of_life.fs");
|
||||
|
||||
// Set shader uniform size of the world
|
||||
resolutionLoc = GetShaderLocation(shdrGameOfLife, "resolution");
|
||||
var resolution = new[] { (float)worldWidth, (float)worldHeight };
|
||||
Raylib.SetShaderValue(shdrGameOfLife, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
|
||||
|
||||
// Define two textures: the current world and the previous world
|
||||
world1 = LoadRenderTexture(worldWidth, worldHeight);
|
||||
world2 = LoadRenderTexture(worldWidth, worldHeight);
|
||||
BeginTextureMode(world2);
|
||||
ClearBackground(Color.RayWhite);
|
||||
EndTextureMode();
|
||||
|
||||
var startPattern = LoadImage("resources/game_of_life/r_pentomino.png");
|
||||
UpdateTextureRec(
|
||||
world2.Texture,
|
||||
new Rectangle(worldWidth / 2.0f, worldHeight / 2.0f, startPattern.Width, startPattern.Height),
|
||||
startPattern.Data
|
||||
);
|
||||
UnloadImage(startPattern);
|
||||
|
||||
// References to the two textures, to be swapped
|
||||
currentWorld = world2;
|
||||
previousWorld = world1;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
frame++;
|
||||
|
||||
// Change zoom: both by buttons or by mouse wheel
|
||||
var mouseWheelMove = GetMouseWheelMove();
|
||||
if (buttonZoomIn || (buttonZomOut && (zoom > 1)) || (mouseWheelMove != 0.0f))
|
||||
{
|
||||
FreeImageToDraw(); // Zoom change: free the image to draw to be recreated again
|
||||
|
||||
var centerX = offsetX + (windowWidth / 2.0f) / zoom;
|
||||
var centerY = offsetY + (windowHeight / 2.0f) / zoom;
|
||||
if (buttonZoomIn || (mouseWheelMove > 0.0f)) zoom *= 2;
|
||||
if ((buttonZomOut || (mouseWheelMove < 0.0f)) && (zoom > 1)) zoom /= 2;
|
||||
offsetX = centerX - (windowWidth / 2.0f) / zoom;
|
||||
offsetY = centerY - (windowHeight / 2.0f) / zoom;
|
||||
}
|
||||
|
||||
// Change speed: number of frames per step
|
||||
if (buttonFaster && framesPerStep > 1) framesPerStep--;
|
||||
if (buttonSlower) framesPerStep++;
|
||||
|
||||
// Mouse management
|
||||
if ((mode == InteractionMode.Run) || (mode == InteractionMode.Pause))
|
||||
{
|
||||
FreeImageToDraw(); // Free the image to draw: no longer needed in these modes
|
||||
|
||||
// Pan with mouse left button
|
||||
var mousePosition = GetMousePosition();
|
||||
if (IsMouseButtonDown(MouseButton.Left) && (mousePosition.X < windowWidth))
|
||||
{
|
||||
offsetX -= (mousePosition.X - previousMousePosition.X) / zoom;
|
||||
offsetY -= (mousePosition.Y - previousMousePosition.Y) / zoom;
|
||||
}
|
||||
previousMousePosition = mousePosition;
|
||||
}
|
||||
else // MODE_DRAW
|
||||
{
|
||||
var offsetDecimalX = offsetX - MathF.Floor(offsetX);
|
||||
var offsetDecimalY = offsetY - MathF.Floor(offsetY);
|
||||
var sizeInWorldX = (int)(MathF.Ceiling((windowWidth + offsetDecimalX * zoom) / zoom));
|
||||
var sizeInWorldY = (int)(MathF.Ceiling((windowHeight + offsetDecimalY * zoom) / zoom));
|
||||
if (offsetX + sizeInWorldX >= worldWidth) sizeInWorldX = worldWidth - (int)MathF.Floor(offsetX);
|
||||
if (offsetY + sizeInWorldY >= worldHeight) sizeInWorldY = worldHeight - (int)MathF.Floor(offsetY);
|
||||
|
||||
// Create image to draw if not created yet
|
||||
if (!imageToDrawValid)
|
||||
{
|
||||
var worldOnScreen = LoadRenderTexture(sizeInWorldX, sizeInWorldY);
|
||||
BeginTextureMode(worldOnScreen);
|
||||
DrawTexturePro(
|
||||
currentWorld.Texture,
|
||||
new Rectangle(MathF.Floor(offsetX), MathF.Floor(offsetY), sizeInWorldX, -sizeInWorldY),
|
||||
new Rectangle(0, 0, sizeInWorldX, sizeInWorldY),
|
||||
new Vector2(0, 0), 0.0f, Color.White
|
||||
);
|
||||
EndTextureMode();
|
||||
imageToDraw = LoadImageFromTexture(worldOnScreen.Texture);
|
||||
imageToDrawValid = true;
|
||||
|
||||
UnloadRenderTexture(worldOnScreen);
|
||||
}
|
||||
|
||||
var mousePosition = GetMousePosition();
|
||||
if (IsMouseButtonDown(MouseButton.Left) && (mousePosition.X < windowWidth))
|
||||
{
|
||||
var mouseX = (int)(mousePosition.X + offsetDecimalX * zoom) / zoom;
|
||||
var mouseY = (int)(mousePosition.Y + offsetDecimalY * zoom) / zoom;
|
||||
if (mouseX >= sizeInWorldX) mouseX = sizeInWorldX - 1;
|
||||
if (mouseY >= sizeInWorldY) mouseY = sizeInWorldY - 1;
|
||||
if (firstColor == -1) firstColor = (GetImageColor(imageToDraw, mouseX, mouseY).R < 5) ? 0 : 1;
|
||||
var prevColor = (GetImageColor(imageToDraw, mouseX, mouseY).R < 5) ? 0 : 1;
|
||||
|
||||
ImageDrawPixel(ref imageToDraw, mouseX, mouseY, (firstColor != 0) ? Color.Black : Color.RayWhite);
|
||||
|
||||
if (prevColor != firstColor)
|
||||
{
|
||||
UpdateTextureRec(
|
||||
currentWorld.Texture,
|
||||
new Rectangle(MathF.Floor(offsetX), MathF.Floor(offsetY), sizeInWorldX, sizeInWorldY),
|
||||
imageToDraw.Data
|
||||
);
|
||||
}
|
||||
}
|
||||
else firstColor = -1;
|
||||
}
|
||||
|
||||
// Load selected preset
|
||||
if (preset >= 0)
|
||||
{
|
||||
Image pattern;
|
||||
if (preset < numberOfPresets - 1) // Preset with pattern image to load
|
||||
{
|
||||
pattern = preset switch
|
||||
{
|
||||
0 => LoadImage("resources/game_of_life/glider.png"),
|
||||
1 => LoadImage("resources/game_of_life/r_pentomino.png"),
|
||||
2 => LoadImage("resources/game_of_life/acorn.png"),
|
||||
3 => LoadImage("resources/game_of_life/spaceships.png"),
|
||||
4 => LoadImage("resources/game_of_life/still_lifes.png"),
|
||||
5 => LoadImage("resources/game_of_life/oscillators.png"),
|
||||
6 => LoadImage("resources/game_of_life/puffer_train.png"),
|
||||
7 => LoadImage("resources/game_of_life/glider_gun.png"),
|
||||
8 => LoadImage("resources/game_of_life/breeder.png"),
|
||||
_ => default,
|
||||
};
|
||||
BeginTextureMode(currentWorld);
|
||||
ClearBackground(Color.RayWhite);
|
||||
EndTextureMode();
|
||||
|
||||
UpdateTextureRec(
|
||||
currentWorld.Texture,
|
||||
new Rectangle(
|
||||
worldWidth * presetPatterns[preset].Position.X - pattern.Width / 2.0f,
|
||||
worldHeight * presetPatterns[preset].Position.Y - pattern.Height / 2.0f,
|
||||
pattern.Width, pattern.Height
|
||||
),
|
||||
pattern.Data
|
||||
);
|
||||
}
|
||||
else // Last preset: Random values
|
||||
{
|
||||
pattern = GenImageColor(worldWidth / randomTiles, worldHeight / randomTiles, Color.RayWhite);
|
||||
for (var i = 0; i < randomTiles; i++)
|
||||
{
|
||||
for (var j = 0; j < randomTiles; j++)
|
||||
{
|
||||
ImageClearBackground(ref pattern, Color.RayWhite);
|
||||
for (var x = 0; x < pattern.Width; x++)
|
||||
{
|
||||
for (var y = 0; y < pattern.Height; y++)
|
||||
{
|
||||
if (GetRandomValue(0, 100) < 15) ImageDrawPixel(ref pattern, x, y, Color.Black);
|
||||
}
|
||||
}
|
||||
UpdateTextureRec(
|
||||
currentWorld.Texture,
|
||||
new Rectangle(pattern.Width * i, pattern.Height * j, pattern.Width, pattern.Height),
|
||||
pattern.Data
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnloadImage(pattern);
|
||||
|
||||
mode = InteractionMode.Pause;
|
||||
offsetX = worldWidth * presetPatterns[preset].Position.X - (float)windowWidth / zoom / 2.0f;
|
||||
offsetY = worldHeight * presetPatterns[preset].Position.Y - (float)windowHeight / zoom / 2.0f;
|
||||
}
|
||||
|
||||
// Check window draw inside world limits
|
||||
if (offsetX < 0) offsetX = 0;
|
||||
if (offsetY < 0) offsetY = 0;
|
||||
if (offsetX > worldWidth - (float)windowWidth / zoom) offsetX = worldWidth - (float)windowWidth / zoom;
|
||||
if (offsetY > worldHeight - (float)windowHeight / zoom) offsetY = worldHeight - (float)windowHeight / zoom;
|
||||
|
||||
// Rectangles for drawing texture portion to screen
|
||||
var textureSourceToScreen = new Rectangle(offsetX, offsetY, (float)windowWidth / zoom, (float)windowHeight / zoom);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw to texture
|
||||
//----------------------------------------------------------------------------------
|
||||
if ((mode == InteractionMode.Run) && ((frame % framesPerStep) == 0))
|
||||
{
|
||||
// Swap worlds
|
||||
var tempWorld = currentWorld;
|
||||
currentWorld = previousWorld;
|
||||
previousWorld = tempWorld;
|
||||
|
||||
// Draw to texture
|
||||
BeginTextureMode(currentWorld);
|
||||
BeginShaderMode(shdrGameOfLife);
|
||||
DrawTexturePro(previousWorld.Texture, worldRectSource, worldRectDest, new Vector2(0, 0), 0.0f, Color.RayWhite);
|
||||
EndShaderMode();
|
||||
EndTextureMode();
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw to screen
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
DrawTexturePro(currentWorld.Texture, textureSourceToScreen, textureOnScreen, new Vector2(0, 0), 0.0f, Color.White);
|
||||
|
||||
DrawLine(windowWidth, 0, windowWidth, screenHeight, new Color(218, 218, 218, 255));
|
||||
DrawRectangle(windowWidth, 0, screenWidth - windowWidth, screenHeight, new Color(232, 232, 232, 255));
|
||||
|
||||
DrawText("Conway's", 704, 4, 20, Color.DarkBlue);
|
||||
DrawText(" game of", 704, 19, 20, Color.DarkBlue);
|
||||
DrawText(" life", 708, 34, 20, Color.DarkBlue);
|
||||
DrawText("in raylib", 757, 42, 6, Color.Black);
|
||||
|
||||
DrawText("Presets", 710, 58, 8, Color.Gray);
|
||||
preset = -1;
|
||||
|
||||
// Draw GUI controls
|
||||
//------------------------------------------------------------------------------
|
||||
// NOTE: raygui is not bound in raylib-cs; controls are kept for reference. The
|
||||
// simulation still runs automatically and mouse wheel zoom / left-drag pan work.
|
||||
/*for (int i = 0; i < numberOfPresets; i++)
|
||||
if (GuiButton(new Rectangle( 710.0f, 70.0f + 18*i, 80.0f, 16.0f ), presetPatterns[i].Name)) preset = i;
|
||||
|
||||
GuiToggleGroup(new Rectangle( 710, 258, 80, 16 ), "Run\nPause\nDraw", ref mode);*/
|
||||
|
||||
DrawText($"Zoom: {zoom}x", 710, 316, 8, Color.Gray);
|
||||
/*buttonZoomIn = GuiButton(new Rectangle( 710, 328, 80, 16 ), "Zoom in");
|
||||
buttonZomOut = GuiButton(new Rectangle( 710, 346, 80, 16 ), "Zoom out");*/
|
||||
|
||||
DrawText($"Speed: {framesPerStep} frame{((framesPerStep > 1) ? "s" : "")}", 710, 370, 8, Color.Gray);
|
||||
/*buttonFaster = GuiButton(new Rectangle( 710, 382, 80, 16 ), "Faster");
|
||||
buttonSlower = GuiButton(new Rectangle( 710, 400, 80, 16 ), "Slower");*/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DrawFPS(712, 426);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shdrGameOfLife);
|
||||
UnloadRenderTexture(world1);
|
||||
UnloadRenderTexture(world2);
|
||||
|
||||
FreeImageToDraw();
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - game of life");
|
||||
|
||||
SetTargetFPS(60); // Set at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new GameOfLife();
|
||||
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,135 +1,189 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - Hot reloading
|
||||
* raylib [shaders] example - hot reloading
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 for shaders support and only #version 330
|
||||
* is currently supported. OpenGL ES 2.0 platforms are not supported at the moment.
|
||||
* is currently supported. OpenGL ES 2.0 platforms are not supported at the moment
|
||||
*
|
||||
* This example has been created using raylib 3.0 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example originally created with raylib 3.0, last time updated with raylib 3.5
|
||||
*
|
||||
* Copyright (c) 2020 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) 2020-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class HotReloading
|
||||
public class HotReloading : IExample
|
||||
{
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Shaders / Hot Reloading";
|
||||
|
||||
public string Title => "raylib [shaders] example - hot reloading";
|
||||
|
||||
private string fragShaderFileName;
|
||||
private Shader shader;
|
||||
private int resolutionLoc;
|
||||
private int mouseLoc;
|
||||
private int timeLoc;
|
||||
private float[] resolution;
|
||||
private float totalTime;
|
||||
#if !BROWSER
|
||||
private long fragShaderFileModTime;
|
||||
private bool shaderAutoReloading;
|
||||
#endif
|
||||
|
||||
public void Init()
|
||||
{
|
||||
fragShaderFileName = $"resources/shaders/glsl{GlslVersion}/reload.fs";
|
||||
#if !BROWSER
|
||||
fragShaderFileModTime = GetFileModTime(fragShaderFileName);
|
||||
#endif
|
||||
|
||||
// Load raymarching shader
|
||||
// NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
|
||||
shader = LoadShader(null, fragShaderFileName);
|
||||
|
||||
// Get shader locations for required uniforms
|
||||
resolutionLoc = GetShaderLocation(shader, "resolution");
|
||||
mouseLoc = GetShaderLocation(shader, "mouse");
|
||||
timeLoc = GetShaderLocation(shader, "time");
|
||||
|
||||
resolution = new[] { (float)screenWidth, (float)screenHeight };
|
||||
Raylib.SetShaderValue(shader, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
|
||||
|
||||
totalTime = 0.0f;
|
||||
#if !BROWSER
|
||||
shaderAutoReloading = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
totalTime += GetFrameTime();
|
||||
var mouse = GetMousePosition();
|
||||
var mousePos = new[] { mouse.X, mouse.Y };
|
||||
|
||||
// Set shader required uniform values
|
||||
Raylib.SetShaderValue(shader, timeLoc, totalTime, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, mouseLoc, mousePos, ShaderUniformDataType.Vec2);
|
||||
|
||||
#if !BROWSER
|
||||
// Hot shader reloading
|
||||
if (shaderAutoReloading || (IsMouseButtonPressed(MouseButton.Left)))
|
||||
{
|
||||
var currentFragShaderModTime = GetFileModTime(fragShaderFileName);
|
||||
|
||||
// Check if shader file has been modified
|
||||
if (currentFragShaderModTime != fragShaderFileModTime)
|
||||
{
|
||||
// Try reloading updated shader
|
||||
var updatedShader = LoadShader(null, fragShaderFileName);
|
||||
|
||||
// It was correctly loaded
|
||||
if (updatedShader.Id != Rlgl.GetShaderIdDefault())
|
||||
{
|
||||
UnloadShader(shader);
|
||||
shader = updatedShader;
|
||||
|
||||
// Get shader locations for required uniforms
|
||||
resolutionLoc = GetShaderLocation(shader, "resolution");
|
||||
mouseLoc = GetShaderLocation(shader, "mouse");
|
||||
timeLoc = GetShaderLocation(shader, "time");
|
||||
|
||||
// Reset required uniforms
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
resolutionLoc,
|
||||
resolution,
|
||||
ShaderUniformDataType.Vec2
|
||||
);
|
||||
}
|
||||
|
||||
fragShaderFileModTime = currentFragShaderModTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.A))
|
||||
{
|
||||
shaderAutoReloading = !shaderAutoReloading;
|
||||
}
|
||||
#endif
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// We only draw a white full-screen rectangle, frame is generated in shader
|
||||
BeginShaderMode(shader);
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
#if BROWSER
|
||||
DrawText("Shader generates the frame in real time", 10, 10, 10, Color.Black);
|
||||
#else
|
||||
var info = $"PRESS [A] to TOGGLE SHADER AUTOLOADING: {(shaderAutoReloading ? "AUTO" : "MANUAL")}";
|
||||
DrawText(info, 10, 10, 10, shaderAutoReloading ? Color.Red : Color.Black);
|
||||
if (!shaderAutoReloading)
|
||||
{
|
||||
DrawText("MOUSE CLICK to SHADER RE-LOADING", 10, 30, 10, Color.Black);
|
||||
}
|
||||
|
||||
var lastModification = DateTimeOffset.FromUnixTimeSeconds(fragShaderFileModTime).LocalDateTime.ToString();
|
||||
DrawText($"Shader last modification: {lastModification}", 10, 430, 10, Color.Black);
|
||||
#endif
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
int screenWidth = 800;
|
||||
int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - hot reloading");
|
||||
|
||||
string fragShaderFileName = "resources/shaders/glsl330/reload.fs";
|
||||
long fragShaderFileModTime = GetFileModTime(fragShaderFileName);
|
||||
|
||||
// Load raymarching shader
|
||||
// NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
|
||||
Shader shader = LoadShader(null, fragShaderFileName);
|
||||
|
||||
// Get shader locations for required uniforms
|
||||
int resolutionLoc = GetShaderLocation(shader, "resolution");
|
||||
int mouseLoc = GetShaderLocation(shader, "mouse");
|
||||
int timeLoc = GetShaderLocation(shader, "time");
|
||||
|
||||
float[] resolution = new[] { (float)screenWidth, (float)screenHeight };
|
||||
Raylib.SetShaderValue(shader, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
|
||||
|
||||
float totalTime = 0.0f;
|
||||
bool shaderAutoReloading = false;
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new HotReloading();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
totalTime += GetFrameTime();
|
||||
Vector2 mouse = GetMousePosition();
|
||||
float[] mousePos = new[] { mouse.X, mouse.Y };
|
||||
|
||||
// Set shader required uniform values
|
||||
Raylib.SetShaderValue(shader, timeLoc, totalTime, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, mouseLoc, mousePos, ShaderUniformDataType.Vec2);
|
||||
|
||||
// Hot shader reloading
|
||||
if (shaderAutoReloading || (IsMouseButtonPressed(MouseButton.Left)))
|
||||
{
|
||||
long currentFragShaderModTime = GetFileModTime(fragShaderFileName);
|
||||
|
||||
// Check if shader file has been modified
|
||||
if (currentFragShaderModTime != fragShaderFileModTime)
|
||||
{
|
||||
// Try reloading updated shader
|
||||
Shader updatedShader = LoadShader(null, fragShaderFileName);
|
||||
|
||||
// It was correctly loaded
|
||||
if (updatedShader.Id != 0) //rlGetShaderIdDefault())
|
||||
{
|
||||
UnloadShader(shader);
|
||||
shader = updatedShader;
|
||||
|
||||
// Get shader locations for required uniforms
|
||||
resolutionLoc = GetShaderLocation(shader, "resolution");
|
||||
mouseLoc = GetShaderLocation(shader, "mouse");
|
||||
timeLoc = GetShaderLocation(shader, "time");
|
||||
|
||||
// Reset required uniforms
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
resolutionLoc,
|
||||
resolution,
|
||||
ShaderUniformDataType.Vec2
|
||||
);
|
||||
}
|
||||
|
||||
fragShaderFileModTime = currentFragShaderModTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.A))
|
||||
{
|
||||
shaderAutoReloading = !shaderAutoReloading;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// We only draw a white full-screen rectangle, frame is generated in shader
|
||||
BeginShaderMode(shader);
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
string info = $"PRESS [A] to TOGGLE SHADER AUTOLOADING: {(shaderAutoReloading ? "AUTO" : "MANUAL")}";
|
||||
DrawText(info, 10, 10, 10, shaderAutoReloading ? Color.Red : Color.Black);
|
||||
if (!shaderAutoReloading)
|
||||
{
|
||||
DrawText("MOUSE CLICK to SHADER RE-LOADING", 10, 30, 10, Color.Black);
|
||||
}
|
||||
|
||||
// DrawText($"Shader last modification: ", 10, 430, 10, Color.BLACK);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadShader(shader);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - Hybrid Rendering
|
||||
* raylib [shaders] example - hybrid rendering
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 4.2, last time updated with raylib 4.2
|
||||
*
|
||||
|
|
@ -9,7 +11,7 @@
|
|||
* 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 Buğra Alptekin Sarı (@BugraAlptekinSari)
|
||||
* Copyright (c) 2022-2025 Buğra Alptekin Sarı (@BugraAlptekinSari)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -19,43 +21,54 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class HybridRender
|
||||
public class HybridRender : IExample
|
||||
{
|
||||
struct RayLocs
|
||||
private struct RayLocs
|
||||
{
|
||||
public int CamPos;
|
||||
public int CamDir;
|
||||
public int ScreenCenter;
|
||||
}
|
||||
|
||||
const int GLSL_VERSION = 330;
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Shaders / Hybrid Render";
|
||||
|
||||
public string Title => "raylib [shaders] example - hybrid rendering";
|
||||
|
||||
private Shader shdrRaymarch;
|
||||
private Shader shdrRaster;
|
||||
private RayLocs marchLocs;
|
||||
private RenderTexture2D target;
|
||||
private Camera3D camera;
|
||||
private float camDist;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - hybrid render");
|
||||
|
||||
// This shader calculates pixel depth and color using raymarch
|
||||
Shader shdrRaymarch = LoadShader(null, $"resources/shaders/glsl{GLSL_VERSION}/hybrid_raymarch.fs");
|
||||
// This Shader calculates pixel depth and color using raymarch
|
||||
shdrRaymarch = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/hybrid_raymarch.fs");
|
||||
|
||||
// This Shader is a standard rasterization fragment shader with the addition of depth writing
|
||||
// You are required to write depth for all shaders if one shader does it
|
||||
Shader shdrRaster = LoadShader(null, $"resources/shaders/glsl{GLSL_VERSION}/hybrid_raster.fs");
|
||||
shdrRaster = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/hybrid_raster.fs");
|
||||
|
||||
// Declare struct used to store camera locs
|
||||
RayLocs marchLocs = new();
|
||||
// Declare Struct used to store camera locs
|
||||
marchLocs = new();
|
||||
|
||||
// Fill the struct with shader locs.
|
||||
// Fill the struct with shader locs
|
||||
marchLocs.CamPos = GetShaderLocation(shdrRaymarch, "camPos");
|
||||
marchLocs.CamDir = GetShaderLocation(shdrRaymarch, "camDir");
|
||||
marchLocs.ScreenCenter = GetShaderLocation(shdrRaymarch, "screenCenter");
|
||||
|
||||
// Transfer screenCenter position to shader. Which is used to calculate ray direction.
|
||||
Vector2 screenCenter = new(screenWidth / 2, screenHeight / 2);
|
||||
// Transfer screenCenter position to shader. Which is used to calculate ray direction
|
||||
Vector2 screenCenter = new(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
SetShaderValue(
|
||||
shdrRaymarch,
|
||||
marchLocs.ScreenCenter,
|
||||
|
|
@ -63,91 +76,111 @@ public class HybridRender
|
|||
ShaderUniformDataType.Vec2
|
||||
);
|
||||
|
||||
// Use customized function to create writable depth texture buffer
|
||||
RenderTexture2D target = LoadRenderTextureDepthTex(screenWidth, screenHeight);
|
||||
// Use Customized function to create writable depth texture buffer
|
||||
target = LoadRenderTextureDepthTex(screenWidth, screenHeight);
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera;
|
||||
camera.Position = new Vector3(0.5f, 1.0f, 1.5f);
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 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.5f, 1.0f, 1.5f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 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
|
||||
|
||||
// Camera FOV is pre-calculated in the camera Distance.
|
||||
float camDist = 1.0f / (MathF.Tan(camera.FovY * 0.5f * Raylib.DEG2RAD));
|
||||
// Camera FOV is pre-calculated in the camera distance
|
||||
camDist = 1.0f / (MathF.Tan(camera.FovY * 0.5f * Raylib.DEG2RAD));
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Update Camera Postion in the ray march shader
|
||||
SetShaderValue(
|
||||
shdrRaymarch,
|
||||
marchLocs.CamPos,
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
// Update Camera Looking Vector. Vector length determines FOV
|
||||
var camDir = Vector3.Normalize(camera.Target - camera.Position) * camDist;
|
||||
SetShaderValue(shdrRaymarch, marchLocs.CamDir, camDir, ShaderUniformDataType.Vec3);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw into our custom render texture (framebuffer)
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.White);
|
||||
|
||||
// Raymarch Scene
|
||||
// Manually enable Depth Test to handle multiple rendering methods
|
||||
Rlgl.EnableDepthTest();
|
||||
BeginShaderMode(shdrRaymarch);
|
||||
DrawRectangleRec(new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
// Rasterize Scene
|
||||
BeginMode3D(camera);
|
||||
BeginShaderMode(shdrRaster);
|
||||
DrawCubeWiresV(new Vector3(0.0f, 0.5f, 1.0f), new Vector3(1.0f, 1.0f, 1.0f), Color.Red);
|
||||
DrawCubeV(new Vector3(0.0f, 0.5f, 1.0f), new Vector3(1.0f, 1.0f, 1.0f), Color.Purple);
|
||||
DrawCubeWiresV(new Vector3(0.0f, 0.5f, -1.0f), new Vector3(1.0f, 1.0f, 1.0f), Color.DarkGreen);
|
||||
DrawCubeV(new Vector3(0.0f, 0.5f, -1.0f), new Vector3(1.0f, 1.0f, 1.0f), Color.Yellow);
|
||||
DrawGrid(10, 1.0f);
|
||||
EndShaderMode();
|
||||
EndMode3D();
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
// Draw custom render texture
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, screenWidth, -screenHeight),
|
||||
Vector2.Zero,
|
||||
Color.White
|
||||
);
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTextureDepthTex(target);
|
||||
UnloadShader(shdrRaymarch);
|
||||
UnloadShader(shdrRaster);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - hybrid rendering");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new HybridRender();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Update Camera Postion in the ray march shader.
|
||||
SetShaderValue(
|
||||
shdrRaymarch,
|
||||
marchLocs.CamPos,
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
// Update Camera Looking Vector. Vector length determines FOV.
|
||||
Vector3 camDir = Vector3.Normalize(camera.Target - camera.Position) * camDist;
|
||||
SetShaderValue(shdrRaymarch, marchLocs.CamDir, camDir, ShaderUniformDataType.Vec3);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw into our custom render texture (framebuffer)
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.White);
|
||||
|
||||
// Raymarch Scene
|
||||
// Manually enable Depth Test to handle multiple rendering methods.
|
||||
Rlgl.EnableDepthTest();
|
||||
BeginShaderMode(shdrRaymarch);
|
||||
DrawRectangleRec(new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
// Rasterize Scene
|
||||
BeginMode3D(camera);
|
||||
BeginShaderMode(shdrRaster);
|
||||
DrawCubeWiresV(new Vector3(0.0f, 0.5f, 1.0f), new Vector3(1.0f, 1.0f, 1.0f), Color.Red);
|
||||
DrawCubeV(new Vector3(0.0f, 0.5f, 1.0f), new Vector3(1.0f, 1.0f, 1.0f), Color.Purple);
|
||||
DrawCubeWiresV(new Vector3(0.0f, 0.5f, -1.0f), new Vector3(1.0f, 1.0f, 1.0f), Color.DarkGreen);
|
||||
DrawCubeV(new Vector3(0.0f, 0.5f, -1.0f), new Vector3(1.0f, 1.0f, 1.0f), Color.Yellow);
|
||||
DrawGrid(10, 1.0f);
|
||||
EndShaderMode();
|
||||
EndMode3D();
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
// Draw custom render texture
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, screenWidth, -screenHeight),
|
||||
Vector2.Zero,
|
||||
Color.White
|
||||
);
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadRenderTextureDepthTex(target);
|
||||
UnloadShader(shdrRaymarch);
|
||||
UnloadShader(shdrRaster);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -203,7 +236,7 @@ public class HybridRender
|
|||
);
|
||||
|
||||
// Check if fbo is complete with attachments (valid)
|
||||
if (Rlgl.FramebufferComplete(target.Id))
|
||||
if (Rlgl.FramebufferComplete(target.Id) != 0)
|
||||
{
|
||||
TraceLog(TraceLogLevel.Info, $"FBO: [ID {target.Id}] Framebuffer object created successfully");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - julia sets
|
||||
* raylib [shaders] example - julia set
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3).
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* 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 originally created with raylib 2.5, last time updated with raylib 4.0
|
||||
*
|
||||
* Example contributed by eggmund (@eggmund) and reviewed by Ramon Santamaria (@raysan5)
|
||||
* Example contributed by Josh Colclough (@joshcol9232) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2019 eggmund (@eggmund) 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 Josh Colclough (@joshcol9232) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -21,12 +25,27 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class JuliaSet
|
||||
public class JuliaSet : IExample
|
||||
{
|
||||
const int GlslVersion = 330;
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
private const float zoomSpeed = 1.01f;
|
||||
private const float offsetSpeedMul = 2.0f;
|
||||
|
||||
private const float startingZoom = 0.75f;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Julia Set";
|
||||
|
||||
public string Title => "raylib [shaders] example - julia set";
|
||||
|
||||
// A few good julia sets
|
||||
static float[][] PointsOfInterest = new float[][] {
|
||||
private float[][] PointsOfInterest = new float[][] {
|
||||
new float[] { -0.348827f, 0.607167f },
|
||||
new float[] { -0.786268f, 0.169728f },
|
||||
new float[] { -0.8f, 0.156f },
|
||||
|
|
@ -35,38 +54,38 @@ public class JuliaSet
|
|||
new float[] { -0.70176f, -0.3842f },
|
||||
};
|
||||
|
||||
public static int Main()
|
||||
private Shader shader;
|
||||
private RenderTexture2D target;
|
||||
private float[] c;
|
||||
private float[] offset;
|
||||
private float zoom;
|
||||
private int cLoc;
|
||||
private int zoomLoc;
|
||||
private int offsetLoc;
|
||||
private int incrementSpeed;
|
||||
private bool showControls;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
const float zoomSpeed = 1.01f;
|
||||
const float offsetSpeedMul = 2.0f;
|
||||
|
||||
const float startingZoom = 0.75f;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - julia sets");
|
||||
|
||||
// Load julia set shader
|
||||
// NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
|
||||
Shader shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/julia_set.fs");
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/julia_set.fs");
|
||||
|
||||
// Create a RenderTexture2D to be used for render to texture
|
||||
RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
|
||||
// c constant to use in z^2 + c
|
||||
float[] c = { PointsOfInterest[0][0], PointsOfInterest[0][1] };
|
||||
c = new float[] { PointsOfInterest[0][0], PointsOfInterest[0][1] };
|
||||
|
||||
// Offset and zoom to draw the julia set at. (centered on screen and default size)
|
||||
float[] offset = { 0, 0 };
|
||||
float zoom = startingZoom;
|
||||
offset = new float[] { 0, 0 };
|
||||
zoom = startingZoom;
|
||||
|
||||
// Get variable (uniform) locations on the shader to connect with the program
|
||||
// NOTE: If uniform variable could not be found in the shader, function returns -1
|
||||
int cLoc = GetShaderLocation(shader, "c");
|
||||
int zoomLoc = GetShaderLocation(shader, "zoom");
|
||||
int offsetLoc = GetShaderLocation(shader, "offset");
|
||||
cLoc = GetShaderLocation(shader, "c");
|
||||
zoomLoc = GetShaderLocation(shader, "zoom");
|
||||
offsetLoc = GetShaderLocation(shader, "offset");
|
||||
|
||||
// Upload the shader uniform values!
|
||||
Raylib.SetShaderValue(shader, cLoc, c, ShaderUniformDataType.Vec2);
|
||||
|
|
@ -74,166 +93,189 @@ public class JuliaSet
|
|||
Raylib.SetShaderValue(shader, offsetLoc, offset, ShaderUniformDataType.Vec2);
|
||||
|
||||
// Multiplier of speed to change c value
|
||||
int incrementSpeed = 0;
|
||||
incrementSpeed = 0;
|
||||
// Show controls
|
||||
bool showControls = true;
|
||||
showControls = true;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Press [1 - 6] to reset c to a point of interest
|
||||
if (IsKeyPressed(KeyboardKey.One) ||
|
||||
IsKeyPressed(KeyboardKey.Two) ||
|
||||
IsKeyPressed(KeyboardKey.Three) ||
|
||||
IsKeyPressed(KeyboardKey.Four) ||
|
||||
IsKeyPressed(KeyboardKey.Five) ||
|
||||
IsKeyPressed(KeyboardKey.Six))
|
||||
{
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
c[0] = PointsOfInterest[0][0];
|
||||
c[1] = PointsOfInterest[0][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
c[0] = PointsOfInterest[1][0];
|
||||
c[1] = PointsOfInterest[1][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
c[0] = PointsOfInterest[2][0];
|
||||
c[1] = PointsOfInterest[2][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
c[0] = PointsOfInterest[3][0];
|
||||
c[1] = PointsOfInterest[3][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Five))
|
||||
{
|
||||
c[0] = PointsOfInterest[4][0];
|
||||
c[1] = PointsOfInterest[4][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Six))
|
||||
{
|
||||
c[0] = PointsOfInterest[5][0];
|
||||
c[1] = PointsOfInterest[5][1];
|
||||
}
|
||||
Raylib.SetShaderValue(shader, cLoc, c, ShaderUniformDataType.Vec2);
|
||||
}
|
||||
|
||||
// If "R" is pressed, reset zoom and offset
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
zoom = startingZoom;
|
||||
offset[0] = 0.0f;
|
||||
offset[1] = 0.0f;
|
||||
Raylib.SetShaderValue(shader, zoomLoc, zoom, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, offsetLoc, offset, ShaderUniformDataType.Vec2);
|
||||
}
|
||||
|
||||
// Pause animation (c change)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
incrementSpeed = 0;
|
||||
}
|
||||
|
||||
// Toggle whether or not to show controls
|
||||
if (IsKeyPressed(KeyboardKey.F1))
|
||||
{
|
||||
showControls = !showControls;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
incrementSpeed++;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
incrementSpeed--;
|
||||
}
|
||||
|
||||
// If either left or right button is pressed, zoom in/out
|
||||
if (IsMouseButtonDown(MouseButton.Left) || IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
if (IsMouseButtonDown(MouseButton.Left))
|
||||
{
|
||||
zoom *= zoomSpeed;
|
||||
}
|
||||
|
||||
if (IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
zoom *= 1.0f / zoomSpeed;
|
||||
}
|
||||
|
||||
var mousePos = GetMousePosition();
|
||||
var offsetVelocity = Vector2.Zero;
|
||||
|
||||
offsetVelocity.X = (mousePos.X / screenWidth - 0.5f) * offsetSpeedMul / zoom;
|
||||
offsetVelocity.Y = (mousePos.Y / screenHeight - 0.5f) * offsetSpeedMul / zoom;
|
||||
|
||||
// Apply move velocity to camera
|
||||
offset[0] += GetFrameTime() * offsetVelocity.X;
|
||||
offset[1] += GetFrameTime() * offsetVelocity.Y;
|
||||
|
||||
Raylib.SetShaderValue(shader, zoomLoc, zoom, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, offsetLoc, offset, ShaderUniformDataType.Vec2);
|
||||
}
|
||||
|
||||
// Increment c value with time
|
||||
var dc = GetFrameTime() * incrementSpeed * 0.0005f;
|
||||
c[0] += dc;
|
||||
c[1] += dc;
|
||||
|
||||
Raylib.SetShaderValue(shader, cLoc, c, ShaderUniformDataType.Vec2);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Using a render texture to draw Julia set
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
// Draw a rectangle in shader mode to be used as shader canvas
|
||||
// NOTE: Rectangle uses font white character texture coordinates,
|
||||
// so shader can not be applied here directly because input vertexTexCoord
|
||||
// do not represent full screen coordinates (space where want to apply shader)
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Black);
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
// Draw the saved texture and rendered julia set with shader
|
||||
// NOTE: We do not invert texture on Y, already considered inside shader
|
||||
BeginShaderMode(shader);
|
||||
// WARNING: If FLAG_WINDOW_HIGHDPI is enabled, HighDPI monitor scaling should be considered
|
||||
// when rendering the RenderTexture2D to fit in the HighDPI scaled Window
|
||||
DrawTextureEx(target.Texture, new Vector2(0.0f, 0.0f), 0.0f, 1.0f, Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
if (showControls)
|
||||
{
|
||||
DrawText("Press Mouse buttons right/left to zoom in/out and move", 10, 15, 10, Color.RayWhite);
|
||||
DrawText("Press KEY_F1 to toggle these controls", 10, 30, 10, Color.RayWhite);
|
||||
DrawText("Press KEYS [1 - 6] to change point of interest", 10, 45, 10, Color.RayWhite);
|
||||
DrawText("Press KEY_LEFT | KEY_RIGHT to change speed", 10, 60, 10, Color.RayWhite);
|
||||
DrawText("Press KEY_SPACE to stop movement animation", 10, 75, 10, Color.RayWhite);
|
||||
DrawText("Press KEY_R to recenter the camera", 10, 90, 10, Color.RayWhite);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader);
|
||||
UnloadRenderTexture(target);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - julia set");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new JuliaSet();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Press [1 - 6] to reset c to a point of interest
|
||||
if (IsKeyPressed(KeyboardKey.One) ||
|
||||
IsKeyPressed(KeyboardKey.Two) ||
|
||||
IsKeyPressed(KeyboardKey.Three) ||
|
||||
IsKeyPressed(KeyboardKey.Four) ||
|
||||
IsKeyPressed(KeyboardKey.Five) ||
|
||||
IsKeyPressed(KeyboardKey.Six))
|
||||
{
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
c[0] = PointsOfInterest[0][0];
|
||||
c[1] = PointsOfInterest[0][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
c[0] = PointsOfInterest[1][0];
|
||||
c[1] = PointsOfInterest[1][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
c[0] = PointsOfInterest[2][0];
|
||||
c[1] = PointsOfInterest[2][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
c[0] = PointsOfInterest[3][0];
|
||||
c[1] = PointsOfInterest[3][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Five))
|
||||
{
|
||||
c[0] = PointsOfInterest[4][0];
|
||||
c[1] = PointsOfInterest[4][1];
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Six))
|
||||
{
|
||||
c[0] = PointsOfInterest[5][0];
|
||||
c[1] = PointsOfInterest[5][1];
|
||||
}
|
||||
Raylib.SetShaderValue(shader, cLoc, c, ShaderUniformDataType.Vec2);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
zoom = startingZoom;
|
||||
offset[0] = 1f;
|
||||
offset[1] = 1f;
|
||||
Raylib.SetShaderValue(shader, zoomLoc, zoom, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, offsetLoc, offset, ShaderUniformDataType.Vec2);
|
||||
}
|
||||
|
||||
// Pause animation (c change)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
incrementSpeed = 0;
|
||||
}
|
||||
|
||||
// Toggle whether or not to show controls
|
||||
if (IsKeyPressed(KeyboardKey.F1))
|
||||
{
|
||||
showControls = !showControls;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
incrementSpeed++;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
incrementSpeed--;
|
||||
}
|
||||
|
||||
// If either left or right button is pressed, zoom in/out
|
||||
if (IsMouseButtonDown(MouseButton.Left) || IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
if (IsMouseButtonDown(MouseButton.Left))
|
||||
{
|
||||
zoom *= zoomSpeed;
|
||||
}
|
||||
|
||||
if (IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
zoom *= 1.0f / zoomSpeed;
|
||||
}
|
||||
|
||||
Vector2 mousePos = GetMousePosition();
|
||||
Vector2 offsetVelocity = Vector2.Zero;
|
||||
|
||||
offsetVelocity.X = (mousePos.X / screenWidth - 0.5f) * offsetSpeedMul / zoom;
|
||||
offsetVelocity.Y = (mousePos.Y / screenHeight - 0.5f) * offsetSpeedMul / zoom;
|
||||
|
||||
// Apply move velocity to camera
|
||||
offset[0] += GetFrameTime() * offsetVelocity.X;
|
||||
offset[1] += GetFrameTime() * offsetVelocity.Y;
|
||||
|
||||
Raylib.SetShaderValue(shader, zoomLoc, zoom, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, offsetLoc, offset, ShaderUniformDataType.Vec2);
|
||||
}
|
||||
|
||||
// Increment c value with time
|
||||
float amount = GetFrameTime() * incrementSpeed * 0.0005f;
|
||||
c[0] += amount;
|
||||
c[1] += amount;
|
||||
|
||||
Raylib.SetShaderValue(shader, cLoc, c, ShaderUniformDataType.Vec2);
|
||||
|
||||
// Using a render texture to draw Julia set
|
||||
// Enable drawing to texture
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
// Draw a rectangle in shader mode to be used as shader canvas
|
||||
// NOTE: Rectangle uses font Color.white character texture coordinates,
|
||||
// so shader can not be applied here directly because input vertexTexCoord
|
||||
// do not represent full screen coordinates (space where want to apply shader)
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Black);
|
||||
EndTextureMode();
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
// Draw the saved texture and rendered julia set with shader
|
||||
// NOTE: We do not invert texture on Y, already considered inside shader
|
||||
BeginShaderMode(shader);
|
||||
DrawTexture(target.Texture, 0, 0, Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
if (showControls)
|
||||
{
|
||||
DrawText("Press Mouse buttons right/left to zoom in/out and move", 10, 15, 10, Color.RayWhite);
|
||||
DrawText("Press KEY_F1 to toggle these controls", 10, 30, 10, Color.RayWhite);
|
||||
DrawText("Press KEYS [1 - 6] to change point of interest", 10, 45, 10, Color.RayWhite);
|
||||
DrawText("Press KEY_LEFT | KEY_RIGHT to change speed", 10, 60, 10, Color.RayWhite);
|
||||
DrawText("Press KEY_SPACE to pause movement animation", 10, 75, 10, Color.RayWhite);
|
||||
DrawText("Press KEY_R to recenter the camera", 10, 90, 10, Color.RayWhite);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadShader(shader);
|
||||
UnloadRenderTexture(target);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
213
Examples/Shaders/LightmapRendering.cs
Normal file
213
Examples/Shaders/LightmapRendering.cs
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - lightmap rendering
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by Jussi Viitala (@nullstare) 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) 2019-2025 Jussi Viitala (@nullstare) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Rlgl;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class LightmapRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MapSize = 16;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Lightmap Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - lightmap rendering";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Mesh mesh;
|
||||
private Shader shader;
|
||||
private Texture2D texture;
|
||||
private Texture2D light;
|
||||
private RenderTexture2D lightmap;
|
||||
private Material material;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(4.0f, 6.0f, 8.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
|
||||
|
||||
mesh = GenMeshPlane((float)MapSize, (float)MapSize, 1, 1);
|
||||
|
||||
// GenMeshPlane doesn't generate texcoords2 so we will upload them separately
|
||||
mesh.AllocTexCoords2();
|
||||
|
||||
// X // Y
|
||||
mesh.TexCoords2[0] = 0.0f; mesh.TexCoords2[1] = 0.0f;
|
||||
mesh.TexCoords2[2] = 1.0f; mesh.TexCoords2[3] = 0.0f;
|
||||
mesh.TexCoords2[4] = 0.0f; mesh.TexCoords2[5] = 1.0f;
|
||||
mesh.TexCoords2[6] = 1.0f; mesh.TexCoords2[7] = 1.0f;
|
||||
|
||||
// Load a new texcoords2 attributes buffer
|
||||
mesh.VboId[(int)ShaderLocationIndex.VertexTexcoord02] =
|
||||
LoadVertexBuffer(mesh.TexCoords2, mesh.VertexCount * 2 * sizeof(float), false);
|
||||
EnableVertexArray(mesh.VaoId);
|
||||
|
||||
// Index 5 is for texcoords2
|
||||
SetVertexAttribute(5, 2, Rlgl.FLOAT, false, 0, 0);
|
||||
EnableVertexAttribute(5);
|
||||
DisableVertexArray();
|
||||
|
||||
// Load lightmap shader
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/lightmap.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/lightmap.fs"
|
||||
);
|
||||
|
||||
texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
light = LoadTexture("resources/spark_flame.png");
|
||||
|
||||
GenTextureMipmaps(ref texture);
|
||||
SetTextureFilter(texture, TextureFilter.Trilinear);
|
||||
|
||||
lightmap = LoadRenderTexture(MapSize, MapSize);
|
||||
|
||||
material = LoadMaterialDefault();
|
||||
material.Shader = shader;
|
||||
material.Maps[(int)MaterialMapIndex.Albedo].Texture = texture;
|
||||
material.Maps[(int)MaterialMapIndex.Metalness].Texture = lightmap.Texture;
|
||||
|
||||
// Drawing to lightmap
|
||||
BeginTextureMode(lightmap);
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
BeginBlendMode(BlendMode.Additive);
|
||||
DrawTexturePro(
|
||||
light,
|
||||
new Rectangle(0, 0, (float)light.Width, (float)light.Height),
|
||||
new Rectangle(0, 0, 2.0f * MapSize, 2.0f * MapSize),
|
||||
new Vector2((float)MapSize, (float)MapSize),
|
||||
0.0f,
|
||||
Color.Red
|
||||
);
|
||||
DrawTexturePro(
|
||||
light,
|
||||
new Rectangle(0, 0, (float)light.Width, (float)light.Height),
|
||||
new Rectangle((float)MapSize * 0.8f, (float)MapSize / 2.0f, 2.0f * MapSize, 2.0f * MapSize),
|
||||
new Vector2((float)MapSize, (float)MapSize),
|
||||
0.0f,
|
||||
Color.Blue
|
||||
);
|
||||
DrawTexturePro(
|
||||
light,
|
||||
new Rectangle(0, 0, (float)light.Width, (float)light.Height),
|
||||
new Rectangle((float)MapSize * 0.8f, (float)MapSize * 0.8f, (float)MapSize, (float)MapSize),
|
||||
new Vector2((float)MapSize / 2.0f, (float)MapSize / 2.0f),
|
||||
0.0f,
|
||||
Color.Green
|
||||
);
|
||||
BeginBlendMode(BlendMode.Alpha);
|
||||
EndTextureMode();
|
||||
|
||||
// NOTE: To enable trilinear filtering we need mipmaps available for texture
|
||||
GenTextureMipmaps(ref lightmap.Texture);
|
||||
SetTextureFilter(lightmap.Texture, TextureFilter.Trilinear);
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawMesh(mesh, material, Matrix4x4.Identity);
|
||||
EndMode3D();
|
||||
|
||||
DrawTexturePro(
|
||||
lightmap.Texture,
|
||||
new Rectangle(0, 0, -MapSize, -MapSize),
|
||||
new Rectangle((float)GetRenderWidth() - MapSize * 8 - 10, 10, (float)MapSize * 8, (float)MapSize * 8),
|
||||
new Vector2(0.0f, 0.0f),
|
||||
0.0f,
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawText($"LIGHTMAP: {MapSize}x{MapSize} pixels", GetRenderWidth() - 130, 20 + MapSize * 8, 10, Color.Green);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMesh(mesh); // Unload the mesh
|
||||
UnloadShader(shader); // Unload shader
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadTexture(light); // Unload texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - lightmap rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LightmapRendering();
|
||||
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;
|
||||
}
|
||||
}
|
||||
265
Examples/Shaders/MandelbrotSet.cs
Normal file
265
Examples/Shaders/MandelbrotSet.cs
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - mandelbrot set
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jordi Santonja (@JordSant)
|
||||
* Based on previous work by Josh Colclough (@joshcol9232)
|
||||
*
|
||||
* 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 Jordi Santonja (@JordSant)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class MandelbrotSet : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Mandelbrot Set";
|
||||
|
||||
public string Title => "raylib [shaders] example - mandelbrot set";
|
||||
|
||||
// A few good interesting places
|
||||
private static readonly float[][] pointsOfInterest = new[]
|
||||
{
|
||||
new[] { -1.76826775f, -0.00422996283f, 28435.9238f },
|
||||
new[] { 0.322004497f, -0.0357099883f, 56499.7266f },
|
||||
new[] { -0.748880744f, -0.0562955774f, 9237.59082f },
|
||||
new[] { -1.78385007f, -0.0156200649f, 14599.5283f },
|
||||
new[] { -0.0985441282f, -0.924688697f, 26259.8535f },
|
||||
new[] { 0.317785531f, -0.0322612226f, 29297.9258f },
|
||||
};
|
||||
|
||||
private const float zoomSpeed = 1.01f;
|
||||
private const float offsetSpeedMul = 2.0f;
|
||||
|
||||
private const float startingZoom = 0.6f;
|
||||
private static readonly float[] startingOffset = { -0.5f, 0.0f };
|
||||
|
||||
private Shader shader;
|
||||
private RenderTexture2D target;
|
||||
private float[] offset;
|
||||
private float zoom;
|
||||
private int maxIterations;
|
||||
private float maxIterationsMultiplier;
|
||||
private int zoomLoc;
|
||||
private int offsetLoc;
|
||||
private int maxIterationsLoc;
|
||||
private bool showControls;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Load mandelbrot set shader
|
||||
// NOTE: Defining null (NULL) for vertex shader forces usage of internal default vertex shader
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/mandelbrot_set.fs");
|
||||
|
||||
// Create a RenderTexture2D to be used for render to texture
|
||||
target = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||
|
||||
// Offset and zoom to draw the mandelbrot set at. (centered on screen and default size)
|
||||
offset = new[] { startingOffset[0], startingOffset[1] };
|
||||
zoom = startingZoom;
|
||||
|
||||
// Depending on the zoom the maximum number of iterations must be adapted to get more detail as we zoom in
|
||||
// The solution is not perfect, so a control has been added to increase/decrease the number of iterations with UP/DOWN keys
|
||||
#if BROWSER
|
||||
maxIterations = 43;
|
||||
maxIterationsMultiplier = 22.0f;
|
||||
#else
|
||||
maxIterations = 333;
|
||||
maxIterationsMultiplier = 166.5f;
|
||||
#endif
|
||||
|
||||
// Get variable (uniform) locations on the shader to connect with the program
|
||||
// NOTE: If uniform variable could not be found in the shader, function returns -1
|
||||
zoomLoc = GetShaderLocation(shader, "zoom");
|
||||
offsetLoc = GetShaderLocation(shader, "offset");
|
||||
maxIterationsLoc = GetShaderLocation(shader, "maxIterations");
|
||||
|
||||
// Upload the shader uniform values!
|
||||
Raylib.SetShaderValue(shader, zoomLoc, zoom, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, offsetLoc, offset, ShaderUniformDataType.Vec2);
|
||||
Raylib.SetShaderValue(shader, maxIterationsLoc, maxIterations, ShaderUniformDataType.Int);
|
||||
|
||||
showControls = true; // Show controls
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var updateShader = false;
|
||||
|
||||
// Press [1 - 6] to reset c to a point of interest
|
||||
if (IsKeyPressed(KeyboardKey.One) ||
|
||||
IsKeyPressed(KeyboardKey.Two) ||
|
||||
IsKeyPressed(KeyboardKey.Three) ||
|
||||
IsKeyPressed(KeyboardKey.Four) ||
|
||||
IsKeyPressed(KeyboardKey.Five) ||
|
||||
IsKeyPressed(KeyboardKey.Six))
|
||||
{
|
||||
var interestIndex = 0;
|
||||
if (IsKeyPressed(KeyboardKey.One)) interestIndex = 0;
|
||||
else if (IsKeyPressed(KeyboardKey.Two)) interestIndex = 1;
|
||||
else if (IsKeyPressed(KeyboardKey.Three)) interestIndex = 2;
|
||||
else if (IsKeyPressed(KeyboardKey.Four)) interestIndex = 3;
|
||||
else if (IsKeyPressed(KeyboardKey.Five)) interestIndex = 4;
|
||||
else if (IsKeyPressed(KeyboardKey.Six)) interestIndex = 5;
|
||||
|
||||
offset[0] = pointsOfInterest[interestIndex][0];
|
||||
offset[1] = pointsOfInterest[interestIndex][1];
|
||||
zoom = pointsOfInterest[interestIndex][2];
|
||||
updateShader = true;
|
||||
}
|
||||
|
||||
// If "R" is pressed, reset zoom and offset
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
offset[0] = startingOffset[0];
|
||||
offset[1] = startingOffset[1];
|
||||
zoom = startingZoom;
|
||||
updateShader = true;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.F1)) showControls = !showControls; // Toggle whether or not to show controls
|
||||
|
||||
// Change number of max iterations with UP and DOWN keys
|
||||
// WARNING: Increasing the number of max iterations greatly impacts performance
|
||||
if (IsKeyPressed(KeyboardKey.Up))
|
||||
{
|
||||
maxIterationsMultiplier *= 1.4f;
|
||||
updateShader = true;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Down))
|
||||
{
|
||||
maxIterationsMultiplier /= 1.4f;
|
||||
updateShader = true;
|
||||
}
|
||||
|
||||
// If either left or right button is pressed, zoom in/out
|
||||
if (IsMouseButtonDown(MouseButton.Left) || IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
// Change zoom. If Mouse left -> zoom in. Mouse right -> zoom out
|
||||
zoom *= IsMouseButtonDown(MouseButton.Left) ? zoomSpeed : (1.0f / zoomSpeed);
|
||||
|
||||
var mousePos = GetMousePosition();
|
||||
Vector2 offsetVelocity;
|
||||
// Find the velocity at which to change the camera. Take the distance of the mouse
|
||||
// From the center of the screen as the direction, and adjust magnitude based on the current zoom
|
||||
offsetVelocity.X = (mousePos.X / (float)screenWidth - 0.5f) * offsetSpeedMul / zoom;
|
||||
offsetVelocity.Y = (mousePos.Y / (float)screenHeight - 0.5f) * offsetSpeedMul / zoom;
|
||||
|
||||
// Apply move velocity to camera
|
||||
offset[0] += GetFrameTime() * offsetVelocity.X;
|
||||
offset[1] += GetFrameTime() * offsetVelocity.Y;
|
||||
|
||||
updateShader = true;
|
||||
}
|
||||
|
||||
// In case a parameter has been changed, update the shader values
|
||||
if (updateShader)
|
||||
{
|
||||
// As we zoom in, increase the number of max iterations to get more detail
|
||||
// Aproximate formula, but it works-ish
|
||||
maxIterations = (int)(MathF.Sqrt(2.0f * MathF.Sqrt(MathF.Abs(1.0f - MathF.Sqrt(37.5f * zoom)))) * maxIterationsMultiplier);
|
||||
|
||||
// Update the shader uniform values!
|
||||
Raylib.SetShaderValue(shader, zoomLoc, zoom, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, offsetLoc, offset, ShaderUniformDataType.Vec2);
|
||||
Raylib.SetShaderValue(shader, maxIterationsLoc, maxIterations, ShaderUniformDataType.Int);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Using a render texture to draw Mandelbrot set
|
||||
BeginTextureMode(target); // Enable drawing to texture
|
||||
ClearBackground(Color.Black); // Clear the render texture
|
||||
|
||||
// Draw a rectangle in shader mode to be used as shader canvas
|
||||
// NOTE: Rectangle uses font white character texture coordinates,
|
||||
// So shader can not be applied here directly because input vertexTexCoord
|
||||
// Do not represent full screen coordinates (space where want to apply shader)
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Black);
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black); // Clear screen background
|
||||
|
||||
// Draw the saved texture and rendered mandelbrot set with shader
|
||||
// NOTE: We do not invert texture on Y, already considered inside shader
|
||||
BeginShaderMode(shader);
|
||||
// WARNING: If FLAG_WINDOW_HIGHDPI is enabled, HighDPI monitor scaling should be considered
|
||||
// When rendering the RenderTexture2D to fit in the HighDPI scaled Window
|
||||
DrawTextureEx(target.Texture, new Vector2(0.0f, 0.0f), 0.0f, 1.0f, Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
if (showControls)
|
||||
{
|
||||
DrawText("Press Mouse buttons right/left to zoom in/out and move", 10, 15, 10, Color.RayWhite);
|
||||
DrawText("Press F1 to toggle these controls", 10, 30, 10, Color.RayWhite);
|
||||
DrawText("Press [1 - 6] to change point of interest", 10, 45, 10, Color.RayWhite);
|
||||
DrawText("Press UP | DOWN to change number of iterations", 10, 60, 10, Color.RayWhite);
|
||||
DrawText("Press R to recenter the camera", 10, 75, 10, Color.RayWhite);
|
||||
}
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader); // Unload shader
|
||||
UnloadRenderTexture(target); // Unload render texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - mandelbrot set");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MandelbrotSet();
|
||||
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,112 +1,97 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - rlgl module usage for instanced meshes
|
||||
* raylib [shaders] example - mesh instancing
|
||||
*
|
||||
* This example uses [rlgl] module funtionality (pseudo-OpenGL 1.1 style coding)
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* This example has been created using raylib 3.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example originally created with raylib 3.7, last time updated with raylib 4.2
|
||||
*
|
||||
* Example contributed by @seanpringle and reviewed by Ramon Santamaria (@raysan5)
|
||||
* Example contributed by seanpringle (@seanpringle) and reviewed by Max (@moliad) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2020 @seanpringle
|
||||
* 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) 2020-2025 seanpringle (@seanpringle), Max (@moliad) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using Examples.Shared;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class MeshInstancing
|
||||
public class MeshInstancing : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
private const int MaxInstances = 10000;
|
||||
|
||||
public string Name => "Shaders / Mesh Instancing";
|
||||
|
||||
public string Title => "raylib [shaders] example - mesh instancing";
|
||||
|
||||
private Camera3D camera;
|
||||
private Mesh cube;
|
||||
private Matrix4x4[] transforms;
|
||||
private Shader shader;
|
||||
private Material matInstances;
|
||||
private Material matDefault;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
const int fps = 60;
|
||||
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - rlgl mesh instanced");
|
||||
|
||||
// Speed of jump animation
|
||||
int speed = 30;
|
||||
// Count of separate groups jumping around
|
||||
int groups = 2;
|
||||
// Maximum amplitude of jump
|
||||
float amp = 10;
|
||||
// Global variance in jump height
|
||||
float variance = 0.8f;
|
||||
// Individual cube's computed loop timer
|
||||
float loop = 0.0f;
|
||||
|
||||
// Used for various 3D coordinate & vector ops
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(-125.0f, 125.0f, -125.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(-125.0f, 125.0f, -125.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
|
||||
|
||||
// Number of instances to display
|
||||
const int instances = 10000;
|
||||
Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f);
|
||||
// Define mesh to be instanced
|
||||
cube = GenMeshCube(1.0f, 1.0f, 1.0f);
|
||||
|
||||
// Rotation state of instances
|
||||
Matrix4x4[] rotations = new Matrix4x4[instances];
|
||||
// Per-frame rotation animation of instances
|
||||
Matrix4x4[] rotationsInc = new Matrix4x4[instances];
|
||||
// Locations of instances
|
||||
Matrix4x4[] translations = new Matrix4x4[instances];
|
||||
// Define transforms to be uploaded to GPU for instances
|
||||
transforms = new Matrix4x4[MaxInstances]; // Pre-multiplied transformations passed to rlgl
|
||||
|
||||
// Scatter random cubes around
|
||||
for (int i = 0; i < instances; i++)
|
||||
// Translate and rotate cubes randomly
|
||||
for (var i = 0; i < MaxInstances; i++)
|
||||
{
|
||||
x = GetRandomValue(-50, 50);
|
||||
y = GetRandomValue(-50, 50);
|
||||
z = GetRandomValue(-50, 50);
|
||||
translations[i] = Matrix4x4.CreateTranslation(x, y, z);
|
||||
|
||||
x = GetRandomValue(0, 360);
|
||||
y = GetRandomValue(0, 360);
|
||||
z = GetRandomValue(0, 360);
|
||||
Vector3 axis = Vector3.Normalize(new Vector3(x, y, z));
|
||||
float angle = (float)GetRandomValue(0, 10) * DEG2RAD;
|
||||
|
||||
rotationsInc[i] = Matrix4x4.CreateFromAxisAngle(axis, angle);
|
||||
rotations[i] = Matrix4x4.Identity;
|
||||
}
|
||||
|
||||
// Pre-multiplied transformations passed to rlgl
|
||||
Matrix4x4[] transforms = new Matrix4x4[instances];
|
||||
Shader shader = LoadShader(
|
||||
"resources/shaders/glsl330/lighting_instancing.vs",
|
||||
"resources/shaders/glsl330/lighting.fs"
|
||||
);
|
||||
|
||||
// Get some shader loactions
|
||||
unsafe
|
||||
{
|
||||
int* locs = (int*)shader.Locs;
|
||||
locs[(int)ShaderLocationIndex.MatrixMvp] = GetShaderLocation(shader, "mvp");
|
||||
locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(shader, "viewPos");
|
||||
locs[(int)ShaderLocationIndex.MatrixModel] = GetShaderLocationAttrib(
|
||||
shader,
|
||||
"instanceTransform"
|
||||
var translation = Matrix4x4.CreateTranslation(
|
||||
GetRandomValue(-50, 50),
|
||||
GetRandomValue(-50, 50),
|
||||
GetRandomValue(-50, 50)
|
||||
);
|
||||
var axis = Vector3.Normalize(new Vector3(
|
||||
GetRandomValue(0, 360),
|
||||
GetRandomValue(0, 360),
|
||||
GetRandomValue(0, 360)
|
||||
));
|
||||
var angle = GetRandomValue(0, 180) * DEG2RAD;
|
||||
var rotation = Matrix4x4.CreateFromAxisAngle(axis, angle);
|
||||
|
||||
transforms[i] = Matrix4x4.Transpose(Matrix4x4.Multiply(rotation, translation));
|
||||
}
|
||||
|
||||
// Ambient light level
|
||||
int ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
// Load lighting shader
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/lighting_instancing.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/lighting.fs"
|
||||
);
|
||||
// Get shader locations
|
||||
shader.Locs[(int)ShaderLocationIndex.MatrixMvp] = GetShaderLocation(shader, "mvp");
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(shader, "viewPos");
|
||||
|
||||
// Set shader value: ambient light level
|
||||
var ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
ambientLoc,
|
||||
|
|
@ -114,211 +99,105 @@ public class MeshInstancing
|
|||
ShaderUniformDataType.Vec4
|
||||
);
|
||||
|
||||
// Create one light
|
||||
Rlights.CreateLight(
|
||||
0,
|
||||
LightType.Directorional,
|
||||
new Vector3(50, 50, 0),
|
||||
new Vector3(50.0f, 50.0f, 0.0f),
|
||||
Vector3.Zero,
|
||||
Color.White,
|
||||
shader
|
||||
);
|
||||
|
||||
Material material = LoadMaterialDefault();
|
||||
material.Shader = shader;
|
||||
unsafe
|
||||
{
|
||||
material.Maps[(int)MaterialMapIndex.Diffuse].Color = Color.Red;
|
||||
}
|
||||
// NOTE: We are assigning the intancing shader to material.shader
|
||||
// to be used on mesh drawing with DrawMeshInstanced()
|
||||
matInstances = LoadMaterialDefault();
|
||||
matInstances.Shader = shader;
|
||||
matInstances.Maps[(int)MaterialMapIndex.Diffuse].Color = Color.Red;
|
||||
|
||||
int textPositionY = 300;
|
||||
// Load default material (using raylib intenral default shader) for non-instanced mesh drawing
|
||||
// WARNING: Default shader enables vertex color attribute BUT GenMeshCube() does not generate vertex colors, so,
|
||||
// when drawing the color attribute is disabled and a default color value is provided as input for thevertex attribute
|
||||
matDefault = LoadMaterialDefault();
|
||||
matDefault.Maps[(int)MaterialMapIndex.Diffuse].Color = Color.Blue;
|
||||
}
|
||||
|
||||
// Simple frames counter to manage animation
|
||||
int framesCounter = 0;
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
SetTargetFPS(fps);
|
||||
// Update the light shader with the camera view position
|
||||
float[] cameraPos = { camera.Position.X, camera.Position.Y, camera.Position.Z };
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
cameraPos,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw cube mesh with default material (BLUE)
|
||||
DrawMesh(cube, matDefault, Matrix4x4.Transpose(Matrix4x4.CreateTranslation(-10.0f, 0.0f, 0.0f)));
|
||||
|
||||
// Draw meshes instanced using material containing instancing shader (RED + lighting),
|
||||
// transforms[] for the instances should be provided, they are dynamically
|
||||
// updated in GPU every frame, so we can animate the different mesh instances
|
||||
DrawMeshInstanced(cube, matInstances, transforms, MaxInstances);
|
||||
|
||||
// Draw cube mesh with default material (BLUE)
|
||||
DrawMesh(cube, matDefault, Matrix4x4.Transpose(Matrix4x4.CreateTranslation(10.0f, 0.0f, 0.0f)));
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// Detach shader so UnloadMaterial does not also unload it, then free everything.
|
||||
matInstances.Shader = new();
|
||||
UnloadMaterial(matInstances);
|
||||
UnloadMaterial(matDefault);
|
||||
UnloadMesh(cube);
|
||||
UnloadShader(shader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - mesh instancing");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MeshInstancing();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
|
||||
textPositionY = 300;
|
||||
framesCounter += 1;
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
amp += 0.5f;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
amp = (amp <= 1) ? 1.0f : (amp - 1.0f);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
variance = (variance <= 0.0f) ? 0.0f : (variance - 0.01f);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
variance = (variance >= 1.0f) ? 1.0f : (variance + 0.01f);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.One))
|
||||
{
|
||||
groups = 1;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Two))
|
||||
{
|
||||
groups = 2;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Three))
|
||||
{
|
||||
groups = 3;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Four))
|
||||
{
|
||||
groups = 4;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Five))
|
||||
{
|
||||
groups = 5;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Six))
|
||||
{
|
||||
groups = 6;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Seven))
|
||||
{
|
||||
groups = 7;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Eight))
|
||||
{
|
||||
groups = 8;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Nine))
|
||||
{
|
||||
groups = 9;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.W))
|
||||
{
|
||||
groups = 7;
|
||||
amp = 25;
|
||||
speed = 18;
|
||||
variance = 0.70f;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Equal))
|
||||
{
|
||||
speed = (speed <= (int)(fps * 0.25f)) ? (int)(fps * 0.25f) : (int)(speed * 0.95f);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.KpAdd))
|
||||
{
|
||||
speed = (speed <= (int)(fps * 0.25f)) ? (int)(fps * 0.25f) : (int)(speed * 0.95f);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Minus))
|
||||
{
|
||||
speed = (int)MathF.Max(speed * 1.02f, speed + 1);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.KpSubtract))
|
||||
{
|
||||
speed = (int)MathF.Max(speed * 1.02f, speed + 1);
|
||||
}
|
||||
|
||||
// Update the light shader with the camera view position
|
||||
float[] cameraPos = { camera.Position.X, camera.Position.Y, camera.Position.Z };
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
(int)ShaderLocationIndex.VectorView,
|
||||
cameraPos,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
// Apply per-instance transformations
|
||||
for (int i = 0; i < instances; i++)
|
||||
{
|
||||
rotations[i] = Matrix4x4.Multiply(rotations[i], rotationsInc[i]);
|
||||
transforms[i] = Matrix4x4.Multiply(rotations[i], translations[i]);
|
||||
|
||||
// Get the animation cycle's framesCounter for this instance
|
||||
loop = (float)((framesCounter + (int)(((float)(i % groups) / groups) * speed)) % speed) / speed;
|
||||
|
||||
// Calculate the y according to loop cycle
|
||||
y = (MathF.Sin(loop * MathF.PI * 2)) * amp * ((1 - variance) + (variance * (float)(i % (groups * 10)) / (groups * 10)));
|
||||
|
||||
// Clamp to floor
|
||||
y = (y < 0) ? 0.0f : y;
|
||||
|
||||
transforms[i] = Matrix4x4.Multiply(transforms[i], Matrix4x4.CreateTranslation(0.0f, y, 0.0f));
|
||||
transforms[i] = Matrix4x4.Transpose(transforms[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawMeshInstanced(cube, material, transforms, instances);
|
||||
EndMode3D();
|
||||
|
||||
DrawText("A CUBE OF DANCING CUBES!", 490, 10, 20, Color.Maroon);
|
||||
DrawText("PRESS KEYS:", 10, textPositionY, 20, Color.Black);
|
||||
|
||||
DrawText("1 - 9", 10, textPositionY += 25, 10, Color.Black);
|
||||
DrawText(": Number of groups", 50, textPositionY, 10, Color.Black);
|
||||
DrawText($": {groups}", 160, textPositionY, 10, Color.Black);
|
||||
|
||||
DrawText("UP", 10, textPositionY += 15, 10, Color.Black);
|
||||
DrawText(": increase amplitude", 50, textPositionY, 10, Color.Black);
|
||||
DrawText($": {amp}%.2f", 160, textPositionY, 10, Color.Black);
|
||||
|
||||
DrawText("DOWN", 10, textPositionY += 15, 10, Color.Black);
|
||||
DrawText(": decrease amplitude", 50, textPositionY, 10, Color.Black);
|
||||
|
||||
DrawText("LEFT", 10, textPositionY += 15, 10, Color.Black);
|
||||
DrawText(": decrease variance", 50, textPositionY, 10, Color.Black);
|
||||
DrawText($": {variance}.2f", 160, textPositionY, 10, Color.Black);
|
||||
|
||||
DrawText("RIGHT", 10, textPositionY += 15, 10, Color.Black);
|
||||
DrawText(": increase variance", 50, textPositionY, 10, Color.Black);
|
||||
|
||||
DrawText("+/=", 10, textPositionY += 15, 10, Color.Black);
|
||||
DrawText(": increase speed", 50, textPositionY, 10, Color.Black);
|
||||
DrawText($": {speed} = {((float)fps / speed)} loops/sec", 160, textPositionY, 10, Color.Black);
|
||||
|
||||
DrawText("-", 10, textPositionY += 15, 10, Color.Black);
|
||||
DrawText(": decrease speed", 50, textPositionY, 10, Color.Black);
|
||||
|
||||
DrawText("W", 10, textPositionY += 15, 10, Color.Black);
|
||||
DrawText(": Wild setup!", 50, textPositionY, 10, Color.Black);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - Apply a shader to a 3d model
|
||||
* raylib [shaders] example - model shader
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3), to test this example
|
||||
* on OpenGL ES 2.0 platforms (Android, Raspberry Pi, HTML5), use #version 100 shaders
|
||||
* raylib comes with shaders ready for both versions, check raylib/shaders install folder
|
||||
*
|
||||
* 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 originally created with raylib 1.3, last time updated with raylib 3.7
|
||||
*
|
||||
* Copyright (c) 2014 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) 2014-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -21,86 +25,122 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class ModelShader
|
||||
public class ModelShader : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Model Shader";
|
||||
|
||||
public string Title => "raylib [shaders] example - model shader";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private Shader shader;
|
||||
private Vector3 position;
|
||||
|
||||
public 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, -1.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
|
||||
|
||||
model = LoadModel("resources/models/obj/watermill.obj"); // Load OBJ model
|
||||
texture = LoadTexture("resources/models/obj/watermill_diffuse.png"); // Load model texture
|
||||
|
||||
// Load shader for model
|
||||
// NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/grayscale.fs");
|
||||
|
||||
Raylib.SetMaterialShader(ref model, 0, ref shader); // Set shader effect to 3d model
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture); // Bind texture to model
|
||||
|
||||
position = new(0.0f, 0.0f, 0.0f); // Set model position
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 0.2f, Color.White); // Draw 3d model with texture
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText(
|
||||
"(c) Watermill 3D model by Alberto Cano",
|
||||
screenWidth - 210,
|
||||
screenHeight - 20,
|
||||
10,
|
||||
Color.Gray
|
||||
);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader); // Unload shader
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - model shader");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(4.0f, 4.0f, 4.0f);
|
||||
camera.Target = new Vector3(0.0f, 1.0f, -1.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
Model model = LoadModel("resources/models/obj/watermill.obj");
|
||||
Texture2D texture = LoadTexture("resources/models/obj/watermill_diffuse.png");
|
||||
Shader shader = LoadShader("resources/shaders/glsl330/base.vs",
|
||||
"resources/shaders/glsl330/grayscale.fs");
|
||||
|
||||
Raylib.SetMaterialShader(ref model, 0, ref shader);
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
SetTargetFPS(60);
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ModelShader();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 0.2f, Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText(
|
||||
"(c) Watermill 3D model by Alberto Cano",
|
||||
screenWidth - 210,
|
||||
screenHeight - 20,
|
||||
10,
|
||||
Color.Gray
|
||||
);
|
||||
|
||||
DrawText($"Camera3D position: ({camera.Position})", 600, 20, 10, Color.Black);
|
||||
DrawText($"Camera3D target: ({camera.Position})", 600, 40, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadShader(shader);
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - Multiple sample2D with default batch system
|
||||
* raylib [shaders] example - multi sample2d
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3), to test this example
|
||||
* on OpenGL ES 2.0 platforms (Android, Raspberry Pi, HTML5), use #version 100 shaders
|
||||
* raylib comes with shaders ready for both versions, check raylib/shaders install folder
|
||||
*
|
||||
* This example has been created using raylib 3.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example originally created with raylib 3.5, last time updated with raylib 3.5
|
||||
*
|
||||
* Copyright (c) 2020 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) 2020-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -20,94 +24,129 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class MultiSample2d
|
||||
public class MultiSample2d : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Multi Sample 2D";
|
||||
|
||||
public string Title => "raylib [shaders] example - multi sample2d";
|
||||
|
||||
private Texture2D texRed;
|
||||
private Texture2D texBlue;
|
||||
private Shader shader;
|
||||
private int texBlueLoc;
|
||||
private int dividerLoc;
|
||||
private float dividerValue;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
var imRed = GenImageColor(800, 450, new Color(255, 0, 0, 255));
|
||||
texRed = LoadTextureFromImage(imRed);
|
||||
UnloadImage(imRed);
|
||||
|
||||
var imBlue = GenImageColor(800, 450, new Color(0, 0, 255, 255));
|
||||
texBlue = LoadTextureFromImage(imBlue);
|
||||
UnloadImage(imBlue);
|
||||
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/color_mix.fs");
|
||||
|
||||
// Get an additional sampler2D location to be enabled on drawing
|
||||
texBlueLoc = GetShaderLocation(shader, "texture1");
|
||||
|
||||
// Get shader uniform for divider
|
||||
dividerLoc = GetShaderLocation(shader, "divider");
|
||||
dividerValue = 0.5f;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
dividerValue += 0.01f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
dividerValue -= 0.01f;
|
||||
}
|
||||
|
||||
if (dividerValue < 0.0f)
|
||||
{
|
||||
dividerValue = 0.0f;
|
||||
}
|
||||
else if (dividerValue > 1.0f)
|
||||
{
|
||||
dividerValue = 1.0f;
|
||||
}
|
||||
|
||||
Raylib.SetShaderValue(shader, dividerLoc, dividerValue, ShaderUniformDataType.Float);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginShaderMode(shader);
|
||||
|
||||
// WARNING: Additional textures (sampler2D) are enabled for ALL draw calls in the batch,
|
||||
// but EndShaderMode() forces batch drawing and resets active textures, this way
|
||||
// other textures (sampler2D) can be activated on consequent drawings (if required)
|
||||
// The downside of this approach is that SetShaderValue() must be called inside the loop,
|
||||
// to be set again after every EndShaderMode() reset
|
||||
SetShaderValueTexture(shader, texBlueLoc, texBlue);
|
||||
|
||||
// We are drawing texRed using default [sampler2D texture0] but
|
||||
// an additional texture units is enabled for texBlue [sampler2D texture1]
|
||||
DrawTexture(texRed, 0, 0, Color.White);
|
||||
|
||||
EndShaderMode(); // Texture sampler2D is reseted, needs to be set again for next frame
|
||||
|
||||
var y = GetScreenHeight() - 40;
|
||||
DrawText("Use KEY_LEFT/KEY_RIGHT to move texture mixing in shader!", 80, y, 20, Color.RayWhite);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader);
|
||||
UnloadTexture(texRed);
|
||||
UnloadTexture(texBlue);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib - multiple sample2D");
|
||||
|
||||
Image imRed = GenImageColor(800, 450, new Color(255, 0, 0, 255));
|
||||
Texture2D texRed = LoadTextureFromImage(imRed);
|
||||
UnloadImage(imRed);
|
||||
|
||||
Image imBlue = GenImageColor(800, 450, new Color(0, 0, 255, 255));
|
||||
Texture2D texBlue = LoadTextureFromImage(imBlue);
|
||||
UnloadImage(imBlue);
|
||||
|
||||
Shader shader = LoadShader(null, "resources/shaders/glsl330/color_mix.fs");
|
||||
|
||||
// Get an additional sampler2D location to be enabled on drawing
|
||||
int texBlueLoc = GetShaderLocation(shader, "texture1");
|
||||
|
||||
// Get shader uniform for divider
|
||||
int dividerLoc = GetShaderLocation(shader, "divider");
|
||||
float dividerValue = 0.5f;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - multi sample2d");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MultiSample2d();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
dividerValue += 0.01f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
dividerValue -= 0.01f;
|
||||
}
|
||||
|
||||
if (dividerValue < 0.0f)
|
||||
{
|
||||
dividerValue = 0.0f;
|
||||
}
|
||||
else if (dividerValue > 1.0f)
|
||||
{
|
||||
dividerValue = 1.0f;
|
||||
}
|
||||
|
||||
Raylib.SetShaderValue(shader, dividerLoc, dividerValue, ShaderUniformDataType.Float);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginShaderMode(shader);
|
||||
|
||||
// WARNING: Additional samplers are enabled for all draw calls in the batch,
|
||||
// EndShaderMode() forces batch drawing and consequently resets active textures
|
||||
// to let other sampler2D to be activated on consequent drawings (if required)
|
||||
SetShaderValueTexture(shader, texBlueLoc, texBlue);
|
||||
|
||||
// We are drawing texRed using default sampler2D texture0 but
|
||||
// an additional texture units is enabled for texBlue (sampler2D texture1)
|
||||
DrawTexture(texRed, 0, 0, Color.White);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
int y = GetScreenHeight() - 40;
|
||||
DrawText("Use KEY_LEFT/KEY_RIGHT to move texture mixing in shader!", 80, y, 20, Color.RayWhite);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadShader(shader);
|
||||
UnloadTexture(texRed);
|
||||
UnloadTexture(texBlue);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
233
Examples/Shaders/NormalmapRendering.cs
Normal file
233
Examples/Shaders/NormalmapRendering.cs
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - normalmap rendering
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jeremy Montgomery (@Sir_Irk) 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 Jeremy Montgomery (@Sir_Irk) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class NormalmapRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Normalmap Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - normalmap rendering";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Shader shader;
|
||||
private Model plane;
|
||||
private Vector3 lightPosition;
|
||||
private int lightPosLoc;
|
||||
private float specularExponent;
|
||||
private int specularExponentLoc;
|
||||
private int useNormalMap;
|
||||
private int useNormalMapLoc;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 2.0f, -4.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 basic normal map lighting shader
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/normalmap.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/normalmap.fs"
|
||||
);
|
||||
|
||||
// Get some required shader locations
|
||||
shader.Locs[(int)ShaderLocationIndex.MapNormal] = GetShaderLocation(shader, "normalMap");
|
||||
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");
|
||||
|
||||
// This example uses just 1 point light
|
||||
lightPosition = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
lightPosLoc = GetShaderLocation(shader, "lightPos");
|
||||
|
||||
// Load a plane model that has proper normals and tangents
|
||||
plane = LoadModel("resources/models/plane.glb");
|
||||
|
||||
// Set the plane model's shader and texture maps
|
||||
plane.Materials[0].Shader = shader;
|
||||
plane.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = LoadTexture("resources/tiles_diffuse.png");
|
||||
plane.Materials[0].Maps[(int)MaterialMapIndex.Normal].Texture = LoadTexture("resources/tiles_normal.png");
|
||||
|
||||
// Generate Mipmaps and use TRILINEAR filtering to help with texture aliasing
|
||||
GenTextureMipmaps(ref plane.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture);
|
||||
GenTextureMipmaps(ref plane.Materials[0].Maps[(int)MaterialMapIndex.Normal].Texture);
|
||||
|
||||
SetTextureFilter(plane.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture, TextureFilter.Trilinear);
|
||||
SetTextureFilter(plane.Materials[0].Maps[(int)MaterialMapIndex.Normal].Texture, TextureFilter.Trilinear);
|
||||
|
||||
// Specular exponent AKA shininess of the material
|
||||
specularExponent = 8.0f;
|
||||
specularExponentLoc = GetShaderLocation(shader, "specularExponent");
|
||||
|
||||
// Allow toggling the normal map on and off for comparison purposes
|
||||
useNormalMap = 1;
|
||||
useNormalMapLoc = GetShaderLocation(shader, "useNormalMap");
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Move the light around on the X and Z axis using WASD keys
|
||||
Vector3 direction = new(0.0f, 0.0f, 0.0f);
|
||||
if (IsKeyDown(KeyboardKey.W))
|
||||
{
|
||||
direction = Vector3Add(direction, new Vector3(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
direction = Vector3Add(direction, new Vector3(0.0f, 0.0f, -1.0f));
|
||||
}
|
||||
if (IsKeyDown(KeyboardKey.D))
|
||||
{
|
||||
direction = Vector3Add(direction, new Vector3(-1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
direction = Vector3Add(direction, new Vector3(1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
direction = Vector3Normalize(direction);
|
||||
lightPosition = Vector3Add(lightPosition, Vector3Scale(direction, GetFrameTime() * 3.0f));
|
||||
|
||||
// Increase/Decrease the specular exponent(shininess)
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
specularExponent = Clamp(specularExponent + 40.0f * GetFrameTime(), 2.0f, 128.0f);
|
||||
}
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
specularExponent = Clamp(specularExponent - 40.0f * GetFrameTime(), 2.0f, 128.0f);
|
||||
}
|
||||
|
||||
// Toggle normal map on and off
|
||||
if (IsKeyPressed(KeyboardKey.N))
|
||||
{
|
||||
useNormalMap = (useNormalMap != 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
// Spin plane model at a constant rate
|
||||
plane.Transform = MatrixRotateY((float)GetTime() * 0.5f);
|
||||
|
||||
// Update shader values
|
||||
Raylib.SetShaderValue(shader, lightPosLoc, lightPosition, ShaderUniformDataType.Vec3);
|
||||
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
Raylib.SetShaderValue(shader, specularExponentLoc, specularExponent, ShaderUniformDataType.Float);
|
||||
|
||||
Raylib.SetShaderValue(shader, useNormalMapLoc, useNormalMap, ShaderUniformDataType.Int);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
BeginShaderMode(shader);
|
||||
|
||||
DrawModel(plane, Vector3.Zero, 2.0f, Color.White);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
// Draw sphere to show light position
|
||||
DrawSphereWires(lightPosition, 0.2f, 8, 8, Color.Orange);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
Color textColor = (useNormalMap != 0) ? Color.DarkGreen : Color.Red;
|
||||
string toggleStr = (useNormalMap != 0) ? "On" : "Off";
|
||||
DrawText($"Use key [N] to toggle normal map: {toggleStr}", 10, 10, 10, textColor);
|
||||
|
||||
int yOffset = 24;
|
||||
DrawText("Use keys [W][A][S][D] to move the light", 10, 10 + yOffset * 1, 10, Color.Black);
|
||||
DrawText("Use keys [Up][Down] to change specular exponent", 10, 10 + yOffset * 2, 10, Color.Black);
|
||||
DrawText($"Specular Exponent: {specularExponent:F2}", 10, 10 + yOffset * 3, 10, Color.Blue);
|
||||
|
||||
DrawFPS(screenWidth - 90, 10);
|
||||
|
||||
EndDrawing();
|
||||
//--------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader);
|
||||
UnloadModel(plane);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - normalmap rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new NormalmapRendering();
|
||||
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;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue