Watch
2
0
Fork
You've already forked raylib-cs
0

WASM examples (+ backports of new official examples) (#344)

* chg: New build system that uses the officially distributed binaries, bumped version to 8.0.0, simplified git workflow, removed deprecated OpenGL 1.1 functionality.

* chg: Modernize CI workflow, enable SourceLink

- Bump workflow actions to latest majors (Node 24); drop deprecated softprops/action-gh-release@v1
- Trigger push builds on main instead of master
- Create local nuget feed dir before pack (fixes NU1301)
- Enable Microsoft.SourceLink.GitHub for debugging symbols (ref PR #340)

* fix: centralized version data in Directory.build.props, and fixed various interop details that had incorrect function signatures

* chore: updated readme

* fix: version the native extract marker and chain download via DependsOnTargets

The .extracted marker now includes the raylib package name, so bumping
TargetRaylibTag re-extracts the new archive instead of silently keeping
(and packing/copying) the previous version's files.

_PrepareNativeLibrary and _StageWasmNative now depend directly on
_DownloadAndExtractInternal instead of CallTarget-ing it; dependency
targets run in the same project instance, so the resolved properties
(RaylibPackageName etc.) propagate naturally.

* fix: let the binding build for browser-wasm on both net8.0 and net10.0

The net8-era wasm workload (Microsoft.NET.Runtime.WebAssembly.Sdk 8.0.x,
auto-imported for RID browser-wasm) treats every browser-wasm project as
a wasm app: it forces OutputType=Exe after project evaluation (CS5001
for a classlib) and hooks its app-bundle build after Build, which errors
because a library has no assemblies to bundle. Opt Raylib-cs out via
DisableAutoWasmBuildApp (props time, before the workload defaults its
trigger) and pin OutputType back to Library in Directory.Build.targets
(evaluated after the workload props, so the assignment wins). net10's
wasm SDK needs neither workaround.

* chore: readme updated

* chg: simplifying build logic - a simple line in the documentation should save us the code here

* fix: Wrong signature of FrameBufferComplete

* chore: readme update

* feat: samples default to local project reference, and can optionally use the nuget package

* feat: backporting existing raylib-cs examples and new official raylib examples to WASM, adopting raylib's original code style

* chore: readme, gitignore, and targets backport.

* fix: Examples.csproj runs the download task when building locally

* feat: backporting existing raylib-cs examples and new official raylib examples to WASM, adopting raylib's original code style

* chore: readme, gitignore, and targets backport.

* chore: clean up linter warnings

* feat: html harness focuses the example and allows quick navigation with J/K instead.

* chore: readme mentions the property to use nuget vs. the local project reference

* feat: replaced the J/K navigation with good old HTML buttons

* chore: run dotnet format scoped default (was previously scoped to just 'style')
This commit is contained in:
tiger tiger tiger 2026-07-30 19:34:34 +02:00 committed by GitHub
commit 8c22e68c2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
236 changed files with 40405 additions and 10896 deletions

View file

@ -0,0 +1,163 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
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;
}
}

View file

@ -2,81 +2,77 @@
*
* 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)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
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 +105,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;

View file

@ -1,53 +1,72 @@
/*******************************************************************************************
*
* 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;
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 +94,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 +125,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 +134,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 +145,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 +188,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 +308,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 +342,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);

View file

@ -0,0 +1,249 @@
/*******************************************************************************************
*
* 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 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;
}
}

View file

@ -0,0 +1,194 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
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;
}
}

View file

@ -1,143 +1,177 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System.Numerics;
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;

View file

@ -0,0 +1,434 @@
/*******************************************************************************************
*
* 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 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;
}
}

View file

@ -0,0 +1,223 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
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;
}
}

View file

@ -1,100 +1,125 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System.Numerics;
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();
//--------------------------------------------------------------------------------------

View file

@ -1,52 +1,60 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
using static Raylib_cs.Raymath;
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 +62,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 +73,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 +89,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 +104,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();
//--------------------------------------------------------------------------------------

View file

@ -0,0 +1,484 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
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;
}
}

View file

@ -1,135 +1,185 @@
/*******************************************************************************************
*
* 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.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();
//--------------------------------------------------------------------------------------

View file

@ -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,53 +11,60 @@
* 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)
*
********************************************************************************************/
using System;
using System.Numerics;
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 +72,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 +232,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");
}

View file

@ -1,32 +1,48 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System.Numerics;
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 +51,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 +90,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();
//--------------------------------------------------------------------------------------

View file

@ -0,0 +1,215 @@
/*******************************************************************************************
*
* 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 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;
}
}

View file

@ -0,0 +1,282 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
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;
}
}

View file

@ -1,112 +1,94 @@
/*******************************************************************************************
*
* 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.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 +96,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;

View file

@ -1,106 +1,143 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System.Numerics;
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;

View file

@ -1,113 +1,150 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
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();
//--------------------------------------------------------------------------------------

View file

@ -0,0 +1,231 @@
/*******************************************************************************************
*
* 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 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;
}
}

View file

@ -1,34 +1,47 @@
/*******************************************************************************************
*
* raylib [shaders] example - Color palette switch
* raylib [shaders] example - palette switch
*
* 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), 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 2.3 (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 Marco Lizza (@MarcoLizza) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 Marco Lizza (@MarcoLizza) 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 Marco Lizza (@MarcoLizza) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Shaders;
public class PaletteSwitch
public class PaletteSwitch : IExample
{
const int GlslVersion = 330;
const int ColorsPerPalette = 8;
const int VALUES_PER_COLOR = 3;
private const int screenWidth = 800;
private const int screenHeight = 450;
static int[][] Palettes = new int[][] {
#if BROWSER
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
#else
private const int GlslVersion = 330;
#endif
private const int ColorsPerPalette = 8;
private const int VALUES_PER_COLOR = 3;
public string Name => "Shaders / Palette Switch";
public string Title => "raylib [shaders] example - palette switch";
private int[][] Palettes = new int[][] {
// 3-BIT RGB
new int[] {
0, 0, 0,
@ -64,101 +77,119 @@ public class PaletteSwitch
}
};
static string[] PaletteText = new string[] {
private string[] PaletteText = new string[] {
"3-BIT RGB",
"AMMO-8 (GameBoy-like)",
"RKBV (2-strip film)"
};
private Shader shader;
private int paletteLoc;
private int currentPalette;
private int lineHeight;
public void Init()
{
// Load shader to be used on some parts drawing
// NOTE 1: Using GLSL 330 shader version, on OpenGL ES 2.0 use GLSL 100 shader version
// NOTE 2: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/palette_switch.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
paletteLoc = GetShaderLocation(shader, "palette");
currentPalette = 0;
lineHeight = screenHeight / ColorsPerPalette;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.Right))
{
currentPalette++;
}
else if (IsKeyPressed(KeyboardKey.Left))
{
currentPalette--;
}
if (currentPalette >= Palettes.Length)
{
currentPalette = 0;
}
else if (currentPalette < 0)
{
currentPalette = Palettes.Length - 1;
}
// Send palette data to the shader to be used on drawing
// NOTE: We are sending RGB triplets w/o the alpha channel
Raylib.SetShaderValueV(
shader,
paletteLoc,
Palettes[currentPalette],
ShaderUniformDataType.IVec3,
ColorsPerPalette
);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginShaderMode(shader);
for (var i = 0; i < ColorsPerPalette; i++)
{
// Draw horizontal screen-wide rectangles with increasing "palette index"
// The used palette index is encoded in the RGB components of the pixel
DrawRectangle(0, lineHeight * i, GetScreenWidth(), lineHeight, new Color(i, i, i, 255));
}
EndShaderMode();
DrawText("< >", 10, 10, 30, Color.DarkBlue);
DrawText("CURRENT PALETTE:", 60, 15, 20, Color.RayWhite);
DrawText(PaletteText[currentPalette], 300, 15, 20, Color.Red);
DrawFPS(700, 15);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadShader(shader); // Unload shader
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - palette switch");
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - color palette switch");
// Load shader to be used on some parts drawing
// NOTE 1: Using GLSL 330 shader version, on OpenGL ES 2.0 use GLSL 100 shader version
// NOTE 2: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
Shader shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/palette_switch.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 paletteLoc = GetShaderLocation(shader, "palette");
int currentPalette = 0;
int lineHeight = screenHeight / ColorsPerPalette;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new PaletteSwitch();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.Right))
{
currentPalette++;
}
else if (IsKeyPressed(KeyboardKey.Left))
{
currentPalette--;
}
if (currentPalette >= Palettes.Length)
{
currentPalette = 0;
}
else if (currentPalette < 0)
{
currentPalette = Palettes.Length - 1;
}
// Send new value to the shader to be used on drawing.
// NOTE: We are sending RGB triplets w/o the alpha channel
Raylib.SetShaderValueV(
shader,
paletteLoc,
Palettes[currentPalette],
ShaderUniformDataType.IVec3,
ColorsPerPalette
);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginShaderMode(shader);
for (int i = 0; i < ColorsPerPalette; i++)
{
// Draw horizontal screen-wide rectangles with increasing "palette index"
// The used palette index is encoded in the RGB components of the pixel
DrawRectangle(0, lineHeight * i, GetScreenWidth(), lineHeight, new Color(i, i, i, 255));
}
EndShaderMode();
DrawText("< >", 10, 10, 30, Color.DarkBlue);
DrawText("CURRENT PALETTE:", 60, 15, 20, Color.RayWhite);
DrawText(PaletteText[currentPalette], 300, 15, 20, Color.Red);
DrawFPS(700, 15);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shader);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -1,31 +1,45 @@
/*******************************************************************************************
*
* raylib [shaders] example - Apply a postprocessing shader to a scene
* raylib [shaders] example - postprocessing
*
* 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), 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)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shaders;
public class PostProcessing
public class PostProcessing : IExample
{
public const int GLSL_VERSION = 330;
private const int screenWidth = 800;
private const int screenHeight = 450;
enum PostproShader
#if BROWSER
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
#else
private const int GlslVersion = 330;
#endif
public string Name => "Shaders / Post Processing";
public string Title => "raylib [shaders] example - postprocessing";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
private enum PostproShader
{
FxGrayScale = 0,
FxPosterization,
@ -43,7 +57,7 @@ public class PostProcessing
Max
}
static string[] postproShaderText = new string[] {
private string[] postproShaderText = new string[] {
"GRAYSCALE",
"POSTERIZATION",
"DREAM_VISION",
@ -59,40 +73,39 @@ public class PostProcessing
//"FXAA"
};
public static int Main()
private Camera3D camera;
private Model model;
private Texture2D texture;
private Vector3 position;
private Shader[] shaders;
private int currentShader;
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 - postprocessing shader");
// Define the camera to look into our 3d world
Camera3D camera = new();
camera.Position = new Vector3(2.0f, 3.0f, 2.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;
camera = new();
camera.Position = new Vector3(2.0f, 3.0f, 2.0f); // Camera position
camera.Target = new Vector3(0.0f, 1.0f, 0.0f); // Camera looking at point
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
camera.FovY = 45.0f; // Camera field-of-view Y
camera.Projection = CameraProjection.Perspective; // Camera projection type
Model model = LoadModel("resources/models/obj/church.obj");
Texture2D texture = LoadTexture("resources/models/obj/church_diffuse.png");
model = LoadModel("resources/models/church.obj"); // Load OBJ model
texture = LoadTexture("resources/models/church_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 all postpro shaders
// NOTE 1: All postpro shader use the base vertex shader (DEFAULT_VERTEX_SHADER)
// NOTE 2: We load the correct shader depending on GLSL version
Shader[] shaders = new Shader[(int)PostproShader.Max];
shaders = new Shader[(int)PostproShader.Max];
// NOTE: Defining null (NULL) for vertex shader forces usage of internal default vertex shader
string shaderPath = "resources/shaders/glsl330";
var shaderPath = $"resources/shaders/glsl{GlslVersion}";
shaders[(int)PostproShader.FxGrayScale] = LoadShader(null, $"{shaderPath}/grayscale.fs");
shaders[(int)PostproShader.FxPosterization] = LoadShader(null, $"{shaderPath}/posterization.fs");
shaders[(int)PostproShader.FxDreamVision] = LoadShader(null, $"{shaderPath}/dream_vision.fs");
@ -106,99 +119,122 @@ public class PostProcessing
shaders[(int)PostproShader.FxBloom] = LoadShader(null, $"{shaderPath}/bloom.fs");
shaders[(int)PostproShader.FxBlur] = LoadShader(null, $"{shaderPath}/blur.fs");
int currentShader = (int)PostproShader.FxGrayScale;
currentShader = (int)PostproShader.FxGrayScale;
// 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);
// Main game loop
while (!WindowShouldClose())
if (IsKeyPressed(KeyboardKey.Right))
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Orbital);
if (IsKeyPressed(KeyboardKey.Right))
{
currentShader++;
}
else if (IsKeyPressed(KeyboardKey.Left))
{
currentShader--;
}
if (currentShader >= (int)PostproShader.Max)
{
currentShader = 0;
}
else if (currentShader < 0)
{
currentShader = (int)PostproShader.Max - 1;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Enable drawing to texture
BeginTextureMode(target);
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawModel(model, position, 0.1f, Color.White);
DrawGrid(10, 1.0f);
EndMode3D();
// End drawing to texture (now we have a texture available for next passes)
EndTextureMode();
// Render previously generated texture using selected postpro shader
BeginShaderMode(shaders[currentShader]);
// 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();
DrawRectangle(0, 9, 580, 30, ColorAlpha(Color.LightGray, 0.7f));
DrawText("(c) Church 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
DrawText("CURRENT POSTPRO SHADER:", 10, 15, 20, Color.Black);
DrawText(postproShaderText[currentShader], 330, 15, 20, Color.Red);
DrawText("< >", 540, 10, 30, Color.DarkBlue);
DrawFPS(700, 15);
EndDrawing();
//----------------------------------------------------------------------------------
currentShader++;
}
else if (IsKeyPressed(KeyboardKey.Left))
{
currentShader--;
}
// De-Initialization
//--------------------------------------------------------------------------------------
for (int i = 0; i < (int)PostproShader.Max; i++)
if (currentShader >= (int)PostproShader.Max)
{
currentShader = 0;
}
else if (currentShader < 0)
{
currentShader = (int)PostproShader.Max - 1;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Enable drawing to texture
BeginTextureMode(target);
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawModel(model, position, 0.1f, Color.White);
DrawGrid(10, 1.0f);
EndMode3D();
// End drawing to texture (now we have a texture available for next passes)
EndTextureMode();
// Render generated texture using selected postprocessing shader
BeginShaderMode(shaders[currentShader]);
// 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();
DrawRectangle(0, 9, 580, 30, Fade(Color.LightGray, 0.7f));
DrawText("(c) Church 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
DrawText("CURRENT POSTPRO SHADER:", 10, 15, 20, Color.Black);
DrawText(postproShaderText[currentShader], 330, 15, 20, Color.Red);
DrawText("< >", 540, 10, 30, Color.DarkBlue);
DrawFPS(700, 15);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
// Unload all postpro shaders
for (var i = 0; i < (int)PostproShader.Max; i++)
{
UnloadShader(shaders[i]);
}
UnloadTexture(texture);
UnloadModel(model);
UnloadRenderTexture(target);
UnloadTexture(texture); // Unload texture
UnloadModel(model); // Unload model
UnloadRenderTexture(target); // Unload render texture
}
CloseWindow();
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.Msaa4xHint); // Enable Multi Sampling Anti Aliasing 4x (if available)
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - postprocessing");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new PostProcessing();
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;

View file

@ -1,119 +1,157 @@
/*******************************************************************************************
*
* raylib [shaders] example - Raymarching shapes generation
* raylib [shaders] example - raymarching rendering
*
* 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 complexity rating: [] 4/4
*
* 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
* 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
*
* This example has been created using raylib 2.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example originally created with raylib 2.0, last time updated with raylib 4.2
*
* Copyright (c) 2018 Ramon Santamaria (@raysan5)
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2018-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
using static Raylib_cs.ConfigFlags;
namespace Examples.Shaders;
public class Raymarching
public class Raymarching : IExample
{
#if BROWSER
public const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
#else
public const int GlslVersion = 330;
#endif
public string Name => "Shaders / Raymarching";
public string Title => "raylib [shaders] example - raymarching rendering";
public ConfigFlags ConfigFlags => ConfigFlags.ResizableWindow;
public bool CursorDisabled => true;
private int screenWidth;
private int screenHeight;
private Camera3D camera;
private Shader shader;
private int viewEyeLoc;
private int viewCenterLoc;
private int runTimeLoc;
private int resolutionLoc;
private float runTime;
public void Init()
{
screenWidth = GetScreenWidth();
screenHeight = GetScreenHeight();
camera = new();
camera.Position = new Vector3(2.5f, 2.5f, 3.0f); // Camera position
camera.Target = new Vector3(0.0f, 0.0f, 0.7f); // Camera looking at point
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
camera.FovY = 65.0f; // Camera field-of-view Y
camera.Projection = CameraProjection.Perspective; // Camera projection type
// Load raymarching shader
// NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/raymarching.fs");
// Get shader locations for required uniforms
viewEyeLoc = GetShaderLocation(shader, "viewEye");
viewCenterLoc = GetShaderLocation(shader, "viewCenter");
runTimeLoc = GetShaderLocation(shader, "runTime");
resolutionLoc = GetShaderLocation(shader, "resolution");
float[] resolution = { (float)screenWidth, (float)screenHeight };
Raylib.SetShaderValue(shader, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
runTime = 0.0f;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.FirstPerson);
var deltaTime = GetFrameTime();
runTime += deltaTime;
// Set shader required uniform values
Raylib.SetShaderValue(shader, viewEyeLoc, camera.Position, ShaderUniformDataType.Vec3);
Raylib.SetShaderValue(shader, viewCenterLoc, camera.Target, ShaderUniformDataType.Vec3);
Raylib.SetShaderValue(shader, runTimeLoc, runTime, ShaderUniformDataType.Float);
// Check if screen is resized
if (IsWindowResized())
{
screenWidth = GetScreenWidth();
screenHeight = GetScreenHeight();
var resolution = new float[] { (float)screenWidth, (float)screenHeight };
Raylib.SetShaderValue(shader, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// We only draw a white full-screen rectangle,
// frame is generated in shader using raymarching
BeginShaderMode(shader);
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
EndShaderMode();
DrawText(
"(c) Raymarching shader by Iñigo Quilez. MIT License.",
screenWidth - 280,
screenHeight - 20,
10,
Color.Black
);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadShader(shader); // Unload shader
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
int screenWidth = 800;
int screenHeight = 450;
SetConfigFlags(ResizableWindow);
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - raymarching shapes");
InitWindow(800, 450, "raylib [shaders] example - raymarching rendering");
Camera3D camera = new();
camera.Position = new Vector3(2.5f, 2.5f, 3.0f);
camera.Target = new Vector3(0.0f, 0.0f, 0.7f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 65.0f;
// Load raymarching shader
// NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
Shader shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/raymarching.fs");
// Get shader locations for required uniforms
int viewEyeLoc = GetShaderLocation(shader, "viewEye");
int viewCenterLoc = GetShaderLocation(shader, "viewCenter");
int runTimeLoc = GetShaderLocation(shader, "runTime");
int resolutionLoc = GetShaderLocation(shader, "resolution");
float[] resolution = { (float)screenWidth, (float)screenHeight };
Raylib.SetShaderValue(shader, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
float runTime = 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 Raymarching();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Check if screen is resized
//----------------------------------------------------------------------------------
if (IsWindowResized())
{
screenWidth = GetScreenWidth();
screenHeight = GetScreenHeight();
resolution = new float[] { (float)screenWidth, (float)screenHeight };
Raylib.SetShaderValue(shader, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
}
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Free);
float deltaTime = GetFrameTime();
runTime += deltaTime;
// Set shader required uniform values
Raylib.SetShaderValue(shader, viewEyeLoc, camera.Position, ShaderUniformDataType.Vec3);
Raylib.SetShaderValue(shader, viewCenterLoc, camera.Target, ShaderUniformDataType.Vec3);
Raylib.SetShaderValue(shader, runTimeLoc, runTime, ShaderUniformDataType.Float);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// We only draw a white full-screen rectangle,
// frame is generated in shader using raymarching
BeginShaderMode(shader);
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
EndShaderMode();
DrawText(
"(c) Raymarching shader by Iñigo Quilez. MIT License.",
screenWidth - 280,
screenHeight - 20,
10,
Color.Black
);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shader);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,240 @@
/*******************************************************************************************
*
* raylib [shaders] example - rlgl compute
*
* WARNING: This example requires raylib compiled with OpenGL 4.3 version for
* compute shaders support, shaders used in this example are #version 430
*
* Example complexity rating: [] 4/4
*
* Example originally created with raylib 4.0, last time updated with raylib 4.0
*
* Example contributed by Teddy Astie (@tsnake41) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2021-2025 Teddy Astie (@tsnake41)
*
********************************************************************************************/
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
namespace Examples.Shaders;
[ExcludeFromBrowser("compute shaders are not available on WebGL")]
public partial class RlglCompute : IExample
{
// IMPORTANT: This must match gol*.glsl GOL_WIDTH constant
// This must be a multiple of 16 (check golLogic compute dispatch)
private const int GolWidth = 768;
// Maximum amount of queued draw commands (squares draw from mouse down events)
private const int MaxBufferedTransferts = 48;
private const int screenWidth = GolWidth;
private const int screenHeight = GolWidth;
public string Name => "Shaders / Rlgl Compute";
public string Title => "raylib [shaders] example - rlgl compute";
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Game Of Life Update Command
[StructLayout(LayoutKind.Sequential)]
private struct GolUpdateCmd
{
public uint X; // x coordinate of the gol command
public uint Y; // y coordinate of the gol command
public uint W; // width of the filled zone
public uint Enabled; // whether to enable or disable zone
}
// Inline fixed-size array of GolUpdateCmd (MAX_BUFFERED_TRANSFERTS entries)
[InlineArray(MaxBufferedTransferts)]
private struct GolUpdateCmdBuffer
{
private GolUpdateCmd _element0;
}
// Game Of Life Update Commands SSBO
[StructLayout(LayoutKind.Sequential)]
private struct GolUpdateSSBO
{
public uint Count;
public GolUpdateCmdBuffer Commands;
}
private Vector2 resolution;
private uint brushSize;
private uint golLogicShader;
private uint golLogicProgram;
private uint golTransfertShader;
private uint golTransfertProgram;
private Shader golRenderShader;
private int resUniformLoc;
private uint ssboA;
private uint ssboB;
private uint ssboTransfert;
private GolUpdateSSBO transfertBuffer;
private Texture2D whiteTex;
public unsafe void Init()
{
resolution = new Vector2(screenWidth, screenHeight);
brushSize = 8;
// Game of Life logic compute shader
var golLogicCode = LoadFileText("resources/shaders/glsl430/gol.glsl");
var golLogicBytes = Encoding.UTF8.GetBytes(golLogicCode + "\0");
fixed (byte* p = golLogicBytes)
{
golLogicShader = Rlgl.LoadShader((sbyte*)p, (int)ShaderType.Compute);
}
golLogicProgram = Rlgl.LoadShaderProgramCompute(golLogicShader);
// Game of Life logic render shader
golRenderShader = LoadShader(null, "resources/shaders/glsl430/gol_render.glsl");
resUniformLoc = GetShaderLocation(golRenderShader, "resolution");
// Game of Life transfert shader (CPU<->GPU download and upload)
var golTransfertCode = LoadFileText("resources/shaders/glsl430/gol_transfert.glsl");
var golTransfertBytes = Encoding.UTF8.GetBytes(golTransfertCode + "\0");
fixed (byte* p = golTransfertBytes)
{
golTransfertShader = Rlgl.LoadShader((sbyte*)p, (int)ShaderType.Compute);
}
golTransfertProgram = Rlgl.LoadShaderProgramCompute(golTransfertShader);
// Load shader storage buffer object (SSBO), id returned
ssboA = Rlgl.LoadShaderBuffer((uint)(GolWidth * GolWidth * sizeof(uint)), null, Rlgl.DYNAMIC_COPY);
ssboB = Rlgl.LoadShaderBuffer((uint)(GolWidth * GolWidth * sizeof(uint)), null, Rlgl.DYNAMIC_COPY);
ssboTransfert = Rlgl.LoadShaderBuffer((uint)sizeof(GolUpdateSSBO), null, Rlgl.DYNAMIC_COPY);
transfertBuffer = new();
// Create a white texture of the size of the window to update
// each pixel of the window using the fragment shader: golRenderShader
var whiteImage = GenImageColor(GolWidth, GolWidth, Color.White);
whiteTex = LoadTextureFromImage(whiteImage);
UnloadImage(whiteImage);
}
public unsafe void Update()
{
// Update
//----------------------------------------------------------------------------------
brushSize += (uint)(int)GetMouseWheelMove();
if ((IsMouseButtonDown(MouseButton.Left) || IsMouseButtonDown(MouseButton.Right))
&& (transfertBuffer.Count < MaxBufferedTransferts))
{
// Buffer a new command
transfertBuffer.Commands[(int)transfertBuffer.Count].X = (uint)GetMouseX() - brushSize / 2;
transfertBuffer.Commands[(int)transfertBuffer.Count].Y = (uint)GetMouseY() - brushSize / 2;
transfertBuffer.Commands[(int)transfertBuffer.Count].W = brushSize;
transfertBuffer.Commands[(int)transfertBuffer.Count].Enabled = IsMouseButtonDown(MouseButton.Left) ? 1u : 0u;
transfertBuffer.Count++;
}
else if (transfertBuffer.Count > 0) // Process transfert buffer
{
// Send SSBO buffer to GPU
fixed (GolUpdateSSBO* ptr = &transfertBuffer)
{
Rlgl.UpdateShaderBuffer(ssboTransfert, ptr, (uint)sizeof(GolUpdateSSBO), 0);
}
// Process SSBO commands on GPU
Rlgl.EnableShader(golTransfertProgram);
Rlgl.BindShaderBuffer(ssboA, 1);
Rlgl.BindShaderBuffer(ssboTransfert, 3);
Rlgl.ComputeShaderDispatch(transfertBuffer.Count, 1, 1); // Each GPU unit will process a command!
Rlgl.DisableShader();
transfertBuffer.Count = 0;
}
else
{
// Process game of life logic
Rlgl.EnableShader(golLogicProgram);
Rlgl.BindShaderBuffer(ssboA, 1);
Rlgl.BindShaderBuffer(ssboB, 2);
Rlgl.ComputeShaderDispatch(GolWidth / 16, GolWidth / 16, 1);
Rlgl.DisableShader();
// ssboA <-> ssboB
var temp = ssboA;
ssboA = ssboB;
ssboB = temp;
}
Rlgl.BindShaderBuffer(ssboA, 1);
Raylib.SetShaderValue(golRenderShader, resUniformLoc, resolution, ShaderUniformDataType.Vec2);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.Blank);
BeginShaderMode(golRenderShader);
DrawTexture(whiteTex, 0, 0, Color.White);
EndShaderMode();
DrawRectangleLines(GetMouseX() - (int)(brushSize / 2), GetMouseY() - (int)(brushSize / 2), (int)brushSize, (int)brushSize, Color.Red);
DrawText("Use Mouse wheel to increase/decrease brush size", 10, 10, 20, Color.White);
DrawFPS(GetScreenWidth() - 100, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
// Unload shader buffers objects
Rlgl.UnloadShaderBuffer(ssboA);
Rlgl.UnloadShaderBuffer(ssboB);
Rlgl.UnloadShaderBuffer(ssboTransfert);
// Unload compute shader
Rlgl.UnloadShader(golLogicShader);
Rlgl.UnloadShader(golTransfertShader);
Rlgl.UnloadShaderProgram(golTransfertProgram);
Rlgl.UnloadShaderProgram(golLogicProgram);
UnloadTexture(whiteTex); // Unload white texture
UnloadShader(golRenderShader); // Unload rendering fragment shader
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - rlgl compute");
//--------------------------------------------------------------------------------------
var game = new RlglCompute();
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;
}
}

View file

@ -0,0 +1,240 @@
/*******************************************************************************************
*
* raylib [shaders] example - rounded rectangle
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by Anstro Pleuton (@anstropleuton) 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 Anstro Pleuton (@anstropleuton)
*
********************************************************************************************/
namespace Examples.Shaders;
public class RoundedRectangle : 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 / Rounded Rectangle";
public string Title => "raylib [shaders] example - rounded rectangle";
// Rounded rectangle data
private struct RoundedRect
{
public Vector4 CornerRadius; // Individual corner radius (top-left, top-right, bottom-left, bottom-right)
// Shadow variables
public float ShadowRadius;
public Vector2 ShadowOffset;
public float ShadowScale;
// Border variables
public float BorderThickness; // Inner-border thickness
// Shader locations
public int RectangleLoc;
public int RadiusLoc;
public int ColorLoc;
public int ShadowRadiusLoc;
public int ShadowOffsetLoc;
public int ShadowScaleLoc;
public int ShadowColorLoc;
public int BorderThicknessLoc;
public int BorderColorLoc;
}
private Shader shader;
private RoundedRect roundedRectangle;
private readonly Color rectangleColor = Color.Blue;
private readonly Color shadowColor = Color.DarkBlue;
private readonly Color borderColor = Color.SkyBlue;
public void Init()
{
// Load the shader
shader = LoadShader(
$"resources/shaders/glsl{GlslVersion}/base.vs",
$"resources/shaders/glsl{GlslVersion}/rounded_rectangle.fs"
);
// Create a rounded rectangle
roundedRectangle = CreateRoundedRectangle(
new Vector4(5.0f, 10.0f, 15.0f, 20.0f), // Corner radius
20.0f, // Shadow radius
new Vector2(0.0f, -5.0f), // Shadow offset
0.95f, // Shadow scale
5.0f, // Border thickness
shader // Shader
);
// Update shader uniforms
UpdateRoundedRectangle(roundedRectangle, shader);
}
public void Update()
{
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw rectangle box with rounded corners using shader
Rectangle rec = new(50, 70, 110, 60);
DrawRectangleLines((int)rec.X - 20, (int)rec.Y - 20, (int)rec.Width + 40, (int)rec.Height + 40, Color.DarkGray);
DrawText("Rounded rectangle", (int)rec.X - 20, (int)rec.Y - 35, 10, Color.DarkGray);
// Flip Y axis to match shader coordinate system
rec.Y = screenHeight - rec.Y - rec.Height;
Raylib.SetShaderValue(shader, roundedRectangle.RectangleLoc, new[] { rec.X, rec.Y, rec.Width, rec.Height }, ShaderUniformDataType.Vec4);
// Only rectangle color
Raylib.SetShaderValue(shader, roundedRectangle.ColorLoc, new[] { rectangleColor.R / 255.0f, rectangleColor.G / 255.0f, rectangleColor.B / 255.0f, rectangleColor.A / 255.0f }, ShaderUniformDataType.Vec4);
Raylib.SetShaderValue(shader, roundedRectangle.ShadowColorLoc, new[] { 0.0f, 0.0f, 0.0f, 0.0f }, ShaderUniformDataType.Vec4);
Raylib.SetShaderValue(shader, roundedRectangle.BorderColorLoc, new[] { 0.0f, 0.0f, 0.0f, 0.0f }, ShaderUniformDataType.Vec4);
BeginShaderMode(shader);
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
EndShaderMode();
// Draw rectangle shadow using shader
rec = new Rectangle(50, 200, 110, 60);
DrawRectangleLines((int)rec.X - 20, (int)rec.Y - 20, (int)rec.Width + 40, (int)rec.Height + 40, Color.DarkGray);
DrawText("Rounded rectangle shadow", (int)rec.X - 20, (int)rec.Y - 35, 10, Color.DarkGray);
rec.Y = screenHeight - rec.Y - rec.Height;
Raylib.SetShaderValue(shader, roundedRectangle.RectangleLoc, new[] { rec.X, rec.Y, rec.Width, rec.Height }, ShaderUniformDataType.Vec4);
// Only shadow color
Raylib.SetShaderValue(shader, roundedRectangle.ColorLoc, new[] { 0.0f, 0.0f, 0.0f, 0.0f }, ShaderUniformDataType.Vec4);
Raylib.SetShaderValue(shader, roundedRectangle.ShadowColorLoc, new[] { shadowColor.R / 255.0f, shadowColor.G / 255.0f, shadowColor.B / 255.0f, shadowColor.A / 255.0f }, ShaderUniformDataType.Vec4);
Raylib.SetShaderValue(shader, roundedRectangle.BorderColorLoc, new[] { 0.0f, 0.0f, 0.0f, 0.0f }, ShaderUniformDataType.Vec4);
BeginShaderMode(shader);
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
EndShaderMode();
// Draw rectangle's border using shader
rec = new Rectangle(50, 330, 110, 60);
DrawRectangleLines((int)rec.X - 20, (int)rec.Y - 20, (int)rec.Width + 40, (int)rec.Height + 40, Color.DarkGray);
DrawText("Rounded rectangle border", (int)rec.X - 20, (int)rec.Y - 35, 10, Color.DarkGray);
rec.Y = screenHeight - rec.Y - rec.Height;
Raylib.SetShaderValue(shader, roundedRectangle.RectangleLoc, new[] { rec.X, rec.Y, rec.Width, rec.Height }, ShaderUniformDataType.Vec4);
// Only border color
Raylib.SetShaderValue(shader, roundedRectangle.ColorLoc, new[] { 0.0f, 0.0f, 0.0f, 0.0f }, ShaderUniformDataType.Vec4);
Raylib.SetShaderValue(shader, roundedRectangle.ShadowColorLoc, new[] { 0.0f, 0.0f, 0.0f, 0.0f }, ShaderUniformDataType.Vec4);
Raylib.SetShaderValue(shader, roundedRectangle.BorderColorLoc, new[] { borderColor.R / 255.0f, borderColor.G / 255.0f, borderColor.B / 255.0f, borderColor.A / 255.0f }, ShaderUniformDataType.Vec4);
BeginShaderMode(shader);
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
EndShaderMode();
// Draw one more rectangle with all three colors
rec = new Rectangle(240, 80, 500, 300);
DrawRectangleLines((int)rec.X - 30, (int)rec.Y - 30, (int)rec.Width + 60, (int)rec.Height + 60, Color.DarkGray);
DrawText("Rectangle with all three combined", (int)rec.X - 30, (int)rec.Y - 45, 10, Color.DarkGray);
rec.Y = screenHeight - rec.Y - rec.Height;
Raylib.SetShaderValue(shader, roundedRectangle.RectangleLoc, new[] { rec.X, rec.Y, rec.Width, rec.Height }, ShaderUniformDataType.Vec4);
// All three colors
Raylib.SetShaderValue(shader, roundedRectangle.ColorLoc, new[] { rectangleColor.R / 255.0f, rectangleColor.G / 255.0f, rectangleColor.B / 255.0f, rectangleColor.A / 255.0f }, ShaderUniformDataType.Vec4);
Raylib.SetShaderValue(shader, roundedRectangle.ShadowColorLoc, new[] { shadowColor.R / 255.0f, shadowColor.G / 255.0f, shadowColor.B / 255.0f, shadowColor.A / 255.0f }, ShaderUniformDataType.Vec4);
Raylib.SetShaderValue(shader, roundedRectangle.BorderColorLoc, new[] { borderColor.R / 255.0f, borderColor.G / 255.0f, borderColor.B / 255.0f, borderColor.A / 255.0f }, ShaderUniformDataType.Vec4);
BeginShaderMode(shader);
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
EndShaderMode();
DrawText("(c) Rounded rectangle SDF by Iñigo Quilez. MIT License.", screenWidth - 300, screenHeight - 20, 10, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadShader(shader); // Unload shader
}
// Create a rounded rectangle and set uniform locations
private static RoundedRect CreateRoundedRectangle(Vector4 cornerRadius, float shadowRadius, Vector2 shadowOffset, float shadowScale, float borderThickness, Shader shader)
{
RoundedRect rec;
rec.CornerRadius = cornerRadius;
rec.ShadowRadius = shadowRadius;
rec.ShadowOffset = shadowOffset;
rec.ShadowScale = shadowScale;
rec.BorderThickness = borderThickness;
// Get shader uniform locations
rec.RectangleLoc = GetShaderLocation(shader, "rectangle");
rec.RadiusLoc = GetShaderLocation(shader, "radius");
rec.ColorLoc = GetShaderLocation(shader, "color");
rec.ShadowRadiusLoc = GetShaderLocation(shader, "shadowRadius");
rec.ShadowOffsetLoc = GetShaderLocation(shader, "shadowOffset");
rec.ShadowScaleLoc = GetShaderLocation(shader, "shadowScale");
rec.ShadowColorLoc = GetShaderLocation(shader, "shadowColor");
rec.BorderThicknessLoc = GetShaderLocation(shader, "borderThickness");
rec.BorderColorLoc = GetShaderLocation(shader, "borderColor");
UpdateRoundedRectangle(rec, shader);
return rec;
}
// Update rounded rectangle uniforms
private static void UpdateRoundedRectangle(RoundedRect rec, Shader shader)
{
Raylib.SetShaderValue(shader, rec.RadiusLoc, new[] { rec.CornerRadius.X, rec.CornerRadius.Y, rec.CornerRadius.Z, rec.CornerRadius.W }, ShaderUniformDataType.Vec4);
Raylib.SetShaderValue(shader, rec.ShadowRadiusLoc, rec.ShadowRadius, ShaderUniformDataType.Float);
Raylib.SetShaderValue(shader, rec.ShadowOffsetLoc, new[] { rec.ShadowOffset.X, rec.ShadowOffset.Y }, ShaderUniformDataType.Vec2);
Raylib.SetShaderValue(shader, rec.ShadowScaleLoc, rec.ShadowScale, ShaderUniformDataType.Float);
Raylib.SetShaderValue(shader, rec.BorderThicknessLoc, rec.BorderThickness, ShaderUniformDataType.Float);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - rounded rectangle");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new RoundedRectangle();
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;
}
}

View file

@ -0,0 +1,314 @@
/*******************************************************************************************
*
* raylib [shaders] example - shadowmap rendering
*
* Example complexity rating: [] 4/4
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
* Example contributed by TheManTheMythTheGameDev (@TheManTheMythTheGameDev) 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 TheManTheMythTheGameDev (@TheManTheMythTheGameDev)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
using static Raylib_cs.Rlgl;
namespace Examples.Shaders;
public partial class ShadowmapRendering : 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 ShadowmapResolution = 1024;
public string Name => "Shaders / Shadowmap Rendering";
public string Title => "raylib [shaders] example - shadowmap rendering";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
private Camera3D camera;
private Shader shadowShader;
private Vector3 lightDir;
private int lightDirLoc;
private int lightVPLoc;
private int shadowMapLoc;
private Model cube;
private Model robot;
private unsafe ModelAnimation* anims;
private int animCount;
private RenderTexture2D shadowMap;
private Camera3D lightCamera;
private int frameCounter;
private int textureActiveSlot;
public unsafe void Init()
{
// Shadows are a HUGE topic, and this example shows an extremely simple implementation of the shadowmapping algorithm,
// which is the industry standard for shadows. This algorithm can be extended in a ridiculous number of ways to improve
// realism and also adapt it for different scenes. This is pretty much the simplest possible implementation
camera = new();
camera.Position = new Vector3(10.0f, 10.0f, 10.0f);
camera.Target = Vector3.Zero;
camera.Projection = CameraProjection.Perspective;
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 45.0f;
shadowShader = LoadShader(
$"resources/shaders/glsl{GlslVersion}/shadowmap.vs",
$"resources/shaders/glsl{GlslVersion}/shadowmap.fs"
);
shadowShader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(shadowShader, "viewPos");
lightDir = Vector3Normalize(new Vector3(0.35f, -1.0f, -0.35f));
var lightColor = Color.White;
var lightColorNormalized = ColorNormalize(lightColor);
lightDirLoc = GetShaderLocation(shadowShader, "lightDir");
var lightColLoc = GetShaderLocation(shadowShader, "lightColor");
Raylib.SetShaderValue(shadowShader, lightDirLoc, lightDir, ShaderUniformDataType.Vec3);
Raylib.SetShaderValue(shadowShader, lightColLoc, lightColorNormalized, ShaderUniformDataType.Vec4);
var ambientLoc = GetShaderLocation(shadowShader, "ambient");
var ambient = new[] { 0.1f, 0.1f, 0.1f, 1.0f };
Raylib.SetShaderValue(shadowShader, ambientLoc, ambient, ShaderUniformDataType.Vec4);
lightVPLoc = GetShaderLocation(shadowShader, "lightVP");
shadowMapLoc = GetShaderLocation(shadowShader, "shadowMap");
var shadowMapResolution = ShadowmapResolution;
Raylib.SetShaderValue(shadowShader, GetShaderLocation(shadowShader, "shadowMapResolution"), shadowMapResolution, ShaderUniformDataType.Int);
cube = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
cube.Materials[0].Shader = shadowShader;
robot = LoadModel("resources/models/robot.glb");
for (var i = 0; i < robot.MaterialCount; i++)
{
robot.Materials[i].Shader = shadowShader;
}
animCount = 0;
anims = LoadModelAnimations("resources/models/robot.glb", ref animCount);
shadowMap = LoadShadowmapRenderTexture(ShadowmapResolution, ShadowmapResolution);
// For the shadowmapping algorithm, we will be rendering everything from the light's point of view
lightCamera = new();
lightCamera.Position = Vector3Scale(lightDir, -15.0f);
lightCamera.Target = Vector3.Zero;
lightCamera.Projection = CameraProjection.Orthographic; // Use an orthographic projection for directional lights
lightCamera.Up = new Vector3(0.0f, 1.0f, 0.0f);
lightCamera.FovY = 20.0f;
frameCounter = 0;
textureActiveSlot = 10; // Can be anything 0 to 15, but 0 will probably be taken up
}
public unsafe void Update()
{
// Update
//----------------------------------------------------------------------------------
var deltaTime = GetFrameTime();
var cameraPos = camera.Position;
Raylib.SetShaderValue(shadowShader, shadowShader.Locs[(int)ShaderLocationIndex.VectorView], cameraPos, ShaderUniformDataType.Vec3);
UpdateCamera(ref camera, CameraMode.Orbital);
frameCounter++;
frameCounter %= anims[0].KeyFrameCount;
UpdateModelAnimation(robot, anims[0], (float)frameCounter);
// Move light with arrow keys
const float cameraSpeed = 0.05f;
if (IsKeyDown(KeyboardKey.Left))
{
if (lightDir.X < 0.6f)
{
lightDir.X += cameraSpeed * 60.0f * deltaTime;
}
}
if (IsKeyDown(KeyboardKey.Right))
{
if (lightDir.X > -0.6f)
{
lightDir.X -= cameraSpeed * 60.0f * deltaTime;
}
}
if (IsKeyDown(KeyboardKey.Up))
{
if (lightDir.Z < 0.6f)
{
lightDir.Z += cameraSpeed * 60.0f * deltaTime;
}
}
if (IsKeyDown(KeyboardKey.Down))
{
if (lightDir.Z > -0.6f)
{
lightDir.Z -= cameraSpeed * 60.0f * deltaTime;
}
}
lightDir = Vector3Normalize(lightDir);
lightCamera.Position = Vector3Scale(lightDir, -15.0f);
Raylib.SetShaderValue(shadowShader, lightDirLoc, lightDir, ShaderUniformDataType.Vec3);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// PASS 01: Render all objects into the shadowmap render texture
// We record all the objects' depths (as rendered from the light source's point of view) in a buffer
// Anything that is "visible" to the light is in light, anything that isn't is in shadow
// We can later use the depth buffer when rendering everything from the player's point of view
// to determine whether a given point is "visible" to the light
Matrix4x4 lightView;
Matrix4x4 lightProj;
BeginTextureMode(shadowMap);
ClearBackground(Color.White);
BeginMode3D(lightCamera);
lightView = GetMatrixModelview();
lightProj = GetMatrixProjection();
DrawScene(cube, robot);
EndMode3D();
EndTextureMode();
var lightViewProj = MatrixMultiply(lightView, lightProj);
// PASS 02: Draw the scene into main framebuffer, using the generated shadowmap
BeginDrawing();
ClearBackground(Color.RayWhite);
SetShaderValueMatrix(shadowShader, lightVPLoc, lightViewProj);
EnableShader(shadowShader.Id);
ActiveTextureSlot(textureActiveSlot);
EnableTexture(shadowMap.Depth.Id);
var slot = textureActiveSlot;
SetUniform(shadowMapLoc, &slot, (int)ShaderUniformDataType.Int, 1);
BeginMode3D(camera);
DrawScene(cube, robot); // Draw the same exact things as we drew in the shadowmap!
EndMode3D();
DrawText("Use the arrow keys to rotate the light!", 10, 10, 30, Color.Red);
DrawText("Shadows in raylib using the shadowmapping algorithm!", screenWidth - 280, screenHeight - 20, 10, Color.Gray);
EndDrawing();
if (IsKeyPressed(KeyboardKey.F))
{
TakeScreenshot("shaders_shadowmap.png");
}
//----------------------------------------------------------------------------------
}
public unsafe void Unload()
{
UnloadShader(shadowShader);
UnloadModel(cube);
UnloadModel(robot);
UnloadModelAnimations(anims, animCount);
UnloadShadowmapRenderTexture(shadowMap);
}
// Load render texture for shadowmap projection
// NOTE: Load framebuffer with only a texture depth attachment,
// no color attachment required for shadowmap
private static unsafe RenderTexture2D LoadShadowmapRenderTexture(int width, int height)
{
RenderTexture2D target = new();
target.Id = LoadFramebuffer(); // Load an empty framebuffer
target.Texture.Width = width;
target.Texture.Height = height;
if (target.Id > 0)
{
EnableFramebuffer(target.Id);
// Create depth texture
// NOTE: No need a color texture attachment for the shadowmap
target.Depth.Id = LoadTextureDepth(width, height, false);
target.Depth.Width = width;
target.Depth.Height = height;
target.Depth.Format = (PixelFormat)19; // DEPTH_COMPONENT_24BIT?
target.Depth.Mipmaps = 1;
// Attach depth texture to FBO
FramebufferAttach(target.Id, target.Depth.Id, FramebufferAttachType.Depth, FramebufferAttachTextureType.Texture2D, 0);
// Check if fbo is complete with attachments (valid)
if (FramebufferComplete(target.Id) != 0)
{
TraceLog(TraceLogLevel.Info, $"FBO: [ID {target.Id}] Framebuffer object created successfully");
}
DisableFramebuffer();
}
else
{
TraceLog(TraceLogLevel.Warning, "FBO: Framebuffer object can not be created");
}
return target;
}
// Unload shadowmap render texture from GPU memory (VRAM)
private static void UnloadShadowmapRenderTexture(RenderTexture2D target)
{
if (target.Id > 0)
{
// NOTE: Depth texture/renderbuffer is automatically
// queried and deleted before deleting framebuffer
UnloadFramebuffer(target.Id);
}
}
// Draw full scene projecting shadows
// NOTE: Required to be called several time to generate shadowmap
private static void DrawScene(Model cube, Model robot)
{
DrawModelEx(cube, Vector3.Zero, new Vector3(0.0f, 1.0f, 0.0f), 0.0f, new Vector3(10.0f, 1.0f, 10.0f), Color.Blue);
DrawModelEx(cube, new Vector3(1.5f, 1.0f, -1.5f), new Vector3(0.0f, 1.0f, 0.0f), 0.0f, Vector3.One, Color.White);
DrawModelEx(robot, new Vector3(0.0f, 0.5f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f), 0.0f, new Vector3(1.0f, 1.0f, 1.0f), Color.Red);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shadowmap rendering");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new ShadowmapRendering();
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;
}
}

View file

@ -1,121 +1,144 @@
/*******************************************************************************************
*
* raylib [shaders] example - Apply a shader to some shape or texture
* raylib [shaders] example - shapes textures
*
* 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.7 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example originally created with raylib 1.7, last time updated with raylib 3.7
*
* 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)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shaders;
public class ShapesTextures
public class ShapesTextures : 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 / Shapes Textures";
public string Title => "raylib [shaders] example - shapes textures";
private Texture2D fudesumi;
private Shader shader;
public void Init()
{
fudesumi = LoadTexture("resources/fudesumi.png");
// Load shader to be used on some parts drawing
// NOTE 1: Using GLSL 330 shader version, on OpenGL ES 2.0 use GLSL 100 shader version
// NOTE 2: Defining null (NULL) for vertex shader forces usage of internal default vertex shader
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/grayscale.fs");
}
public void Update()
{
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Start drawing with default shader
DrawText("USING DEFAULT SHADER", 20, 40, 10, Color.Red);
DrawCircle(80, 120, 35, Color.DarkBlue);
DrawCircleGradient(new Vector2(80, 220), 60, Color.Green, Color.SkyBlue);
DrawCircleLines(80, 340, 80, Color.DarkBlue);
// Activate our custom shader to be applied on next shapes/textures drawings
BeginShaderMode(shader);
DrawText("USING CUSTOM SHADER", 190, 40, 10, Color.Red);
DrawRectangle(250 - 60, 90, 120, 60, Color.Red);
DrawRectangleGradientH(250 - 90, 170, 180, 130, Color.Maroon, Color.Gold);
DrawRectangleLines(250 - 40, 320, 80, 60, Color.Orange);
// Activate our default shader for next drawings
EndShaderMode();
DrawText("USING DEFAULT SHADER", 370, 40, 10, Color.Red);
DrawTriangle(
new Vector2(430, 80),
new Vector2(430 - 60, 150),
new Vector2(430 + 60, 150), Color.Violet
);
DrawTriangleLines(
new Vector2(430, 160),
new Vector2(430 - 20, 230),
new Vector2(430 + 20, 230), Color.DarkBlue
);
DrawPoly(new Vector2(430, 320), 6, 80, 0, Color.Brown);
// Activate our custom shader to be applied on next shapes/textures drawings
BeginShaderMode(shader);
// Using custom shader
DrawTexture(fudesumi, 500, -30, Color.White);
// Activate our default shader for next drawings
EndShaderMode();
DrawText("(c) Fudesumi sprite by Eiden Marsal", 380, screenHeight - 20, 10, Color.Gray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadShader(shader); // Unload shader
UnloadTexture(fudesumi); // Unload texture
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shapes textures");
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shapes and texture shaders");
Texture2D fudesumi = LoadTexture("resources/fudesumi.png");
// NOTE: Using GLSL 330 shader version, on OpenGL ES 2.0 use GLSL 100 shader version
Shader shader = LoadShader(
"resources/shaders/glsl330/base.vs",
"resources/shaders/glsl330/grayscale.fs"
);
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new ShapesTextures();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Start drawing with default shader
DrawText("USING DEFAULT SHADER", 20, 40, 10, Color.Red);
DrawCircle(80, 120, 35, Color.DarkBlue);
DrawCircleGradient(new Vector2(80, 220), 60, Color.Green, Color.SkyBlue);
DrawCircleLines(80, 340, 80, Color.DarkBlue);
// Activate our custom shader to be applied on next shapes/textures drawings
BeginShaderMode(shader);
DrawText("USING CUSTOM SHADER", 190, 40, 10, Color.Red);
DrawRectangle(250 - 60, 90, 120, 60, Color.Red);
DrawRectangleGradientH(250 - 90, 170, 180, 130, Color.Maroon, Color.Gold);
DrawRectangleLines(250 - 40, 320, 80, 60, Color.Orange);
// Activate our default shader for next drawings
EndShaderMode();
DrawText("USING DEFAULT SHADER", 370, 40, 10, Color.Red);
DrawTriangle(
new Vector2(430, 80),
new Vector2(430 - 60, 150),
new Vector2(430 + 60, 150), Color.Violet
);
DrawTriangleLines(
new Vector2(430, 160),
new Vector2(430 - 20, 230),
new Vector2(430 + 20, 230), Color.DarkBlue
);
DrawPoly(new Vector2(430, 320), 6, 80, 0, Color.Brown);
// Activate our custom shader to be applied on next shapes/textures drawings
BeginShaderMode(shader);
// Using custom shader
DrawTexture(fudesumi, 500, -30, Color.White);
// Activate our default shader for next drawings
EndShaderMode();
DrawText("(c) Fudesumi sprite by Eiden Marsal", 380, screenHeight - 20, 10, Color.Gray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shader);
UnloadTexture(fudesumi);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,13 +1,17 @@
/*******************************************************************************************
*
* raylib [shaders] example - Simple shader mask
* raylib [shaders] example - simple mask
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Example contributed by Chris Camacho (@codifies) and reviewed by Ramon Santamaria (@raysan5)
* Example originally created with raylib 2.5, last time updated with raylib 3.7
*
* Copyright (c) 2019 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5)
* Example contributed by Chris Camacho (@chriscamacho) 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 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5)
*
********************************************************************************************
*
@ -18,60 +22,76 @@
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
using static Raylib_cs.Raymath;
namespace Examples.Shaders;
public class SimpleMask
public class SimpleMask : IExample
{
public unsafe 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
public string Name => "Shaders / Simple Mask";
public string Title => "raylib [shaders] example - simple mask";
public bool CursorDisabled => true;
private Camera3D camera;
private Model model1;
private Model model2;
private Model model3;
private Shader shader;
private Texture2D texDiffuse;
private Texture2D texMask;
private int shaderFrame;
private int framesCounter;
private Vector3 rotation;
public unsafe void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib - simple shader mask");
// Define the camera to look into our 3d world
Camera3D camera = new();
camera.Position = new Vector3(0.0f, 1.0f, 2.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(0.0f, 1.0f, 2.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
// Define our three models to show the shader on
Mesh torus = GenMeshTorus(.3f, 1, 16, 32);
Model model1 = LoadModelFromMesh(torus);
var torus = GenMeshTorus(.3f, 1, 16, 32);
model1 = LoadModelFromMesh(torus);
Mesh cube = GenMeshCube(.8f, .8f, .8f);
Model model2 = LoadModelFromMesh(cube);
var cube = GenMeshCube(.8f, .8f, .8f);
model2 = LoadModelFromMesh(cube);
// Generate model to be shaded just to see the gaps in the other two
Mesh sphere = GenMeshSphere(1, 16, 16);
Model model3 = LoadModelFromMesh(sphere);
var sphere = GenMeshSphere(1, 16, 16);
model3 = LoadModelFromMesh(sphere);
// Load the shader
Shader shader = LoadShader("resources/shaders/glsl330/mask.vs", "resources/shaders/glsl330/mask.fs");
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/mask.fs");
// Load and apply the diffuse texture (colour map)
Texture2D texDiffuse = LoadTexture("resources/plasma.png");
texDiffuse = LoadTexture("resources/plasma.png");
Material* materials = model1.Materials;
MaterialMap* maps = materials[0].Maps;
var materials = model1.Materials;
var maps = materials[0].Maps;
model1.Materials[0].Maps[(int)MaterialMapIndex.Albedo].Texture = texDiffuse;
materials = model2.Materials;
maps = materials[0].Maps;
maps[(int)MaterialMapIndex.Albedo].Texture = texDiffuse;
// Using MAP_EMISSION as a spare slot to use for 2nd texture
// NOTE: Don't use MAP_IRRADIANCE, MAP_PREFILTER or MAP_CUBEMAP
// as they are bound as cube maps
Texture2D texMask = LoadTexture("resources/mask.png");
// Using MATERIAL_MAP_EMISSION as a spare slot to use for 2nd texture
// NOTE: Don't use MATERIAL_MAP_IRRADIANCE, MATERIAL_MAP_PREFILTER or MATERIAL_MAP_CUBEMAP as they are bound as cube maps
texMask = LoadTexture("resources/mask.png");
materials = model1.Materials;
maps = (MaterialMap*)materials[0].Maps;
@ -81,11 +101,11 @@ public class SimpleMask
maps = (MaterialMap*)materials[0].Maps;
maps[(int)MaterialMapIndex.Emission].Texture = texMask;
int* locs = shader.Locs;
var locs = shader.Locs;
locs[(int)ShaderLocationIndex.MapEmission] = GetShaderLocation(shader, "mask");
// Frame is incremented each frame to animate the shader
int shaderFrame = GetShaderLocation(shader, "framesCounter");
shaderFrame = GetShaderLocation(shader, "frame");
// Apply the shader to the two models
materials = model1.Materials;
@ -94,69 +114,88 @@ public class SimpleMask
materials = (Material*)model2.Materials;
materials[0].Shader = shader;
int framesCounter = 0;
framesCounter = 0;
rotation = new(0, 0, 0); // Model rotation angles
}
// Model rotation angles
Vector3 rotation = new(0, 0, 0);
public void Update()
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.FirstPerson);
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
framesCounter++;
rotation.X += 0.01f;
rotation.Y += 0.005f;
rotation.Z -= 0.0025f;
// Main game loop
while (!WindowShouldClose())
{
// Update
//----------------------------------------------------------------------------------
framesCounter++;
rotation.X += 0.01f;
rotation.Y += 0.005f;
rotation.Z -= 0.0025f;
// Send frames counter to shader for animation
Raylib.SetShaderValue(shader, shaderFrame, framesCounter, ShaderUniformDataType.Int);
// Send frames counter to shader for animation
Raylib.SetShaderValue(shader, shaderFrame, framesCounter, ShaderUniformDataType.Int);
// Rotate one of the models
model1.Transform = MatrixRotateXYZ(rotation);
//----------------------------------------------------------------------------------
// Rotate one of the models
model1.Transform = MatrixRotateXYZ(rotation);
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.DarkBlue);
UpdateCamera(ref camera, CameraMode.Custom);
//----------------------------------------------------------------------------------
BeginMode3D(camera);
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.DarkBlue);
DrawModel(model1, new Vector3(0.5f, 0, 0), 1, Color.White);
DrawModelEx(model2, new Vector3(-.5f, 0, 0), new Vector3(1, 1, 0), 50, new Vector3(1, 1, 1), Color.White);
DrawModel(model3, new Vector3(0, 0, -1.5f), 1, Color.White);
DrawGrid(10, 1.0f); // Draw a grid
BeginMode3D(camera);
EndMode3D();
DrawModel(model1, new Vector3(0.5f, 0, 0), 1, Color.White);
DrawModelEx(model2, new Vector3(-.5f, 0, 0), new Vector3(1, 1, 0), 50, new Vector3(1, 1, 1), Color.White);
DrawModel(model3, new Vector3(0, 0, -1.5f), 1, Color.White);
DrawGrid(10, 1.0f);
var frameText = $"Frame: {framesCounter}";
DrawRectangle(16, 698, MeasureText(frameText, 20) + 8, 42, Color.Blue);
DrawText(frameText, 20, 700, 20, Color.White);
EndMode3D();
DrawFPS(10, 10);
string frameText = $"Frame: {framesCounter}";
DrawRectangle(16, 698, MeasureText(frameText, 20) + 8, 42, Color.Blue);
DrawText(frameText, 20, 700, 20, Color.White);
EndDrawing();
//----------------------------------------------------------------------------------
}
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
public void Unload()
{
UnloadModel(model1);
UnloadModel(model2);
UnloadModel(model3);
UnloadTexture(texDiffuse);
UnloadTexture(texMask);
UnloadTexture(texDiffuse); // Unload default diffuse texture
UnloadTexture(texMask); // Unload texture mask
UnloadShader(shader);
UnloadShader(shader); // Unload shader
}
CloseWindow();
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - simple mask");
DisableCursor(); // Limit cursor to relative movement inside the window
SetTargetFPS(60); // Set to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new SimpleMask();
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;

View file

@ -1,46 +1,60 @@
/*******************************************************************************************
*
* raylib [shaders] example - Simple shader mask
* raylib [shaders] example - spotlight rendering
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Example contributed by Chris Camacho (@chriscamacho - http://bedroomcoders.co.uk/)
* and reviewed by Ramon Santamaria (@raysan5)
* Example originally created with raylib 2.5, last time updated with raylib 3.7
*
* Copyright (c) 2019 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5)
* Example contributed by Chris Camacho (@chriscamacho) 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 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5)
*
********************************************************************************************
*
* The shader makes alpha holes in the forground to give the apearance of a top
* The shader makes alpha holes in the forground to give the appearance of a top
* down look at a spotlight casting a pool of light...
*
* The right hand side of the screen there is just enough light to see whats
* going on without the spot light, great for a stealth type game where you
* have to avoid the spotlights.
* have to avoid the spotlights
*
* The left hand side of the screen is in pitch dark except for where the spotlights are.
* The left hand side of the screen is in pitch dark except for where the spotlights are
*
* Although this example doesn't scale like the letterbox example, you could integrate
* the two techniques, but by scaling the actual colour of the render texture rather
* than using alpha as a mask.
* than using alpha as a mask
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shaders;
public class Spotlight
public class Spotlight : 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
// NOTE: It must be the same as define in shader
const int MaxSpots = 3;
const int MaxStars = 400;
private const int MaxSpots = 3;
private const int MaxStars = 400;
public string Name => "Shaders / Spotlight";
public string Title => "raylib [shaders] example - spotlight rendering";
public bool CursorHidden => true;
// Spot data
struct Spot
private struct Spot
{
public Vector2 pos;
public Vector2 vel;
@ -54,53 +68,51 @@ public class Spotlight
}
// Stars in the star field have a position and velocity
struct Star
private struct Star
{
public Vector2 pos;
public Vector2 vel;
}
public static int Main()
private Texture2D texRay;
private Star[] stars;
private int frameCounter;
private Shader shdrSpot;
private Spot[] spots;
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
texRay = LoadTexture("resources/raysan.png");
InitWindow(screenWidth, screenHeight, "raylib - shader spotlight");
HideCursor();
stars = new Star[MaxStars];
Texture2D texRay = LoadTexture("resources/raysan.png");
Star[] stars = new Star[MaxStars];
for (int n = 0; n < MaxStars; n++)
for (var n = 0; n < MaxStars; n++)
{
ResetStar(ref stars[n]);
}
// Progress all the stars on, so they don't all start in the centre
for (int m = 0; m < screenWidth / 2.0; m++)
for (var m = 0; m < screenWidth / 2.0; m++)
{
for (int n = 0; n < MaxStars; n++)
for (var n = 0; n < MaxStars; n++)
{
UpdateStar(ref stars[n]);
}
}
int frameCounter = 0;
frameCounter = 0;
// Use default vert shader
Shader shdrSpot = LoadShader(null, "resources/shaders/glsl330/spotlight.fs");
shdrSpot = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/spotlight.fs");
// Get the locations of spots in the shader
Spot[] spots = new Spot[MaxSpots];
spots = new Spot[MaxSpots];
for (int i = 0; i < MaxSpots; i++)
for (var i = 0; i < MaxSpots; i++)
{
string posName = $"spots[{i}].pos";
string innerName = $"spots[{i}].inner";
string radiusName = $"spots[{i}].radius";
var posName = $"spots[{i}].pos";
var innerName = $"spots[{i}].inner";
var radiusName = $"spots[{i}].radius";
spots[i].posLoc = GetShaderLocation(shdrSpot, posName);
spots[i].innerLoc = GetShaderLocation(shdrSpot, innerName);
@ -108,14 +120,14 @@ public class Spotlight
}
// Tell the shader how wide the screen is so we can have
// a pitch Color.black half and a dimly lit half.
int wLoc = GetShaderLocation(shdrSpot, "screenWidth");
float sw = (float)GetScreenWidth();
// a pitch black half and a dimly lit half
var wLoc = GetShaderLocation(shdrSpot, "screenWidth");
var sw = (float)GetScreenWidth();
Raylib.SetShaderValue(shdrSpot, wLoc, sw, ShaderUniformDataType.Float);
// Randomise the locations and velocities of the spotlights
// and initialise the shader locations
for (int i = 0; i < MaxSpots; i++)
// Randomize the locations and velocities of the spotlights
// and initialize the shader locations
for (var i = 0; i < MaxSpots; i++)
{
spots[i].pos.X = GetRandomValue(64, screenWidth - 64);
spots[i].pos.Y = GetRandomValue(64, screenHeight - 64);
@ -123,8 +135,8 @@ public class Spotlight
while ((MathF.Abs(spots[i].vel.X) + MathF.Abs(spots[i].vel.Y)) < 2)
{
spots[i].vel.X = GetRandomValue(-40, 40) / 10.0f;
spots[i].vel.Y = GetRandomValue(-40, 40) / 10.0f;
spots[i].vel.X = GetRandomValue(-400, 40) / 25.0f;
spots[i].vel.Y = GetRandomValue(-400, 40) / 25.0f;
}
spots[i].inner = 28.0f * (i + 1);
@ -149,118 +161,110 @@ public class Spotlight
ShaderUniformDataType.Float
);
}
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose())
{
// Update
//----------------------------------------------------------------------------------
frameCounter++;
// Move the stars, resetting them if the go offscreen
for (int n = 0; n < MaxStars; n++)
{
UpdateStar(ref stars[n]);
}
// Update the spots, send them to the shader
for (int i = 0; i < MaxSpots; i++)
{
if (i == 0)
{
Vector2 mp = GetMousePosition();
spots[i].pos.X = mp.X;
spots[i].pos.Y = screenHeight - mp.Y;
}
else
{
spots[i].pos.X += spots[i].vel.X;
spots[i].pos.Y += spots[i].vel.Y;
if (spots[i].pos.X < 64)
{
spots[i].vel.X = -spots[i].vel.X;
}
if (spots[i].pos.X > (screenWidth - 64))
{
spots[i].vel.X = -spots[i].vel.X;
}
if (spots[i].pos.Y < 64)
{
spots[i].vel.Y = -spots[i].vel.Y;
}
if (spots[i].pos.Y > (screenHeight - 64))
{
spots[i].vel.Y = -spots[i].vel.Y;
}
}
Raylib.SetShaderValue(
shdrSpot,
spots[i].posLoc,
spots[i].pos,
ShaderUniformDataType.Vec2
);
}
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.DarkBlue);
// Draw stars and bobs
for (int n = 0; n < MaxStars; n++)
{
// MathF.Single pixel is just too small these days!
DrawRectangle((int)stars[n].pos.X, (int)stars[n].pos.Y, 2, 2, Color.White);
}
for (int i = 0; i < 16; i++)
{
DrawTexture(
texRay,
(int)((screenWidth / 2.0) + MathF.Cos((frameCounter + i * 8) / 51.45f) * (screenWidth / 2.2) - 32),
(int)((screenHeight / 2.0) + MathF.Sin((frameCounter + i * 8) / 17.87f) * (screenHeight / 4.2)),
Color.White
);
}
// Draw spot lights
BeginShaderMode(shdrSpot);
// Instead of a blank rectangle you could render a render texture of the full screen used to do screen
// scaling (slight adjustment to shader would be required to actually pay attention to the colour!)
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
EndShaderMode();
DrawFPS(10, 10);
DrawText("Move the mouse!", 10, 30, 20, Color.Green);
DrawText("Pitch Color.Black", (int)(screenWidth * 0.2f), screenHeight / 2, 20, Color.Green);
DrawText("Dark", (int)(screenWidth * 0.66f), screenHeight / 2, 20, Color.Green);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadTexture(texRay);
UnloadShader(shdrSpot);
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}
static void ResetStar(ref Star s)
public void Update()
{
// Update
//----------------------------------------------------------------------------------
frameCounter++;
// Move the stars, resetting them if the go offscreen
for (var n = 0; n < MaxStars; n++)
{
UpdateStar(ref stars[n]);
}
// Update the spots, send them to the shader
for (var i = 0; i < MaxSpots; i++)
{
if (i == 0)
{
var mp = GetMousePosition();
spots[i].pos.X = mp.X;
spots[i].pos.Y = screenHeight - mp.Y;
}
else
{
spots[i].pos.X += spots[i].vel.X;
spots[i].pos.Y += spots[i].vel.Y;
if (spots[i].pos.X < 64)
{
spots[i].vel.X = -spots[i].vel.X;
}
if (spots[i].pos.X > (screenWidth - 64))
{
spots[i].vel.X = -spots[i].vel.X;
}
if (spots[i].pos.Y < 64)
{
spots[i].vel.Y = -spots[i].vel.Y;
}
if (spots[i].pos.Y > (screenHeight - 64))
{
spots[i].vel.Y = -spots[i].vel.Y;
}
}
Raylib.SetShaderValue(
shdrSpot,
spots[i].posLoc,
spots[i].pos,
ShaderUniformDataType.Vec2
);
}
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.DarkBlue);
// Draw stars and bobs
for (var n = 0; n < MaxStars; n++)
{
// Single pixel is just too small these days!
DrawRectangle((int)stars[n].pos.X, (int)stars[n].pos.Y, 2, 2, Color.White);
}
for (var i = 0; i < 16; i++)
{
DrawTexture(
texRay,
(int)((screenWidth / 2.0) + MathF.Cos((frameCounter + i * 8) / 51.45f) * (screenWidth / 2.2) - 32),
(int)((screenHeight / 2.0) + MathF.Sin((frameCounter + i * 8) / 17.87f) * (screenHeight / 4.2)),
Color.White
);
}
// Draw spot lights
BeginShaderMode(shdrSpot);
// Instead of a blank rectangle you could render a render texture of the full screen used to do screen
// scaling (slight adjustment to shader would be required to actually pay attention to the colour!)
DrawRectangle(0, 0, screenWidth, screenHeight, Color.White);
EndShaderMode();
DrawFPS(10, 10);
DrawText("Move the mouse!", 10, 30, 20, Color.Green);
DrawText("Pitch Black", (int)(screenWidth * 0.2f), screenHeight / 2, 20, Color.Green);
DrawText("Dark", (int)(screenWidth * 0.66f), screenHeight / 2, 20, Color.Green);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadTexture(texRay);
UnloadShader(shdrSpot);
}
private static void ResetStar(ref Star s)
{
s.pos = new Vector2(GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f);
@ -270,10 +274,10 @@ public class Spotlight
s.vel.Y = (float)GetRandomValue(-1000, 1000) / 100.0f;
} while (!((MathF.Abs(s.vel.X) + (MathF.Abs(s.vel.Y)) > 1)));
s.pos += s.pos + (s.vel * new Vector2(8.0f, 8.0f));
s.pos += s.vel * new Vector2(8.0f, 8.0f);
}
static void UpdateStar(ref Star s)
private static void UpdateStar(ref Star s)
{
s.pos += s.vel;
@ -283,4 +287,33 @@ public class Spotlight
ResetStar(ref s);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - spotlight rendering");
HideCursor();
SetTargetFPS(60); // Set to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new Spotlight();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,84 +1,108 @@
/*******************************************************************************************
*
* raylib [textures] example - Texture drawing
* raylib [shaders] example - texture rendering
*
* This example illustrates how to draw on a blank texture using a shader
* Example complexity rating: [] 2/4
*
* This example has been created using raylib 2.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example originally created with raylib 2.0, last time updated with raylib 3.7
*
* Example contributed by Michał Ciesielski and reviewed by Ramon Santamaria (@raysan5)
* Example contributed by Michał Ciesielski (@ciessielski) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 Michał Ciesielski 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 Michał Ciesielski (@ciessielski) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Shaders;
public class TextureDrawing
public class TextureDrawing : IExample
{
const int GlslVersion = 330;
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 / Texture Drawing";
public string Title => "raylib [shaders] example - texture rendering";
private Texture2D texture;
private Shader shader;
private float time;
private int timeLoc;
public void Init()
{
var imBlank = GenImageColor(1024, 1024, Color.Blank);
texture = LoadTextureFromImage(imBlank); // Load blank texture to fill on shader
UnloadImage(imBlank);
// NOTE: Using GLSL 330 shader version, on OpenGL ES 2.0 use GLSL 100 shader version
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/cubes_panning.fs");
time = 0.0f;
timeLoc = GetShaderLocation(shader, "uTime");
Raylib.SetShaderValue(shader, timeLoc, time, ShaderUniformDataType.Float);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
time = (float)GetTime();
Raylib.SetShaderValue(shader, timeLoc, time, ShaderUniformDataType.Float);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginShaderMode(shader); // Enable our custom shader for next shapes/textures drawings
DrawTexture(texture, 0, 0, Color.White); // Drawing BLANK texture, all rendering magic happens on shader
EndShaderMode(); // Disable our custom shader, return to default shader
DrawText("BACKGROUND is PAINTED and ANIMATED on SHADER!", 10, 10, 20, Color.Maroon);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadShader(shader);
UnloadTexture(texture);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture rendering");
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture drawing");
// Load blank texture to fill on shader
Image imBlank = GenImageColor(1024, 1024, Color.Blank);
Texture2D texture = LoadTextureFromImage(imBlank);
UnloadImage(imBlank);
// NOTE: Using GLSL 330 shader version, on OpenGL ES 2.0 use GLSL 100 shader version
Shader shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/cubes_panning.fs");
float time = 0.0f;
int timeLoc = GetShaderLocation(shader, "uTime");
Raylib.SetShaderValue(shader, timeLoc, time, ShaderUniformDataType.Float);
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new TextureDrawing();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
time = (float)GetTime();
Raylib.SetShaderValue(shader, timeLoc, time, ShaderUniformDataType.Float);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Enable our custom shader for next shapes/textures drawings
BeginShaderMode(shader);
// Drawing blank texture, all magic happens on shader
DrawTexture(texture, 0, 0, Color.White);
// Disable our custom shader, return to default shader
EndShaderMode();
DrawText("BACKGROUND is PAINTED and ANIMATED on SHADER!", 10, 10, 20, Color.Maroon);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shader);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -1,48 +1,60 @@
/*******************************************************************************************
*
* raylib [textures] example - Texture drawing
* raylib [shaders] example - texture outline
*
* This example illustrates how to draw on a blank texture using a shader
* Example complexity rating: [] 3/4
*
* This example has been created using raylib 2.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* 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 contributed by Michał Ciesielski and reviewed by Ramon Santamaria (@raysan5)
* Example originally created with raylib 4.0, last time updated with raylib 4.0
*
* Copyright (c) 2019 Michał Ciesielski and Ramon Santamaria (@raysan5)
* Example contributed by Serenity Skiff (@GoldenThumbs) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2021-2025 Serenity Skiff (@GoldenThumbs) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Shaders;
public class TextureOutline
public class TextureOutline : IExample
{
const int GLSL_VERSION = 330;
private const int screenWidth = 800;
private const int screenHeight = 450;
public 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 / Texture Outline";
public string Title => "raylib [shaders] example - texture outline";
private Texture2D texture;
private Shader shdrOutline;
private float outlineSize;
private int outlineSizeLoc;
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
texture = LoadTexture("resources/fudesumi.png");
shdrOutline = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/outline.fs");
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - Apply an outline to a texture");
outlineSize = 2.0f;
Texture2D texture = LoadTexture("resources/fudesumi.png");
Shader shdrOutline = LoadShader(null, $"resources/shaders/glsl{GLSL_VERSION}/outline.fs");
float outlineSize = 2.0f;
// Normalized red color
float[] outlineColor = new[] { 1.0f, 0.0f, 0.0f, 1.0f };
// Normalized RED color
var outlineColor = new[] { 1.0f, 0.0f, 0.0f, 1.0f };
float[] textureSize = { (float)texture.Width, (float)texture.Height };
// Get shader locations
int outlineSizeLoc = GetShaderLocation(shdrOutline, "outlineSize");
int outlineColorLoc = GetShaderLocation(shdrOutline, "outlineColor");
int textureSizeLoc = GetShaderLocation(shdrOutline, "textureSize");
outlineSizeLoc = GetShaderLocation(shdrOutline, "outlineSize");
var outlineColorLoc = GetShaderLocation(shdrOutline, "outlineColor");
var textureSizeLoc = GetShaderLocation(shdrOutline, "textureSize");
// Set shader values (they can be changed later)
Raylib.SetShaderValue(
@ -63,55 +75,75 @@ public class TextureOutline
textureSize,
ShaderUniformDataType.Vec2
);
}
SetTargetFPS(60);
public void Update()
{
// Update
//----------------------------------------------------------------------------------
outlineSize += GetMouseWheelMove();
if (outlineSize < 1.0f)
{
outlineSize = 1.0f;
}
Raylib.SetShaderValue(
shdrOutline,
outlineSizeLoc,
outlineSize,
ShaderUniformDataType.Float
);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginShaderMode(shdrOutline);
DrawTexture(texture, GetScreenWidth() / 2 - texture.Width / 2, -30, Color.White);
EndShaderMode();
DrawText("Shader-based\ntexture\noutline", 10, 10, 20, Color.Gray);
DrawText("Scroll mouse wheel to\nchange outline size", 10, 72, 20, Color.Gray);
DrawText($"Outline size: {(int)outlineSize} px", 10, 120, 20, Color.Maroon);
DrawFPS(710, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadTexture(texture);
UnloadShader(shdrOutline);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture outline");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new TextureOutline();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
outlineSize += GetMouseWheelMove();
if (outlineSize < 1.0f)
{
outlineSize = 1.0f;
}
Raylib.SetShaderValue(
shdrOutline,
outlineSizeLoc,
outlineSize,
ShaderUniformDataType.Float
);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginShaderMode(shdrOutline);
DrawTexture(texture, GetScreenWidth() / 2 - texture.Width / 2, -30, Color.White);
EndShaderMode();
DrawText("Shader-based\ntexture\noutline", 10, 10, 20, Color.Gray);
DrawText($"Outline size: {outlineSize} px", 10, 120, 20, Color.Maroon);
DrawFPS(710, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadTexture(texture);
UnloadShader(shdrOutline);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,140 @@
/*******************************************************************************************
*
* raylib [shaders] example - texture tiling
*
* Example complexity rating: [] 2/4
*
* Example demonstrates how to tile a texture on a 3D model using raylib
*
* Example originally created with raylib 4.5, last time updated with raylib 4.5
*
* Example contributed by Luis 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) 2023-2025 Luis Almeida (@luis605)
*
********************************************************************************************/
namespace Examples.Shaders;
public class TextureTiling : 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 / Texture Tiling";
public string Title => "raylib [shaders] example - texture tiling";
public bool CursorDisabled => true;
private Camera3D camera;
private Model model;
private Texture2D texture;
private Shader shader;
public unsafe void Init()
{
// Define the camera to look into our 3d world
camera = new();
camera.Position = new Vector3(4.0f, 4.0f, 4.0f); // Camera position
camera.Target = new Vector3(0.0f, 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 a cube model
var cube = GenMeshCube(1.0f, 1.0f, 1.0f);
model = LoadModelFromMesh(cube);
// Load a texture and assign to cube model
texture = LoadTexture("resources/cubicmap_atlas.png");
model.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = texture;
// Set the texture tiling using a shader
var tiling = new[] { 3.0f, 3.0f };
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/tiling.fs");
SetTextureWrap(texture, TextureWrap.Repeat);
Raylib.SetShaderValue(shader, GetShaderLocation(shader, "tiling"), tiling, ShaderUniformDataType.Vec2);
model.Materials[0].Shader = shader;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Free);
if (IsKeyPressed(KeyboardKey.Z))
{
camera.Target = new Vector3(0.0f, 0.5f, 0.0f);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
BeginShaderMode(shader);
DrawModel(model, new Vector3(0.0f, 0.0f, 0.0f), 2.0f, Color.White);
EndShaderMode();
DrawGrid(10, 1.0f);
EndMode3D();
DrawText("Use mouse to rotate the camera", 10, 10, 20, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadModel(model); // Unload model
UnloadShader(shader); // Unload shader
UnloadTexture(texture); // Unload texture
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture tiling");
DisableCursor(); // Limit cursor to relative movement inside the window
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new TextureTiling();
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;
}
}

View file

@ -1,61 +1,72 @@
/*******************************************************************************************
*
* raylib [shaders] example - Texture Waves
* raylib [shaders] example - texture waves
*
* 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 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 Anata (@anatagawa) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 Anata (@anatagawa) 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 Anata (@anatagawa) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Shaders;
public class TextureWaves
public class TextureWaves : IExample
{
const int GlslVersion = 330;
private const int screenWidth = 800;
private const int screenHeight = 450;
public 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 / Texture Waves";
public string Title => "raylib [shaders] example - texture waves";
private Texture2D texture;
private Shader shader;
private int secondsLoc;
private float seconds;
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture waves");
// Load texture texture to apply shaders
Texture2D texture = LoadTexture("resources/space.png");
texture = LoadTexture("resources/space.png");
// Load shader and setup location points and values
Shader shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/wave.fs");
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/wave.fs");
int secondsLoc = GetShaderLocation(shader, "secondes");
int freqXLoc = GetShaderLocation(shader, "freqX");
int freqYLoc = GetShaderLocation(shader, "freqY");
int ampXLoc = GetShaderLocation(shader, "ampX");
int ampYLoc = GetShaderLocation(shader, "ampY");
int speedXLoc = GetShaderLocation(shader, "speedX");
int speedYLoc = GetShaderLocation(shader, "speedY");
secondsLoc = GetShaderLocation(shader, "seconds");
var freqXLoc = GetShaderLocation(shader, "freqX");
var freqYLoc = GetShaderLocation(shader, "freqY");
var ampXLoc = GetShaderLocation(shader, "ampX");
var ampYLoc = GetShaderLocation(shader, "ampY");
var speedXLoc = GetShaderLocation(shader, "speedX");
var speedYLoc = GetShaderLocation(shader, "speedY");
// Shader uniform values that can be updated at any time
float freqX = 25.0f;
float freqY = 25.0f;
float ampX = 5.0f;
float ampY = 5.0f;
float speedX = 8.0f;
float speedY = 8.0f;
var freqX = 25.0f;
var freqY = 25.0f;
var ampX = 5.0f;
var ampY = 5.0f;
var speedX = 8.0f;
var speedY = 8.0f;
float[] screenSize = { (float)GetScreenWidth(), (float)GetScreenHeight() };
Raylib.SetShaderValue(
@ -71,43 +82,63 @@ public class TextureWaves
Raylib.SetShaderValue(shader, speedXLoc, speedX, ShaderUniformDataType.Float);
Raylib.SetShaderValue(shader, speedYLoc, speedY, ShaderUniformDataType.Float);
float seconds = 0.0f;
seconds = 0.0f;
}
SetTargetFPS(60);
public void Update()
{
// Update
//----------------------------------------------------------------------------------
seconds += GetFrameTime();
Raylib.SetShaderValue(shader, secondsLoc, seconds, ShaderUniformDataType.Float);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginShaderMode(shader);
DrawTexture(texture, 0, 0, Color.White);
DrawTexture(texture, texture.Width, 0, Color.White);
EndShaderMode();
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadShader(shader); // Unload shader
UnloadTexture(texture); // Unload texture
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - texture waves");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new TextureWaves();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
seconds += GetFrameTime();
Raylib.SetShaderValue(shader, secondsLoc, seconds, ShaderUniformDataType.Float);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginShaderMode(shader);
DrawTexture(texture, 0, 0, Color.White);
DrawTexture(texture, texture.Width, 0, Color.White);
EndShaderMode();
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shader);
UnloadTexture(texture);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,146 @@
/*******************************************************************************************
*
* raylib [shaders] example - vertex displacement
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.0, last time updated with raylib 4.5
*
* Example contributed by Alex ZH (@ZzzhHe) 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 Alex ZH (@ZzzhHe)
*
********************************************************************************************/
using static Raylib_cs.Rlgl;
namespace Examples.Shaders;
public partial class VertexDisplacement : 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 / Vertex Displacement";
public string Title => "raylib [shaders] example - vertex displacement";
private Camera3D camera;
private Shader shader;
private Texture2D perlinNoiseMap;
private Model planeModel;
private float time;
public unsafe void Init()
{
// set up camera
camera = new();
camera.Position = new Vector3(20.0f, 5.0f, -20.0f);
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 60.0f;
camera.Projection = CameraProjection.Perspective;
// Load vertex and fragment shaders
shader = LoadShader(
$"resources/shaders/glsl{GlslVersion}/vertex_displacement.vs",
$"resources/shaders/glsl{GlslVersion}/vertex_displacement.fs"
);
// Load perlin noise texture
var perlinNoiseImage = GenImagePerlinNoise(512, 512, 0, 0, 1.0f);
perlinNoiseMap = LoadTextureFromImage(perlinNoiseImage);
UnloadImage(perlinNoiseImage);
// Set shader uniform location
var perlinNoiseMapLoc = GetShaderLocation(shader, "perlinNoiseMap");
EnableShader(shader.Id);
ActiveTextureSlot(1);
EnableTexture(perlinNoiseMap.Id);
SetUniformSampler(perlinNoiseMapLoc, 1);
// Create a plane mesh and model
var planeMesh = GenMeshPlane(50, 50, 50, 50);
planeModel = LoadModelFromMesh(planeMesh);
// Set plane model material
var materials = planeModel.Materials;
materials[0].Shader = shader;
time = 0.0f;
}
public unsafe void Update()
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Free); // Update camera
time += GetFrameTime(); // Update time variable
Raylib.SetShaderValue(shader, GetShaderLocation(shader, "time"), time, ShaderUniformDataType.Float); // Send time value to shader
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
BeginShaderMode(shader);
// Draw plane model
DrawModel(planeModel, new Vector3(0.0f, 0.0f, 0.0f), 1.0f, new Color(255, 255, 255, 255));
EndShaderMode();
EndMode3D();
DrawText("Vertex displacement", 10, 10, 20, Color.DarkGray);
DrawFPS(10, 40);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadShader(shader);
UnloadModel(planeModel);
UnloadTexture(perlinNoiseMap);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - vertex displacement");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new VertexDisplacement();
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;
}
}

View file

@ -1,6 +1,8 @@
/*******************************************************************************************
*
* raylib [shaders] example - Depth buffer writing
* raylib [shaders] example - depth writing
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 4.2, last time updated with raylib 4.2
*
@ -9,95 +11,121 @@
* 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)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shaders;
public class WriteDepth
public class WriteDepth : IExample
{
const int GLSL_VERSION = 330;
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 / Write Depth";
public string Title => "raylib [shaders] example - depth writing";
private Camera3D camera;
private RenderTexture2D target;
private Shader shader;
public void Init()
{
// Define the camera to look into our 3d world
camera = new();
camera.Position = new Vector3(2.0f, 2.0f, 3.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 custom render texture with writable depth texture buffer
target = LoadRenderTextureDepthTex(screenWidth, screenHeight);
// Load depth writing shader
// NOTE: The shader inverts the depth buffer by writing into it by `gl_FragDepth = 1 - gl_FragCoord.z;`
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/depth_write.fs");
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Orbital);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// Draw into our custom render texture
BeginTextureMode(target);
ClearBackground(Color.White);
BeginMode3D(camera);
BeginShaderMode(shader);
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 into screen our 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(shader);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - depth writing");
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - write depth buffer");
// The shader inverts the depth buffer by writing into it by `gl_FragDepth = 1 - gl_FragCoord.z;`
Shader shader = LoadShader(null, $"resources/shaders/glsl{GLSL_VERSION}/write_depth.fs");
// Use customized function to create writable depth texture buffer
RenderTexture2D target = LoadRenderTextureDepthTex(screenWidth, screenHeight);
// Define the camera to look into our 3d world
Camera3D camera;
camera.Position = new Vector3(2.0f, 2.0f, 3.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;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new WriteDepth();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Orbital);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// Draw into our custom render texture (framebuffer)
BeginTextureMode(target);
ClearBackground(Color.White);
BeginMode3D(camera);
BeginShaderMode(shader);
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(shader);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
@ -152,7 +180,7 @@ public class WriteDepth
);
// 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");
}