chore: clean recommit
This commit is contained in:
parent
8024c6ac40
commit
60ad2e7fb1
122 changed files with 23950 additions and 323 deletions
166
Examples/Shaders/AsciiRendering.cs
Normal file
166
Examples/Shaders/AsciiRendering.cs
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - ascii rendering
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Maicon Santana (@maiconpintoabreu) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 Maicon Santana (@maiconpintoabreu)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class AsciiRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Ascii Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - ascii rendering";
|
||||
|
||||
private Texture2D fudesumi;
|
||||
private Texture2D raysan;
|
||||
private Shader shader;
|
||||
private int resolutionLoc;
|
||||
private int fontSizeLoc;
|
||||
private float fontSize;
|
||||
private Vector2 circlePos;
|
||||
private float circleSpeed;
|
||||
private RenderTexture2D target;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Texture to test static drawing
|
||||
fudesumi = LoadTexture("resources/fudesumi.png");
|
||||
// Texture to test moving drawing
|
||||
raysan = LoadTexture("resources/raysan.png");
|
||||
|
||||
// Load shader to be used on postprocessing
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/ascii.fs");
|
||||
|
||||
// These locations are used to send data to the GPU
|
||||
resolutionLoc = GetShaderLocation(shader, "resolution");
|
||||
fontSizeLoc = GetShaderLocation(shader, "fontSize");
|
||||
|
||||
// Set the character size for the ASCII effect
|
||||
// Fontsize should be 9 or more
|
||||
fontSize = 9.0f;
|
||||
|
||||
// Send the updated values to the shader
|
||||
var resolution = new[] { (float)screenWidth, (float)screenHeight };
|
||||
Raylib.SetShaderValue(shader, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
|
||||
|
||||
circlePos = new Vector2(40.0f, screenHeight * 0.5f);
|
||||
circleSpeed = 1.0f;
|
||||
|
||||
// RenderTexture to apply the postprocessing later
|
||||
target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
circlePos.X += circleSpeed;
|
||||
if ((circlePos.X > 200.0f) || (circlePos.X < 40.0f))
|
||||
{
|
||||
circleSpeed *= -1; // Revert speed
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Left) && (fontSize > 9.0))
|
||||
{
|
||||
fontSize -= 1; // Reduce fontSize
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Right) && (fontSize < 15.0))
|
||||
{
|
||||
fontSize += 1; // Increase fontSize
|
||||
}
|
||||
|
||||
// Set fontsize for the shader
|
||||
Raylib.SetShaderValue(shader, fontSizeLoc, fontSize, ShaderUniformDataType.Float);
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.White);
|
||||
|
||||
// Draw scene in our render texture
|
||||
DrawTexture(fudesumi, 500, -30, Color.White);
|
||||
DrawTextureV(raysan, circlePos, Color.White);
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginShaderMode(shader);
|
||||
// Draw the scene texture (that we rendered earlier) to the screen
|
||||
// The shader will process every pixel of this texture
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, target.Texture.Width, -target.Texture.Height),
|
||||
new Vector2(0, 0),
|
||||
Color.White
|
||||
);
|
||||
EndShaderMode();
|
||||
|
||||
DrawRectangle(0, 0, screenWidth, 40, Color.Black);
|
||||
DrawText($"Ascii effect - FontSize:{fontSize,2:F0} - [Left] -1 [Right] +1 ", 120, 10, 20, Color.LightGray);
|
||||
DrawFPS(10, 10);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTexture(target); // Unload render texture
|
||||
|
||||
UnloadShader(shader); // Unload shader
|
||||
UnloadTexture(fudesumi); // Unload texture
|
||||
UnloadTexture(raysan); // Unload texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - ascii rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AsciiRendering();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
252
Examples/Shaders/CelShading.cs
Normal file
252
Examples/Shaders/CelShading.cs
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - cel shading
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* Example contributed by Gleb A (@ggrizzly) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2026 Gleb A (@ggrizzly)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
using static Raylib_cs.Rlgl;
|
||||
using Examples.Shared;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class CelShading : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxLights = 4;
|
||||
|
||||
// rlgl cull face modes (rlgl.h: RL_CULL_FACE_FRONT = 0, RL_CULL_FACE_BACK = 1)
|
||||
private const int CullFaceFront = 0;
|
||||
private const int CullFaceBack = 1;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Cel Shading";
|
||||
|
||||
public string Title => "raylib [shaders] example - cel shading";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Shader celShader;
|
||||
private Shader defaultShader;
|
||||
private Shader outlineShader;
|
||||
private float numBands;
|
||||
private int numBandsLoc;
|
||||
private int outlineThicknessLoc;
|
||||
private Light[] lights;
|
||||
private bool celEnabled;
|
||||
private bool outlineEnabled;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
camera = new();
|
||||
camera.Position = new Vector3(9.0f, 6.0f, 9.0f);
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/old_car_new.glb");
|
||||
|
||||
// Load cel shader
|
||||
celShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/cel.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/cel.fs"
|
||||
);
|
||||
celShader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(celShader, "viewPos");
|
||||
|
||||
// Apply cel shader to model, keep copy of default shader
|
||||
defaultShader = model.Materials[0].Shader;
|
||||
model.Materials[0].Shader = celShader;
|
||||
|
||||
// numBands: controls toon quantization steps (2 = hard binary, 20 = near-smooth)
|
||||
numBands = 10.0f;
|
||||
numBandsLoc = GetShaderLocation(celShader, "numBands");
|
||||
Raylib.SetShaderValue(celShader, numBandsLoc, numBands, ShaderUniformDataType.Float);
|
||||
|
||||
// Inverted-hull outline shader: draws back faces extruded along normals
|
||||
outlineShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/outline_hull.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/outline_hull.fs"
|
||||
);
|
||||
outlineThicknessLoc = GetShaderLocation(outlineShader, "outlineThickness");
|
||||
|
||||
// Single directional white light, angled so toon bands are visible on the model sides.
|
||||
// Spins opposite to CAMERA_ORBITAL (0.5 rad/s) so lighting changes as you watch.
|
||||
lights = new Light[MaxLights];
|
||||
lights[0] = Rlights.CreateLight(
|
||||
0,
|
||||
LightType.Directorional,
|
||||
new Vector3(50.0f, 50.0f, 50.0f),
|
||||
Vector3.Zero,
|
||||
Color.White,
|
||||
celShader
|
||||
);
|
||||
|
||||
celEnabled = true;
|
||||
outlineEnabled = true;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
Raylib.SetShaderValue(
|
||||
celShader,
|
||||
celShader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
// [Z] Toggle cel shading on/off
|
||||
if (IsKeyPressed(KeyboardKey.Z))
|
||||
{
|
||||
celEnabled = !celEnabled;
|
||||
if (celEnabled)
|
||||
{
|
||||
model.Materials[0].Shader = celShader; // Apply cel shader to model
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Materials[0].Shader = defaultShader; // Apply default shader to model
|
||||
}
|
||||
}
|
||||
|
||||
// [C] Toggle outline on/off
|
||||
if (IsKeyPressed(KeyboardKey.C))
|
||||
{
|
||||
outlineEnabled = !outlineEnabled;
|
||||
}
|
||||
|
||||
// [Q/E] Decrease/increase toon band count (press or hold to repeat)
|
||||
if (IsKeyPressed(KeyboardKey.E) || IsKeyPressedRepeat(KeyboardKey.E))
|
||||
{
|
||||
numBands = Clamp(numBands + 1.0f, 2.0f, 20.0f);
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Q) || IsKeyPressedRepeat(KeyboardKey.Q))
|
||||
{
|
||||
numBands = Clamp(numBands - 1.0f, 2.0f, 20.0f);
|
||||
}
|
||||
Raylib.SetShaderValue(celShader, numBandsLoc, numBands, ShaderUniformDataType.Float);
|
||||
|
||||
// Spin light opposite to CAMERA_ORBITAL (0.5 rad/s), angled 45 degrees off vertical
|
||||
float t = (float)GetTime();
|
||||
lights[0].Position = new Vector3(MathF.Sin(-t * 0.3f) * 5.0f, 5.0f, MathF.Cos(-t * 0.3f) * 5.0f);
|
||||
|
||||
for (var i = 0; i < MaxLights; i++)
|
||||
{
|
||||
Rlights.UpdateLightValues(celShader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
if (outlineEnabled)
|
||||
{
|
||||
// Outline pass: cull front faces, draw extruded back faces as silhouette
|
||||
float thickness = 0.005f;
|
||||
Raylib.SetShaderValue(outlineShader, outlineThicknessLoc, thickness, ShaderUniformDataType.Float);
|
||||
|
||||
SetCullFace(CullFaceFront);
|
||||
|
||||
model.Materials[0].Shader = outlineShader;
|
||||
|
||||
DrawModel(model, Vector3.Zero, 0.75f, Color.White);
|
||||
|
||||
if (celEnabled)
|
||||
{
|
||||
model.Materials[0].Shader = celShader; // Apply cel shader to model
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Materials[0].Shader = defaultShader; // Apply default shader to model
|
||||
}
|
||||
|
||||
SetCullFace(CullFaceBack);
|
||||
}
|
||||
|
||||
DrawModel(model, Vector3.Zero, 0.75f, Color.White);
|
||||
DrawSphereEx(lights[0].Position, 0.2f, 50, 50, Color.Yellow); // Light position indicator
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
DrawText($"Cel: {(celEnabled ? "ON" : "OFF")} [Z]", 10, 65, 20, celEnabled ? Color.DarkGreen : Color.DarkGray);
|
||||
DrawText($"Outline: {(outlineEnabled ? "ON" : "OFF")} [C]", 10, 90, 20, outlineEnabled ? Color.DarkGreen : Color.DarkGray);
|
||||
DrawText($"Bands: {numBands:0} [Q/E]", 10, 115, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(model);
|
||||
UnloadShader(celShader);
|
||||
UnloadShader(outlineShader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - cel shading");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new CelShading();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
184
Examples/Shaders/ColorCorrection.cs
Normal file
184
Examples/Shaders/ColorCorrection.cs
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - color correction
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 Jordi Santonja (@JordSant)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class ColorCorrection : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
private const int MaxTextures = 4;
|
||||
|
||||
public string Name => "Shaders / Color Correction";
|
||||
|
||||
public string Title => "raylib [shaders] example - color correction";
|
||||
|
||||
private Texture2D[] texture;
|
||||
private Shader shdrColorCorrection;
|
||||
private int imageIndex;
|
||||
private int resetButtonClicked;
|
||||
private float contrast;
|
||||
private float saturation;
|
||||
private float brightness;
|
||||
private int contrastLoc;
|
||||
private int saturationLoc;
|
||||
private int brightnessLoc;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
texture = new[]
|
||||
{
|
||||
LoadTexture("resources/parrots.png"),
|
||||
LoadTexture("resources/cat.png"),
|
||||
LoadTexture("resources/mandrill.png"),
|
||||
LoadTexture("resources/fudesumi.png")
|
||||
};
|
||||
|
||||
shdrColorCorrection = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/color_correction.fs");
|
||||
|
||||
imageIndex = 0;
|
||||
resetButtonClicked = 0;
|
||||
|
||||
contrast = 0.0f;
|
||||
saturation = 0.0f;
|
||||
brightness = 0.0f;
|
||||
|
||||
// Get shader locations
|
||||
contrastLoc = GetShaderLocation(shdrColorCorrection, "contrast");
|
||||
saturationLoc = GetShaderLocation(shdrColorCorrection, "saturation");
|
||||
brightnessLoc = GetShaderLocation(shdrColorCorrection, "brightness");
|
||||
|
||||
// Set shader values (they can be changed later)
|
||||
Raylib.SetShaderValue(shdrColorCorrection, contrastLoc, contrast, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shdrColorCorrection, saturationLoc, saturation, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shdrColorCorrection, brightnessLoc, brightness, ShaderUniformDataType.Float);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Select texture to draw
|
||||
if (IsKeyPressed(KeyboardKey.One)) imageIndex = 0;
|
||||
else if (IsKeyPressed(KeyboardKey.Two)) imageIndex = 1;
|
||||
else if (IsKeyPressed(KeyboardKey.Three)) imageIndex = 2;
|
||||
else if (IsKeyPressed(KeyboardKey.Four)) imageIndex = 3;
|
||||
|
||||
// Reset values to 0
|
||||
if (IsKeyPressed(KeyboardKey.R) || resetButtonClicked != 0)
|
||||
{
|
||||
contrast = 0.0f;
|
||||
saturation = 0.0f;
|
||||
brightness = 0.0f;
|
||||
}
|
||||
|
||||
// Send the values to the shader
|
||||
Raylib.SetShaderValue(shdrColorCorrection, contrastLoc, contrast, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shdrColorCorrection, saturationLoc, saturation, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shdrColorCorrection, brightnessLoc, brightness, ShaderUniformDataType.Float);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginShaderMode(shdrColorCorrection);
|
||||
|
||||
DrawTexture(texture[imageIndex], 580 / 2 - texture[imageIndex].Width / 2, GetScreenHeight() / 2 - texture[imageIndex].Height / 2, Color.White);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
DrawLine(580, 0, 580, GetScreenHeight(), new Color(218, 218, 218, 255));
|
||||
DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), new Color(232, 232, 232, 255));
|
||||
|
||||
// Draw UI info text
|
||||
DrawText("Color Correction", 585, 40, 20, Color.Gray);
|
||||
|
||||
DrawText("Picture", 602, 75, 10, Color.Gray);
|
||||
DrawText("Press [1] - [4] to Change Picture", 600, 230, 8, Color.Gray);
|
||||
DrawText("Press [R] to Reset Values", 600, 250, 8, Color.Gray);
|
||||
|
||||
// Draw GUI controls
|
||||
//------------------------------------------------------------------------------
|
||||
// NOTE: raygui is not bound in raylib-cs; controls are kept for reference. Use
|
||||
// keyboard shortcuts ([1]-[4], [R]) to interact with the example.
|
||||
/*GuiToggleGroup(new Rectangle( 645, 70, 20, 20 ), "1;2;3;4", ref imageIndex);
|
||||
|
||||
GuiSliderBar(new Rectangle( 645, 100, 120, 20 ), "Contrast", TextFormat("%.0f", contrast), ref contrast, -100.0f, 100.0f);
|
||||
GuiSliderBar(new Rectangle( 645, 130, 120, 20 ), "Saturation", TextFormat("%.0f", saturation), ref saturation, -100.0f, 100.0f);
|
||||
GuiSliderBar(new Rectangle( 645, 160, 120, 20 ), "Brightness", TextFormat("%.0f", brightness), ref brightness, -100.0f, 100.0f);
|
||||
|
||||
resetButtonClicked = GuiButton(new Rectangle( 645, 190, 40, 20 ), "Reset");*/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DrawFPS(710, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
for (var i = 0; i < MaxTextures; i++)
|
||||
{
|
||||
UnloadTexture(texture[i]);
|
||||
}
|
||||
UnloadShader(shdrColorCorrection);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - color correction");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ColorCorrection();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
400
Examples/Shaders/DeferredRendering.cs
Normal file
400
Examples/Shaders/DeferredRendering.cs
Normal file
|
|
@ -0,0 +1,400 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - deferred rendering
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or OpenGL ES 3.0
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by Justin Andreas Lacoste (@27justin) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2023-2025 Justin Andreas Lacoste (@27justin)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using Examples.Shared;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
[ExcludeFromBrowser("multiple-render-target G-buffer, unsupported on WebGL1/GLSL100")]
|
||||
public partial class DeferredRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
private const int MaxCubes = 30;
|
||||
private const int MaxLights = 4;
|
||||
private const float CubeScale = 0.25f;
|
||||
|
||||
// GL_READ_FRAMEBUFFER / GL_DRAW_FRAMEBUFFER / GL_DEPTH_BUFFER_BIT
|
||||
private const uint RlReadFramebuffer = 0x8CA8;
|
||||
private const uint RlDrawFramebuffer = 0x8CA9;
|
||||
private const int GlDepthBufferBit = 0x00000100;
|
||||
|
||||
public string Name => "Shaders / Deferred Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - deferred rendering";
|
||||
|
||||
// GBuffer data
|
||||
private struct GBuffer
|
||||
{
|
||||
public uint FramebufferId;
|
||||
|
||||
public uint PositionTextureId;
|
||||
public uint NormalTextureId;
|
||||
public uint AlbedoSpecTextureId;
|
||||
|
||||
public uint DepthRenderbufferId;
|
||||
}
|
||||
|
||||
// Deferred mode passes
|
||||
private enum DeferredMode
|
||||
{
|
||||
Position,
|
||||
Normal,
|
||||
Albedo,
|
||||
Shading
|
||||
}
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Model cube;
|
||||
private Shader gbufferShader;
|
||||
private Shader deferredShader;
|
||||
private GBuffer gBuffer;
|
||||
private Light[] lights;
|
||||
private Vector3[] cubePositions;
|
||||
private float[] cubeRotations;
|
||||
private DeferredMode mode;
|
||||
|
||||
// Texture units our g-buffer textures are bound to
|
||||
private const int TexUnitPosition = 0;
|
||||
private const int TexUnitNormal = 1;
|
||||
private const int TexUnitAlbedoSpec = 2;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 4.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 60.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load plane model from a generated mesh
|
||||
model = LoadModelFromMesh(GenMeshPlane(10.0f, 10.0f, 3, 3));
|
||||
cube = LoadModelFromMesh(GenMeshCube(2.0f, 2.0f, 2.0f));
|
||||
|
||||
// Load geometry buffer (G-buffer) shader and deferred shader
|
||||
gbufferShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/gbuffer.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/gbuffer.fs"
|
||||
);
|
||||
|
||||
deferredShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/deferred_shading.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/deferred_shading.fs"
|
||||
);
|
||||
deferredShader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(deferredShader, "viewPosition");
|
||||
|
||||
// Initialize the G-buffer
|
||||
gBuffer = new();
|
||||
gBuffer.FramebufferId = Rlgl.LoadFramebuffer();
|
||||
if (gBuffer.FramebufferId == 0)
|
||||
{
|
||||
TraceLog(TraceLogLevel.Warning, "Failed to create framebufferId");
|
||||
}
|
||||
|
||||
Rlgl.EnableFramebuffer(gBuffer.FramebufferId);
|
||||
|
||||
// NOTE: Vertex positions are stored in a texture for simplicity. A better approach would use a depth texture
|
||||
// (instead of a detph renderbuffer) to reconstruct world positions in the final render shader via clip-space position,
|
||||
// depth, and the inverse view/projection matrices
|
||||
|
||||
// 16-bit precision ensures OpenGL ES 3 compatibility, though it may lack precision for real scenarios
|
||||
gBuffer.PositionTextureId = Rlgl.LoadTexture(null, screenWidth, screenHeight, PixelFormat.UncompressedR16G16B16, 1);
|
||||
|
||||
// Similarly, 16-bit precision is used for normals ensures OpenGL ES 3 compatibility
|
||||
gBuffer.NormalTextureId = Rlgl.LoadTexture(null, screenWidth, screenHeight, PixelFormat.UncompressedR16G16B16, 1);
|
||||
|
||||
// Albedo (diffuse color) and specular strength can be combined into one texture
|
||||
// The color in RGB, and the specular strength in the alpha channel
|
||||
gBuffer.AlbedoSpecTextureId = Rlgl.LoadTexture(null, screenWidth, screenHeight, PixelFormat.UncompressedR8G8B8A8, 1);
|
||||
|
||||
// Activate the draw buffers for our framebufferId
|
||||
Rlgl.ActiveDrawBuffers(3);
|
||||
|
||||
// Now we attach our textures to the framebufferId
|
||||
Rlgl.FramebufferAttach(gBuffer.FramebufferId, gBuffer.PositionTextureId, FramebufferAttachType.ColorChannel0, FramebufferAttachTextureType.Texture2D, 0);
|
||||
Rlgl.FramebufferAttach(gBuffer.FramebufferId, gBuffer.NormalTextureId, FramebufferAttachType.ColorChannel1, FramebufferAttachTextureType.Texture2D, 0);
|
||||
Rlgl.FramebufferAttach(gBuffer.FramebufferId, gBuffer.AlbedoSpecTextureId, FramebufferAttachType.ColorChannel2, FramebufferAttachTextureType.Texture2D, 0);
|
||||
|
||||
// Finally we attach the depth buffer
|
||||
gBuffer.DepthRenderbufferId = Rlgl.LoadTextureDepth(screenWidth, screenHeight, true);
|
||||
Rlgl.FramebufferAttach(gBuffer.FramebufferId, gBuffer.DepthRenderbufferId, FramebufferAttachType.Depth, FramebufferAttachTextureType.Renderbuffer, 0);
|
||||
|
||||
// Make sure our framebufferId is complete
|
||||
// NOTE: rlFramebufferComplete() automatically unbinds the framebufferId, so we don't have to rlDisableFramebuffer() here
|
||||
if (Rlgl.FramebufferComplete(gBuffer.FramebufferId) == 0)
|
||||
{
|
||||
TraceLog(TraceLogLevel.Warning, "Framebuffer is not complete");
|
||||
}
|
||||
|
||||
// Now we initialize the sampler2D uniform's in the deferred shader
|
||||
// We do this by setting the uniform's values to the texture units that
|
||||
// we later bind our g-buffer textures to
|
||||
Rlgl.EnableShader(deferredShader.Id);
|
||||
int texUnitPosition = TexUnitPosition;
|
||||
int texUnitNormal = TexUnitNormal;
|
||||
int texUnitAlbedoSpec = TexUnitAlbedoSpec;
|
||||
Raylib.SetShaderValue(deferredShader, GetShaderLocation(deferredShader, "gPosition"), texUnitPosition, ShaderUniformDataType.Sampler2D);
|
||||
Raylib.SetShaderValue(deferredShader, GetShaderLocation(deferredShader, "gNormal"), texUnitNormal, ShaderUniformDataType.Sampler2D);
|
||||
Raylib.SetShaderValue(deferredShader, GetShaderLocation(deferredShader, "gAlbedoSpec"), texUnitAlbedoSpec, ShaderUniformDataType.Sampler2D);
|
||||
Rlgl.DisableShader();
|
||||
|
||||
// Assign out lighting shader to model
|
||||
model.Materials[0].Shader = gbufferShader;
|
||||
cube.Materials[0].Shader = gbufferShader;
|
||||
|
||||
// Create lights
|
||||
lights = new Light[MaxLights];
|
||||
lights[0] = Rlights.CreateLight(0, LightType.Point, new Vector3(-2, 1, -2), Vector3.Zero, Color.Yellow, deferredShader);
|
||||
lights[1] = Rlights.CreateLight(1, LightType.Point, new Vector3(2, 1, 2), Vector3.Zero, Color.Red, deferredShader);
|
||||
lights[2] = Rlights.CreateLight(2, LightType.Point, new Vector3(-2, 1, 2), Vector3.Zero, Color.Green, deferredShader);
|
||||
lights[3] = Rlights.CreateLight(3, LightType.Point, new Vector3(2, 1, -2), Vector3.Zero, Color.Blue, deferredShader);
|
||||
|
||||
var rand = new Random();
|
||||
cubePositions = new Vector3[MaxCubes];
|
||||
cubeRotations = new float[MaxCubes];
|
||||
|
||||
for (var i = 0; i < MaxCubes; i++)
|
||||
{
|
||||
cubePositions[i] = new Vector3(
|
||||
(float)(rand.Next() % 10) - 5,
|
||||
(float)(rand.Next() % 5),
|
||||
(float)(rand.Next() % 10) - 5
|
||||
);
|
||||
|
||||
cubeRotations[i] = (float)(rand.Next() % 360);
|
||||
}
|
||||
|
||||
mode = DeferredMode.Shading;
|
||||
|
||||
Rlgl.EnableDepthTest();
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
|
||||
Raylib.SetShaderValue(
|
||||
deferredShader,
|
||||
deferredShader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
// Check key inputs to enable/disable lights
|
||||
if (IsKeyPressed(KeyboardKey.Y)) { lights[0].Enabled = !lights[0].Enabled; }
|
||||
if (IsKeyPressed(KeyboardKey.R)) { lights[1].Enabled = !lights[1].Enabled; }
|
||||
if (IsKeyPressed(KeyboardKey.G)) { lights[2].Enabled = !lights[2].Enabled; }
|
||||
if (IsKeyPressed(KeyboardKey.B)) { lights[3].Enabled = !lights[3].Enabled; }
|
||||
|
||||
// Check key inputs to switch between G-buffer textures
|
||||
if (IsKeyPressed(KeyboardKey.One)) mode = DeferredMode.Position;
|
||||
if (IsKeyPressed(KeyboardKey.Two)) mode = DeferredMode.Normal;
|
||||
if (IsKeyPressed(KeyboardKey.Three)) mode = DeferredMode.Albedo;
|
||||
if (IsKeyPressed(KeyboardKey.Four)) mode = DeferredMode.Shading;
|
||||
|
||||
// Update light values (actually, only enable/disable them)
|
||||
for (var i = 0; i < MaxLights; i++) Rlights.UpdateLightValues(deferredShader, lights[i]);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
// Draw to the geometry buffer by first activating it
|
||||
Rlgl.EnableFramebuffer(gBuffer.FramebufferId);
|
||||
Rlgl.ClearColor(0, 0, 0, 0);
|
||||
Rlgl.ClearScreenBuffers(); // Clear color and depth buffer
|
||||
Rlgl.DisableColorBlend();
|
||||
|
||||
BeginMode3D(camera);
|
||||
// NOTE: We have to use rlEnableShader here. `BeginShaderMode` or thus `rlSetShader`
|
||||
// will not work, as they won't immediately load the shader program
|
||||
Rlgl.EnableShader(gbufferShader.Id);
|
||||
// When drawing a model here, make sure that the material's shaders are set to the gbuffer shader!
|
||||
DrawModel(model, Vector3.Zero, 1.0f, Color.White);
|
||||
DrawModel(cube, new Vector3(0.0f, 1.0f, 0.0f), 1.0f, Color.White);
|
||||
|
||||
for (var i = 0; i < MaxCubes; i++)
|
||||
{
|
||||
var position = cubePositions[i];
|
||||
DrawModelEx(cube, position, new Vector3(1, 1, 1), cubeRotations[i], new Vector3(CubeScale, CubeScale, CubeScale), Color.White);
|
||||
}
|
||||
Rlgl.DisableShader();
|
||||
EndMode3D();
|
||||
|
||||
Rlgl.EnableColorBlend();
|
||||
|
||||
// Go back to the default framebufferId (0) and draw our deferred shading
|
||||
Rlgl.DisableFramebuffer();
|
||||
Rlgl.ClearScreenBuffers(); // Clear color & depth buffer
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case DeferredMode.Shading:
|
||||
{
|
||||
BeginMode3D(camera);
|
||||
Rlgl.DisableColorBlend();
|
||||
Rlgl.EnableShader(deferredShader.Id);
|
||||
// Bind our g-buffer textures
|
||||
// We are binding them to locations that we earlier set in sampler2D uniforms `gPosition`, `gNormal`,
|
||||
// and `gAlbedoSpec`
|
||||
Rlgl.ActiveTextureSlot(TexUnitPosition);
|
||||
Rlgl.EnableTexture(gBuffer.PositionTextureId);
|
||||
Rlgl.ActiveTextureSlot(TexUnitNormal);
|
||||
Rlgl.EnableTexture(gBuffer.NormalTextureId);
|
||||
Rlgl.ActiveTextureSlot(TexUnitAlbedoSpec);
|
||||
Rlgl.EnableTexture(gBuffer.AlbedoSpecTextureId);
|
||||
|
||||
// Finally, we draw a fullscreen quad to our default framebufferId
|
||||
// This will now be shaded using our deferred shader
|
||||
Rlgl.LoadDrawQuad();
|
||||
Rlgl.DisableShader();
|
||||
Rlgl.EnableColorBlend();
|
||||
EndMode3D();
|
||||
|
||||
// As a last step, we now copy over the depth buffer from our g-buffer to the default framebufferId
|
||||
Rlgl.BindFramebuffer(RlReadFramebuffer, gBuffer.FramebufferId);
|
||||
Rlgl.BindFramebuffer(RlDrawFramebuffer, 0);
|
||||
Rlgl.BlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, GlDepthBufferBit);
|
||||
Rlgl.DisableFramebuffer();
|
||||
|
||||
// Since our shader is now done and disabled, we can draw spheres
|
||||
// that represent light positions in default forward rendering
|
||||
BeginMode3D(camera);
|
||||
Rlgl.EnableShader(Rlgl.GetShaderIdDefault());
|
||||
for (var i = 0; i < MaxLights; i++)
|
||||
{
|
||||
if (lights[i].Enabled) DrawSphereEx(lights[i].Position, 0.2f, 8, 8, lights[i].Color);
|
||||
else DrawSphereWires(lights[i].Position, 0.2f, 8, 8, ColorAlpha(lights[i].Color, 0.3f));
|
||||
}
|
||||
Rlgl.DisableShader();
|
||||
EndMode3D();
|
||||
|
||||
DrawText("FINAL RESULT", 10, screenHeight - 30, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
case DeferredMode.Position:
|
||||
{
|
||||
DrawTextureRec(
|
||||
new Texture2D { Id = gBuffer.PositionTextureId, Width = screenWidth, Height = screenHeight },
|
||||
new Rectangle(0, 0, screenWidth, -screenHeight),
|
||||
Vector2.Zero,
|
||||
Color.RayWhite
|
||||
);
|
||||
|
||||
DrawText("POSITION TEXTURE", 10, screenHeight - 30, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
case DeferredMode.Normal:
|
||||
{
|
||||
DrawTextureRec(
|
||||
new Texture2D { Id = gBuffer.NormalTextureId, Width = screenWidth, Height = screenHeight },
|
||||
new Rectangle(0, 0, screenWidth, -screenHeight),
|
||||
Vector2.Zero,
|
||||
Color.RayWhite
|
||||
);
|
||||
|
||||
DrawText("NORMAL TEXTURE", 10, screenHeight - 30, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
case DeferredMode.Albedo:
|
||||
{
|
||||
DrawTextureRec(
|
||||
new Texture2D { Id = gBuffer.AlbedoSpecTextureId, Width = screenWidth, Height = screenHeight },
|
||||
new Rectangle(0, 0, screenWidth, -screenHeight),
|
||||
Vector2.Zero,
|
||||
Color.RayWhite
|
||||
);
|
||||
|
||||
DrawText("ALBEDO TEXTURE", 10, screenHeight - 30, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
DrawText("Toggle lights keys: [Y][R][G][B]", 10, 40, 20, Color.DarkGray);
|
||||
DrawText("Switch G-buffer textures: [1][2][3][4]", 10, 70, 20, Color.DarkGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// Unload the models
|
||||
UnloadModel(model);
|
||||
UnloadModel(cube);
|
||||
|
||||
// Unload shaders
|
||||
UnloadShader(deferredShader);
|
||||
UnloadShader(gbufferShader);
|
||||
|
||||
// Unload geometry buffer and all attached textures
|
||||
Rlgl.UnloadFramebuffer(gBuffer.FramebufferId);
|
||||
Rlgl.UnloadTexture(gBuffer.PositionTextureId);
|
||||
Rlgl.UnloadTexture(gBuffer.NormalTextureId);
|
||||
Rlgl.UnloadTexture(gBuffer.AlbedoSpecTextureId);
|
||||
Rlgl.UnloadTexture(gBuffer.DepthRenderbufferId);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - deferred rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DeferredRendering();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
226
Examples/Shaders/DepthRendering.cs
Normal file
226
Examples/Shaders/DepthRendering.cs
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - depth rendering
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Luís Almeida (@luis605) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 Luís Almeida (@luis605)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class DepthRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Depth Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - depth rendering";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private RenderTexture2D target;
|
||||
private Shader depthShader;
|
||||
private int depthLoc;
|
||||
private Model cube;
|
||||
private Model floor;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(4.0f, 1.0f, 5.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load render texture with a depth texture attached
|
||||
target = LoadRenderTextureDepthTex(screenWidth, screenHeight);
|
||||
|
||||
// Load depth shader and get depth texture shader location
|
||||
depthShader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/depth_render.fs");
|
||||
depthLoc = GetShaderLocation(depthShader, "depthTexture");
|
||||
var flipTextureLoc = GetShaderLocation(depthShader, "flipY");
|
||||
Raylib.SetShaderValue(depthShader, flipTextureLoc, 1, ShaderUniformDataType.Int); // Flip Y texture
|
||||
|
||||
// Load scene models
|
||||
cube = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
|
||||
floor = LoadModelFromMesh(GenMeshPlane(20.0f, 20.0f, 1, 1));
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.White);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawModel(cube, new Vector3(0.0f, 0.0f, 0.0f), 3.0f, Color.Yellow);
|
||||
DrawModel(floor, new Vector3(10.0f, 0.0f, 2.0f), 2.0f, Color.Red);
|
||||
EndMode3D();
|
||||
EndTextureMode();
|
||||
|
||||
// Draw into screen (main framebuffer)
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginShaderMode(depthShader);
|
||||
SetShaderValueTexture(depthShader, depthLoc, target.Depth);
|
||||
DrawTexture(target.Depth, 0, 0, Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
DrawRectangle(10, 10, 320, 93, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 320, 93, Color.Blue);
|
||||
|
||||
DrawText("Camera Controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- WASD to move", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Z to zoom to (0, 0, 0)", 40, 80, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(cube); // Unload model
|
||||
UnloadModel(floor); // Unload model
|
||||
UnloadRenderTextureDepthTex(target);
|
||||
UnloadShader(depthShader); // Unload shader
|
||||
}
|
||||
|
||||
// Load custom render texture, create a writable depth texture buffer
|
||||
private static unsafe RenderTexture2D LoadRenderTextureDepthTex(int width, int height)
|
||||
{
|
||||
RenderTexture2D target = new();
|
||||
|
||||
// Load an empty framebuffer
|
||||
target.Id = Rlgl.LoadFramebuffer();
|
||||
|
||||
if (target.Id > 0)
|
||||
{
|
||||
Rlgl.EnableFramebuffer(target.Id);
|
||||
|
||||
// Create color texture (default to RGBA)
|
||||
target.Texture.Id = Rlgl.LoadTexture(
|
||||
null,
|
||||
width,
|
||||
height,
|
||||
PixelFormat.UncompressedR8G8B8A8,
|
||||
1
|
||||
);
|
||||
target.Texture.Width = width;
|
||||
target.Texture.Height = height;
|
||||
target.Texture.Format = PixelFormat.UncompressedR8G8B8A8;
|
||||
target.Texture.Mipmaps = 1;
|
||||
|
||||
// Create depth texture buffer (instead of raylib default renderbuffer)
|
||||
target.Depth.Id = Rlgl.LoadTextureDepth(width, height, false);
|
||||
target.Depth.Width = width;
|
||||
target.Depth.Height = height;
|
||||
target.Depth.Format = PixelFormat.CompressedPvrtRgba; // DEPTH_COMPONENT_24BIT: Not defined in raylib
|
||||
target.Depth.Mipmaps = 1;
|
||||
|
||||
// Attach color texture and depth texture to FBO
|
||||
Rlgl.FramebufferAttach(
|
||||
target.Id,
|
||||
target.Texture.Id,
|
||||
FramebufferAttachType.ColorChannel0,
|
||||
FramebufferAttachTextureType.Texture2D,
|
||||
0
|
||||
);
|
||||
Rlgl.FramebufferAttach(
|
||||
target.Id,
|
||||
target.Depth.Id,
|
||||
FramebufferAttachType.Depth,
|
||||
FramebufferAttachTextureType.Texture2D,
|
||||
0
|
||||
);
|
||||
|
||||
// Check if fbo is complete with attachments (valid)
|
||||
if (Rlgl.FramebufferComplete(target.Id) != 0)
|
||||
{
|
||||
TraceLog(TraceLogLevel.Info, $"FBO: [ID {target.Id}] Framebuffer object created successfully");
|
||||
}
|
||||
|
||||
Rlgl.DisableFramebuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLog(TraceLogLevel.Warning, "FBO: Framebuffer object can not be created");
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// Unload render texture from GPU memory (VRAM)
|
||||
private static void UnloadRenderTextureDepthTex(RenderTexture2D target)
|
||||
{
|
||||
if (target.Id > 0)
|
||||
{
|
||||
// Color texture attached to FBO is deleted
|
||||
Rlgl.UnloadTexture(target.Texture.Id);
|
||||
Rlgl.UnloadTexture(target.Depth.Id);
|
||||
|
||||
// NOTE: Depth texture is automatically
|
||||
// queried and deleted before deleting framebuffer
|
||||
Rlgl.UnloadFramebuffer(target.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - depth rendering");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DepthRendering();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
433
Examples/Shaders/GameOfLife.cs
Normal file
433
Examples/Shaders/GameOfLife.cs
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - game of life
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 Jordi Santonja (@JordSant)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class GameOfLife : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Game of Life";
|
||||
|
||||
public string Title => "raylib [shaders] example - game of life";
|
||||
|
||||
// Interaction mode
|
||||
private enum InteractionMode
|
||||
{
|
||||
Run = 0,
|
||||
Pause,
|
||||
Draw,
|
||||
}
|
||||
|
||||
// Struct to store example preset patterns
|
||||
private struct PresetPattern
|
||||
{
|
||||
public string Name;
|
||||
public Vector2 Position;
|
||||
|
||||
public PresetPattern(string name, Vector2 position)
|
||||
{
|
||||
Name = name;
|
||||
Position = position;
|
||||
}
|
||||
}
|
||||
|
||||
private const int menuWidth = 100;
|
||||
private const int windowWidth = screenWidth - menuWidth;
|
||||
private const int windowHeight = screenHeight;
|
||||
|
||||
private const int worldWidth = 2048;
|
||||
private const int worldHeight = 2048;
|
||||
|
||||
private const int randomTiles = 8; // Random preset: divide the world to compute random points in each tile
|
||||
|
||||
private static readonly PresetPattern[] presetPatterns =
|
||||
{
|
||||
new("Glider", new Vector2(0.5f, 0.5f)), new("R-pentomino", new Vector2(0.5f, 0.5f)), new("Acorn", new Vector2(0.5f, 0.5f)),
|
||||
new("Spaceships", new Vector2(0.1f, 0.5f)), new("Still lifes", new Vector2(0.5f, 0.5f)), new("Oscillators", new Vector2(0.5f, 0.5f)),
|
||||
new("Puffer train", new Vector2(0.1f, 0.5f)), new("Glider Gun", new Vector2(0.2f, 0.2f)), new("Breeder", new Vector2(0.1f, 0.5f)),
|
||||
new("Random", new Vector2(0.5f, 0.5f))
|
||||
};
|
||||
|
||||
private static readonly int numberOfPresets = presetPatterns.Length;
|
||||
|
||||
private Rectangle worldRectSource;
|
||||
private Rectangle worldRectDest;
|
||||
private Rectangle textureOnScreen;
|
||||
|
||||
private int zoom;
|
||||
private float offsetX;
|
||||
private float offsetY;
|
||||
private int framesPerStep;
|
||||
private int frame;
|
||||
|
||||
private int preset;
|
||||
private InteractionMode mode;
|
||||
private bool buttonZoomIn;
|
||||
private bool buttonZomOut;
|
||||
private bool buttonFaster;
|
||||
private bool buttonSlower;
|
||||
|
||||
private Shader shdrGameOfLife;
|
||||
private int resolutionLoc;
|
||||
|
||||
private RenderTexture2D world1;
|
||||
private RenderTexture2D world2;
|
||||
private RenderTexture2D currentWorld;
|
||||
private RenderTexture2D previousWorld;
|
||||
|
||||
// Image to be used in DRAW mode, to be changed with mouse input
|
||||
private Image imageToDraw;
|
||||
private bool imageToDrawValid;
|
||||
|
||||
// Static locals in the original loop, promoted to fields
|
||||
private Vector2 previousMousePosition;
|
||||
private int firstColor;
|
||||
|
||||
private void FreeImageToDraw()
|
||||
{
|
||||
if (imageToDrawValid)
|
||||
{
|
||||
UnloadImage(imageToDraw);
|
||||
imageToDrawValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
worldRectSource = new Rectangle(0, 0, worldWidth, -worldHeight);
|
||||
worldRectDest = new Rectangle(0, 0, worldWidth, worldHeight);
|
||||
textureOnScreen = new Rectangle(0, 0, windowWidth, windowHeight);
|
||||
|
||||
zoom = 1;
|
||||
offsetX = (worldWidth - windowWidth) / 2.0f; // Centered on window
|
||||
offsetY = (worldHeight - windowHeight) / 2.0f; // Centered on window
|
||||
framesPerStep = 1;
|
||||
frame = 0;
|
||||
|
||||
preset = -1; // No button pressed for preset
|
||||
mode = InteractionMode.Run; // Starting mode: running
|
||||
buttonZoomIn = false; // Button states: false not pressed
|
||||
buttonZomOut = false;
|
||||
buttonFaster = false;
|
||||
buttonSlower = false;
|
||||
|
||||
previousMousePosition = new Vector2(0.0f, 0.0f);
|
||||
firstColor = -1;
|
||||
imageToDrawValid = false;
|
||||
|
||||
// Load shader
|
||||
shdrGameOfLife = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/game_of_life.fs");
|
||||
|
||||
// Set shader uniform size of the world
|
||||
resolutionLoc = GetShaderLocation(shdrGameOfLife, "resolution");
|
||||
var resolution = new[] { (float)worldWidth, (float)worldHeight };
|
||||
Raylib.SetShaderValue(shdrGameOfLife, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
|
||||
|
||||
// Define two textures: the current world and the previous world
|
||||
world1 = LoadRenderTexture(worldWidth, worldHeight);
|
||||
world2 = LoadRenderTexture(worldWidth, worldHeight);
|
||||
BeginTextureMode(world2);
|
||||
ClearBackground(Color.RayWhite);
|
||||
EndTextureMode();
|
||||
|
||||
var startPattern = LoadImage("resources/game_of_life/r_pentomino.png");
|
||||
UpdateTextureRec(
|
||||
world2.Texture,
|
||||
new Rectangle(worldWidth / 2.0f, worldHeight / 2.0f, startPattern.Width, startPattern.Height),
|
||||
startPattern.Data
|
||||
);
|
||||
UnloadImage(startPattern);
|
||||
|
||||
// References to the two textures, to be swapped
|
||||
currentWorld = world2;
|
||||
previousWorld = world1;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
frame++;
|
||||
|
||||
// Change zoom: both by buttons or by mouse wheel
|
||||
var mouseWheelMove = GetMouseWheelMove();
|
||||
if (buttonZoomIn || (buttonZomOut && (zoom > 1)) || (mouseWheelMove != 0.0f))
|
||||
{
|
||||
FreeImageToDraw(); // Zoom change: free the image to draw to be recreated again
|
||||
|
||||
var centerX = offsetX + (windowWidth / 2.0f) / zoom;
|
||||
var centerY = offsetY + (windowHeight / 2.0f) / zoom;
|
||||
if (buttonZoomIn || (mouseWheelMove > 0.0f)) zoom *= 2;
|
||||
if ((buttonZomOut || (mouseWheelMove < 0.0f)) && (zoom > 1)) zoom /= 2;
|
||||
offsetX = centerX - (windowWidth / 2.0f) / zoom;
|
||||
offsetY = centerY - (windowHeight / 2.0f) / zoom;
|
||||
}
|
||||
|
||||
// Change speed: number of frames per step
|
||||
if (buttonFaster && framesPerStep > 1) framesPerStep--;
|
||||
if (buttonSlower) framesPerStep++;
|
||||
|
||||
// Mouse management
|
||||
if ((mode == InteractionMode.Run) || (mode == InteractionMode.Pause))
|
||||
{
|
||||
FreeImageToDraw(); // Free the image to draw: no longer needed in these modes
|
||||
|
||||
// Pan with mouse left button
|
||||
var mousePosition = GetMousePosition();
|
||||
if (IsMouseButtonDown(MouseButton.Left) && (mousePosition.X < windowWidth))
|
||||
{
|
||||
offsetX -= (mousePosition.X - previousMousePosition.X) / zoom;
|
||||
offsetY -= (mousePosition.Y - previousMousePosition.Y) / zoom;
|
||||
}
|
||||
previousMousePosition = mousePosition;
|
||||
}
|
||||
else // MODE_DRAW
|
||||
{
|
||||
var offsetDecimalX = offsetX - MathF.Floor(offsetX);
|
||||
var offsetDecimalY = offsetY - MathF.Floor(offsetY);
|
||||
var sizeInWorldX = (int)(MathF.Ceiling((windowWidth + offsetDecimalX * zoom) / zoom));
|
||||
var sizeInWorldY = (int)(MathF.Ceiling((windowHeight + offsetDecimalY * zoom) / zoom));
|
||||
if (offsetX + sizeInWorldX >= worldWidth) sizeInWorldX = worldWidth - (int)MathF.Floor(offsetX);
|
||||
if (offsetY + sizeInWorldY >= worldHeight) sizeInWorldY = worldHeight - (int)MathF.Floor(offsetY);
|
||||
|
||||
// Create image to draw if not created yet
|
||||
if (!imageToDrawValid)
|
||||
{
|
||||
var worldOnScreen = LoadRenderTexture(sizeInWorldX, sizeInWorldY);
|
||||
BeginTextureMode(worldOnScreen);
|
||||
DrawTexturePro(
|
||||
currentWorld.Texture,
|
||||
new Rectangle(MathF.Floor(offsetX), MathF.Floor(offsetY), sizeInWorldX, -sizeInWorldY),
|
||||
new Rectangle(0, 0, sizeInWorldX, sizeInWorldY),
|
||||
new Vector2(0, 0), 0.0f, Color.White
|
||||
);
|
||||
EndTextureMode();
|
||||
imageToDraw = LoadImageFromTexture(worldOnScreen.Texture);
|
||||
imageToDrawValid = true;
|
||||
|
||||
UnloadRenderTexture(worldOnScreen);
|
||||
}
|
||||
|
||||
var mousePosition = GetMousePosition();
|
||||
if (IsMouseButtonDown(MouseButton.Left) && (mousePosition.X < windowWidth))
|
||||
{
|
||||
var mouseX = (int)(mousePosition.X + offsetDecimalX * zoom) / zoom;
|
||||
var mouseY = (int)(mousePosition.Y + offsetDecimalY * zoom) / zoom;
|
||||
if (mouseX >= sizeInWorldX) mouseX = sizeInWorldX - 1;
|
||||
if (mouseY >= sizeInWorldY) mouseY = sizeInWorldY - 1;
|
||||
if (firstColor == -1) firstColor = (GetImageColor(imageToDraw, mouseX, mouseY).R < 5) ? 0 : 1;
|
||||
var prevColor = (GetImageColor(imageToDraw, mouseX, mouseY).R < 5) ? 0 : 1;
|
||||
|
||||
ImageDrawPixel(ref imageToDraw, mouseX, mouseY, (firstColor != 0) ? Color.Black : Color.RayWhite);
|
||||
|
||||
if (prevColor != firstColor)
|
||||
{
|
||||
UpdateTextureRec(
|
||||
currentWorld.Texture,
|
||||
new Rectangle(MathF.Floor(offsetX), MathF.Floor(offsetY), sizeInWorldX, sizeInWorldY),
|
||||
imageToDraw.Data
|
||||
);
|
||||
}
|
||||
}
|
||||
else firstColor = -1;
|
||||
}
|
||||
|
||||
// Load selected preset
|
||||
if (preset >= 0)
|
||||
{
|
||||
Image pattern;
|
||||
if (preset < numberOfPresets - 1) // Preset with pattern image to load
|
||||
{
|
||||
pattern = preset switch
|
||||
{
|
||||
0 => LoadImage("resources/game_of_life/glider.png"),
|
||||
1 => LoadImage("resources/game_of_life/r_pentomino.png"),
|
||||
2 => LoadImage("resources/game_of_life/acorn.png"),
|
||||
3 => LoadImage("resources/game_of_life/spaceships.png"),
|
||||
4 => LoadImage("resources/game_of_life/still_lifes.png"),
|
||||
5 => LoadImage("resources/game_of_life/oscillators.png"),
|
||||
6 => LoadImage("resources/game_of_life/puffer_train.png"),
|
||||
7 => LoadImage("resources/game_of_life/glider_gun.png"),
|
||||
8 => LoadImage("resources/game_of_life/breeder.png"),
|
||||
_ => default,
|
||||
};
|
||||
BeginTextureMode(currentWorld);
|
||||
ClearBackground(Color.RayWhite);
|
||||
EndTextureMode();
|
||||
|
||||
UpdateTextureRec(
|
||||
currentWorld.Texture,
|
||||
new Rectangle(
|
||||
worldWidth * presetPatterns[preset].Position.X - pattern.Width / 2.0f,
|
||||
worldHeight * presetPatterns[preset].Position.Y - pattern.Height / 2.0f,
|
||||
pattern.Width, pattern.Height
|
||||
),
|
||||
pattern.Data
|
||||
);
|
||||
}
|
||||
else // Last preset: Random values
|
||||
{
|
||||
pattern = GenImageColor(worldWidth / randomTiles, worldHeight / randomTiles, Color.RayWhite);
|
||||
for (var i = 0; i < randomTiles; i++)
|
||||
{
|
||||
for (var j = 0; j < randomTiles; j++)
|
||||
{
|
||||
ImageClearBackground(ref pattern, Color.RayWhite);
|
||||
for (var x = 0; x < pattern.Width; x++)
|
||||
{
|
||||
for (var y = 0; y < pattern.Height; y++)
|
||||
{
|
||||
if (GetRandomValue(0, 100) < 15) ImageDrawPixel(ref pattern, x, y, Color.Black);
|
||||
}
|
||||
}
|
||||
UpdateTextureRec(
|
||||
currentWorld.Texture,
|
||||
new Rectangle(pattern.Width * i, pattern.Height * j, pattern.Width, pattern.Height),
|
||||
pattern.Data
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnloadImage(pattern);
|
||||
|
||||
mode = InteractionMode.Pause;
|
||||
offsetX = worldWidth * presetPatterns[preset].Position.X - (float)windowWidth / zoom / 2.0f;
|
||||
offsetY = worldHeight * presetPatterns[preset].Position.Y - (float)windowHeight / zoom / 2.0f;
|
||||
}
|
||||
|
||||
// Check window draw inside world limits
|
||||
if (offsetX < 0) offsetX = 0;
|
||||
if (offsetY < 0) offsetY = 0;
|
||||
if (offsetX > worldWidth - (float)windowWidth / zoom) offsetX = worldWidth - (float)windowWidth / zoom;
|
||||
if (offsetY > worldHeight - (float)windowHeight / zoom) offsetY = worldHeight - (float)windowHeight / zoom;
|
||||
|
||||
// Rectangles for drawing texture portion to screen
|
||||
var textureSourceToScreen = new Rectangle(offsetX, offsetY, (float)windowWidth / zoom, (float)windowHeight / zoom);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw to texture
|
||||
//----------------------------------------------------------------------------------
|
||||
if ((mode == InteractionMode.Run) && ((frame % framesPerStep) == 0))
|
||||
{
|
||||
// Swap worlds
|
||||
var tempWorld = currentWorld;
|
||||
currentWorld = previousWorld;
|
||||
previousWorld = tempWorld;
|
||||
|
||||
// Draw to texture
|
||||
BeginTextureMode(currentWorld);
|
||||
BeginShaderMode(shdrGameOfLife);
|
||||
DrawTexturePro(previousWorld.Texture, worldRectSource, worldRectDest, new Vector2(0, 0), 0.0f, Color.RayWhite);
|
||||
EndShaderMode();
|
||||
EndTextureMode();
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw to screen
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
DrawTexturePro(currentWorld.Texture, textureSourceToScreen, textureOnScreen, new Vector2(0, 0), 0.0f, Color.White);
|
||||
|
||||
DrawLine(windowWidth, 0, windowWidth, screenHeight, new Color(218, 218, 218, 255));
|
||||
DrawRectangle(windowWidth, 0, screenWidth - windowWidth, screenHeight, new Color(232, 232, 232, 255));
|
||||
|
||||
DrawText("Conway's", 704, 4, 20, Color.DarkBlue);
|
||||
DrawText(" game of", 704, 19, 20, Color.DarkBlue);
|
||||
DrawText(" life", 708, 34, 20, Color.DarkBlue);
|
||||
DrawText("in raylib", 757, 42, 6, Color.Black);
|
||||
|
||||
DrawText("Presets", 710, 58, 8, Color.Gray);
|
||||
preset = -1;
|
||||
|
||||
// Draw GUI controls
|
||||
//------------------------------------------------------------------------------
|
||||
// NOTE: raygui is not bound in raylib-cs; controls are kept for reference. The
|
||||
// simulation still runs automatically and mouse wheel zoom / left-drag pan work.
|
||||
/*for (int i = 0; i < numberOfPresets; i++)
|
||||
if (GuiButton(new Rectangle( 710.0f, 70.0f + 18*i, 80.0f, 16.0f ), presetPatterns[i].Name)) preset = i;
|
||||
|
||||
GuiToggleGroup(new Rectangle( 710, 258, 80, 16 ), "Run\nPause\nDraw", ref mode);*/
|
||||
|
||||
DrawText($"Zoom: {zoom}x", 710, 316, 8, Color.Gray);
|
||||
/*buttonZoomIn = GuiButton(new Rectangle( 710, 328, 80, 16 ), "Zoom in");
|
||||
buttonZomOut = GuiButton(new Rectangle( 710, 346, 80, 16 ), "Zoom out");*/
|
||||
|
||||
DrawText($"Speed: {framesPerStep} frame{((framesPerStep > 1) ? "s" : "")}", 710, 370, 8, Color.Gray);
|
||||
/*buttonFaster = GuiButton(new Rectangle( 710, 382, 80, 16 ), "Faster");
|
||||
buttonSlower = GuiButton(new Rectangle( 710, 400, 80, 16 ), "Slower");*/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DrawFPS(712, 426);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shdrGameOfLife);
|
||||
UnloadRenderTexture(world1);
|
||||
UnloadRenderTexture(world2);
|
||||
|
||||
FreeImageToDraw();
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - game of life");
|
||||
|
||||
SetTargetFPS(60); // Set at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new GameOfLife();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
213
Examples/Shaders/LightmapRendering.cs
Normal file
213
Examples/Shaders/LightmapRendering.cs
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - lightmap rendering
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by Jussi Viitala (@nullstare) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2019-2025 Jussi Viitala (@nullstare) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Rlgl;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class LightmapRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MapSize = 16;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Lightmap Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - lightmap rendering";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Mesh mesh;
|
||||
private Shader shader;
|
||||
private Texture2D texture;
|
||||
private Texture2D light;
|
||||
private RenderTexture2D lightmap;
|
||||
private Material material;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(4.0f, 6.0f, 8.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
mesh = GenMeshPlane((float)MapSize, (float)MapSize, 1, 1);
|
||||
|
||||
// GenMeshPlane doesn't generate texcoords2 so we will upload them separately
|
||||
mesh.AllocTexCoords2();
|
||||
|
||||
// X // Y
|
||||
mesh.TexCoords2[0] = 0.0f; mesh.TexCoords2[1] = 0.0f;
|
||||
mesh.TexCoords2[2] = 1.0f; mesh.TexCoords2[3] = 0.0f;
|
||||
mesh.TexCoords2[4] = 0.0f; mesh.TexCoords2[5] = 1.0f;
|
||||
mesh.TexCoords2[6] = 1.0f; mesh.TexCoords2[7] = 1.0f;
|
||||
|
||||
// Load a new texcoords2 attributes buffer
|
||||
mesh.VboId[(int)ShaderLocationIndex.VertexTexcoord02] =
|
||||
LoadVertexBuffer(mesh.TexCoords2, mesh.VertexCount * 2 * sizeof(float), false);
|
||||
EnableVertexArray(mesh.VaoId);
|
||||
|
||||
// Index 5 is for texcoords2
|
||||
SetVertexAttribute(5, 2, Rlgl.FLOAT, false, 0, 0);
|
||||
EnableVertexAttribute(5);
|
||||
DisableVertexArray();
|
||||
|
||||
// Load lightmap shader
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/lightmap.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/lightmap.fs"
|
||||
);
|
||||
|
||||
texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
light = LoadTexture("resources/spark_flame.png");
|
||||
|
||||
GenTextureMipmaps(ref texture);
|
||||
SetTextureFilter(texture, TextureFilter.Trilinear);
|
||||
|
||||
lightmap = LoadRenderTexture(MapSize, MapSize);
|
||||
|
||||
material = LoadMaterialDefault();
|
||||
material.Shader = shader;
|
||||
material.Maps[(int)MaterialMapIndex.Albedo].Texture = texture;
|
||||
material.Maps[(int)MaterialMapIndex.Metalness].Texture = lightmap.Texture;
|
||||
|
||||
// Drawing to lightmap
|
||||
BeginTextureMode(lightmap);
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
BeginBlendMode(BlendMode.Additive);
|
||||
DrawTexturePro(
|
||||
light,
|
||||
new Rectangle(0, 0, (float)light.Width, (float)light.Height),
|
||||
new Rectangle(0, 0, 2.0f * MapSize, 2.0f * MapSize),
|
||||
new Vector2((float)MapSize, (float)MapSize),
|
||||
0.0f,
|
||||
Color.Red
|
||||
);
|
||||
DrawTexturePro(
|
||||
light,
|
||||
new Rectangle(0, 0, (float)light.Width, (float)light.Height),
|
||||
new Rectangle((float)MapSize * 0.8f, (float)MapSize / 2.0f, 2.0f * MapSize, 2.0f * MapSize),
|
||||
new Vector2((float)MapSize, (float)MapSize),
|
||||
0.0f,
|
||||
Color.Blue
|
||||
);
|
||||
DrawTexturePro(
|
||||
light,
|
||||
new Rectangle(0, 0, (float)light.Width, (float)light.Height),
|
||||
new Rectangle((float)MapSize * 0.8f, (float)MapSize * 0.8f, (float)MapSize, (float)MapSize),
|
||||
new Vector2((float)MapSize / 2.0f, (float)MapSize / 2.0f),
|
||||
0.0f,
|
||||
Color.Green
|
||||
);
|
||||
BeginBlendMode(BlendMode.Alpha);
|
||||
EndTextureMode();
|
||||
|
||||
// NOTE: To enable trilinear filtering we need mipmaps available for texture
|
||||
GenTextureMipmaps(ref lightmap.Texture);
|
||||
SetTextureFilter(lightmap.Texture, TextureFilter.Trilinear);
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawMesh(mesh, material, Matrix4x4.Identity);
|
||||
EndMode3D();
|
||||
|
||||
DrawTexturePro(
|
||||
lightmap.Texture,
|
||||
new Rectangle(0, 0, -MapSize, -MapSize),
|
||||
new Rectangle((float)GetRenderWidth() - MapSize * 8 - 10, 10, (float)MapSize * 8, (float)MapSize * 8),
|
||||
new Vector2(0.0f, 0.0f),
|
||||
0.0f,
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawText($"LIGHTMAP: {MapSize}x{MapSize} pixels", GetRenderWidth() - 130, 20 + MapSize * 8, 10, Color.Green);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMesh(mesh); // Unload the mesh
|
||||
UnloadShader(shader); // Unload shader
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadTexture(light); // Unload texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - lightmap rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LightmapRendering();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
265
Examples/Shaders/MandelbrotSet.cs
Normal file
265
Examples/Shaders/MandelbrotSet.cs
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - mandelbrot set
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jordi Santonja (@JordSant)
|
||||
* Based on previous work by Josh Colclough (@joshcol9232)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 Jordi Santonja (@JordSant)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class MandelbrotSet : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Mandelbrot Set";
|
||||
|
||||
public string Title => "raylib [shaders] example - mandelbrot set";
|
||||
|
||||
// A few good interesting places
|
||||
private static readonly float[][] pointsOfInterest = new[]
|
||||
{
|
||||
new[] { -1.76826775f, -0.00422996283f, 28435.9238f },
|
||||
new[] { 0.322004497f, -0.0357099883f, 56499.7266f },
|
||||
new[] { -0.748880744f, -0.0562955774f, 9237.59082f },
|
||||
new[] { -1.78385007f, -0.0156200649f, 14599.5283f },
|
||||
new[] { -0.0985441282f, -0.924688697f, 26259.8535f },
|
||||
new[] { 0.317785531f, -0.0322612226f, 29297.9258f },
|
||||
};
|
||||
|
||||
private const float zoomSpeed = 1.01f;
|
||||
private const float offsetSpeedMul = 2.0f;
|
||||
|
||||
private const float startingZoom = 0.6f;
|
||||
private static readonly float[] startingOffset = { -0.5f, 0.0f };
|
||||
|
||||
private Shader shader;
|
||||
private RenderTexture2D target;
|
||||
private float[] offset;
|
||||
private float zoom;
|
||||
private int maxIterations;
|
||||
private float maxIterationsMultiplier;
|
||||
private int zoomLoc;
|
||||
private int offsetLoc;
|
||||
private int maxIterationsLoc;
|
||||
private bool showControls;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Load mandelbrot set shader
|
||||
// NOTE: Defining null (NULL) for vertex shader forces usage of internal default vertex shader
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/mandelbrot_set.fs");
|
||||
|
||||
// Create a RenderTexture2D to be used for render to texture
|
||||
target = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||
|
||||
// Offset and zoom to draw the mandelbrot set at. (centered on screen and default size)
|
||||
offset = new[] { startingOffset[0], startingOffset[1] };
|
||||
zoom = startingZoom;
|
||||
|
||||
// Depending on the zoom the maximum number of iterations must be adapted to get more detail as we zoom in
|
||||
// The solution is not perfect, so a control has been added to increase/decrease the number of iterations with UP/DOWN keys
|
||||
#if BROWSER
|
||||
maxIterations = 43;
|
||||
maxIterationsMultiplier = 22.0f;
|
||||
#else
|
||||
maxIterations = 333;
|
||||
maxIterationsMultiplier = 166.5f;
|
||||
#endif
|
||||
|
||||
// Get variable (uniform) locations on the shader to connect with the program
|
||||
// NOTE: If uniform variable could not be found in the shader, function returns -1
|
||||
zoomLoc = GetShaderLocation(shader, "zoom");
|
||||
offsetLoc = GetShaderLocation(shader, "offset");
|
||||
maxIterationsLoc = GetShaderLocation(shader, "maxIterations");
|
||||
|
||||
// Upload the shader uniform values!
|
||||
Raylib.SetShaderValue(shader, zoomLoc, zoom, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, offsetLoc, offset, ShaderUniformDataType.Vec2);
|
||||
Raylib.SetShaderValue(shader, maxIterationsLoc, maxIterations, ShaderUniformDataType.Int);
|
||||
|
||||
showControls = true; // Show controls
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var updateShader = false;
|
||||
|
||||
// Press [1 - 6] to reset c to a point of interest
|
||||
if (IsKeyPressed(KeyboardKey.One) ||
|
||||
IsKeyPressed(KeyboardKey.Two) ||
|
||||
IsKeyPressed(KeyboardKey.Three) ||
|
||||
IsKeyPressed(KeyboardKey.Four) ||
|
||||
IsKeyPressed(KeyboardKey.Five) ||
|
||||
IsKeyPressed(KeyboardKey.Six))
|
||||
{
|
||||
var interestIndex = 0;
|
||||
if (IsKeyPressed(KeyboardKey.One)) interestIndex = 0;
|
||||
else if (IsKeyPressed(KeyboardKey.Two)) interestIndex = 1;
|
||||
else if (IsKeyPressed(KeyboardKey.Three)) interestIndex = 2;
|
||||
else if (IsKeyPressed(KeyboardKey.Four)) interestIndex = 3;
|
||||
else if (IsKeyPressed(KeyboardKey.Five)) interestIndex = 4;
|
||||
else if (IsKeyPressed(KeyboardKey.Six)) interestIndex = 5;
|
||||
|
||||
offset[0] = pointsOfInterest[interestIndex][0];
|
||||
offset[1] = pointsOfInterest[interestIndex][1];
|
||||
zoom = pointsOfInterest[interestIndex][2];
|
||||
updateShader = true;
|
||||
}
|
||||
|
||||
// If "R" is pressed, reset zoom and offset
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
offset[0] = startingOffset[0];
|
||||
offset[1] = startingOffset[1];
|
||||
zoom = startingZoom;
|
||||
updateShader = true;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.F1)) showControls = !showControls; // Toggle whether or not to show controls
|
||||
|
||||
// Change number of max iterations with UP and DOWN keys
|
||||
// WARNING: Increasing the number of max iterations greatly impacts performance
|
||||
if (IsKeyPressed(KeyboardKey.Up))
|
||||
{
|
||||
maxIterationsMultiplier *= 1.4f;
|
||||
updateShader = true;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Down))
|
||||
{
|
||||
maxIterationsMultiplier /= 1.4f;
|
||||
updateShader = true;
|
||||
}
|
||||
|
||||
// If either left or right button is pressed, zoom in/out
|
||||
if (IsMouseButtonDown(MouseButton.Left) || IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
// Change zoom. If Mouse left -> zoom in. Mouse right -> zoom out
|
||||
zoom *= IsMouseButtonDown(MouseButton.Left) ? zoomSpeed : (1.0f / zoomSpeed);
|
||||
|
||||
var mousePos = GetMousePosition();
|
||||
Vector2 offsetVelocity;
|
||||
// Find the velocity at which to change the camera. Take the distance of the mouse
|
||||
// From the center of the screen as the direction, and adjust magnitude based on the current zoom
|
||||
offsetVelocity.X = (mousePos.X / (float)screenWidth - 0.5f) * offsetSpeedMul / zoom;
|
||||
offsetVelocity.Y = (mousePos.Y / (float)screenHeight - 0.5f) * offsetSpeedMul / zoom;
|
||||
|
||||
// Apply move velocity to camera
|
||||
offset[0] += GetFrameTime() * offsetVelocity.X;
|
||||
offset[1] += GetFrameTime() * offsetVelocity.Y;
|
||||
|
||||
updateShader = true;
|
||||
}
|
||||
|
||||
// In case a parameter has been changed, update the shader values
|
||||
if (updateShader)
|
||||
{
|
||||
// As we zoom in, increase the number of max iterations to get more detail
|
||||
// Aproximate formula, but it works-ish
|
||||
maxIterations = (int)(MathF.Sqrt(2.0f * MathF.Sqrt(MathF.Abs(1.0f - MathF.Sqrt(37.5f * zoom)))) * maxIterationsMultiplier);
|
||||
|
||||
// Update the shader uniform values!
|
||||
Raylib.SetShaderValue(shader, zoomLoc, zoom, ShaderUniformDataType.Float);
|
||||
Raylib.SetShaderValue(shader, offsetLoc, offset, ShaderUniformDataType.Vec2);
|
||||
Raylib.SetShaderValue(shader, maxIterationsLoc, maxIterations, ShaderUniformDataType.Int);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Using a render texture to draw Mandelbrot set
|
||||
BeginTextureMode(target); // Enable drawing to texture
|
||||
ClearBackground(Color.Black); // Clear the render texture
|
||||
|
||||
// Draw a rectangle in shader mode to be used as shader canvas
|
||||
// NOTE: Rectangle uses font white character texture coordinates,
|
||||
// So shader can not be applied here directly because input vertexTexCoord
|
||||
// Do not represent full screen coordinates (space where want to apply shader)
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Black);
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black); // Clear screen background
|
||||
|
||||
// Draw the saved texture and rendered mandelbrot set with shader
|
||||
// NOTE: We do not invert texture on Y, already considered inside shader
|
||||
BeginShaderMode(shader);
|
||||
// WARNING: If FLAG_WINDOW_HIGHDPI is enabled, HighDPI monitor scaling should be considered
|
||||
// When rendering the RenderTexture2D to fit in the HighDPI scaled Window
|
||||
DrawTextureEx(target.Texture, new Vector2(0.0f, 0.0f), 0.0f, 1.0f, Color.White);
|
||||
EndShaderMode();
|
||||
|
||||
if (showControls)
|
||||
{
|
||||
DrawText("Press Mouse buttons right/left to zoom in/out and move", 10, 15, 10, Color.RayWhite);
|
||||
DrawText("Press F1 to toggle these controls", 10, 30, 10, Color.RayWhite);
|
||||
DrawText("Press [1 - 6] to change point of interest", 10, 45, 10, Color.RayWhite);
|
||||
DrawText("Press UP | DOWN to change number of iterations", 10, 60, 10, Color.RayWhite);
|
||||
DrawText("Press R to recenter the camera", 10, 75, 10, Color.RayWhite);
|
||||
}
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader); // Unload shader
|
||||
UnloadRenderTexture(target); // Unload render texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - mandelbrot set");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MandelbrotSet();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
233
Examples/Shaders/NormalmapRendering.cs
Normal file
233
Examples/Shaders/NormalmapRendering.cs
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - normalmap rendering
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jeremy Montgomery (@Sir_Irk) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 Jeremy Montgomery (@Sir_Irk) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class NormalmapRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Normalmap Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - normalmap rendering";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Shader shader;
|
||||
private Model plane;
|
||||
private Vector3 lightPosition;
|
||||
private int lightPosLoc;
|
||||
private float specularExponent;
|
||||
private int specularExponentLoc;
|
||||
private int useNormalMap;
|
||||
private int useNormalMapLoc;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 2.0f, -4.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load basic normal map lighting shader
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/normalmap.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/normalmap.fs"
|
||||
);
|
||||
|
||||
// Get some required shader locations
|
||||
shader.Locs[(int)ShaderLocationIndex.MapNormal] = GetShaderLocation(shader, "normalMap");
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(shader, "viewPos");
|
||||
|
||||
// NOTE: "matModel" location name is automatically assigned on shader loading,
|
||||
// no need to get the location again if using that uniform name
|
||||
// shader.Locs[(int)ShaderLocationIndex.MatrixModel] = GetShaderLocation(shader, "matModel");
|
||||
|
||||
// This example uses just 1 point light
|
||||
lightPosition = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
lightPosLoc = GetShaderLocation(shader, "lightPos");
|
||||
|
||||
// Load a plane model that has proper normals and tangents
|
||||
plane = LoadModel("resources/models/plane.glb");
|
||||
|
||||
// Set the plane model's shader and texture maps
|
||||
plane.Materials[0].Shader = shader;
|
||||
plane.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = LoadTexture("resources/tiles_diffuse.png");
|
||||
plane.Materials[0].Maps[(int)MaterialMapIndex.Normal].Texture = LoadTexture("resources/tiles_normal.png");
|
||||
|
||||
// Generate Mipmaps and use TRILINEAR filtering to help with texture aliasing
|
||||
GenTextureMipmaps(ref plane.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture);
|
||||
GenTextureMipmaps(ref plane.Materials[0].Maps[(int)MaterialMapIndex.Normal].Texture);
|
||||
|
||||
SetTextureFilter(plane.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture, TextureFilter.Trilinear);
|
||||
SetTextureFilter(plane.Materials[0].Maps[(int)MaterialMapIndex.Normal].Texture, TextureFilter.Trilinear);
|
||||
|
||||
// Specular exponent AKA shininess of the material
|
||||
specularExponent = 8.0f;
|
||||
specularExponentLoc = GetShaderLocation(shader, "specularExponent");
|
||||
|
||||
// Allow toggling the normal map on and off for comparison purposes
|
||||
useNormalMap = 1;
|
||||
useNormalMapLoc = GetShaderLocation(shader, "useNormalMap");
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Move the light around on the X and Z axis using WASD keys
|
||||
Vector3 direction = new(0.0f, 0.0f, 0.0f);
|
||||
if (IsKeyDown(KeyboardKey.W))
|
||||
{
|
||||
direction = Vector3Add(direction, new Vector3(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
direction = Vector3Add(direction, new Vector3(0.0f, 0.0f, -1.0f));
|
||||
}
|
||||
if (IsKeyDown(KeyboardKey.D))
|
||||
{
|
||||
direction = Vector3Add(direction, new Vector3(-1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
direction = Vector3Add(direction, new Vector3(1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
direction = Vector3Normalize(direction);
|
||||
lightPosition = Vector3Add(lightPosition, Vector3Scale(direction, GetFrameTime() * 3.0f));
|
||||
|
||||
// Increase/Decrease the specular exponent(shininess)
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
specularExponent = Clamp(specularExponent + 40.0f * GetFrameTime(), 2.0f, 128.0f);
|
||||
}
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
specularExponent = Clamp(specularExponent - 40.0f * GetFrameTime(), 2.0f, 128.0f);
|
||||
}
|
||||
|
||||
// Toggle normal map on and off
|
||||
if (IsKeyPressed(KeyboardKey.N))
|
||||
{
|
||||
useNormalMap = (useNormalMap != 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
// Spin plane model at a constant rate
|
||||
plane.Transform = MatrixRotateY((float)GetTime() * 0.5f);
|
||||
|
||||
// Update shader values
|
||||
Raylib.SetShaderValue(shader, lightPosLoc, lightPosition, ShaderUniformDataType.Vec3);
|
||||
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
Raylib.SetShaderValue(shader, specularExponentLoc, specularExponent, ShaderUniformDataType.Float);
|
||||
|
||||
Raylib.SetShaderValue(shader, useNormalMapLoc, useNormalMap, ShaderUniformDataType.Int);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
BeginShaderMode(shader);
|
||||
|
||||
DrawModel(plane, Vector3.Zero, 2.0f, Color.White);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
// Draw sphere to show light position
|
||||
DrawSphereWires(lightPosition, 0.2f, 8, 8, Color.Orange);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
Color textColor = (useNormalMap != 0) ? Color.DarkGreen : Color.Red;
|
||||
string toggleStr = (useNormalMap != 0) ? "On" : "Off";
|
||||
DrawText($"Use key [N] to toggle normal map: {toggleStr}", 10, 10, 10, textColor);
|
||||
|
||||
int yOffset = 24;
|
||||
DrawText("Use keys [W][A][S][D] to move the light", 10, 10 + yOffset * 1, 10, Color.Black);
|
||||
DrawText("Use keys [Up][Down] to change specular exponent", 10, 10 + yOffset * 2, 10, Color.Black);
|
||||
DrawText($"Specular Exponent: {specularExponent:F2}", 10, 10 + yOffset * 3, 10, Color.Blue);
|
||||
|
||||
DrawFPS(screenWidth - 90, 10);
|
||||
|
||||
EndDrawing();
|
||||
//--------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader);
|
||||
UnloadModel(plane);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - normalmap rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new NormalmapRendering();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
242
Examples/Shaders/RlglCompute.cs
Normal file
242
Examples/Shaders/RlglCompute.cs
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* 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.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
243
Examples/Shaders/RoundedRectangle.cs
Normal file
243
Examples/Shaders/RoundedRectangle.cs
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
316
Examples/Shaders/ShadowmapRendering.cs
Normal file
316
Examples/Shaders/ShadowmapRendering.cs
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* 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 System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
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;
|
||||
}
|
||||
}
|
||||
143
Examples/Shaders/TextureTiling.cs
Normal file
143
Examples/Shaders/TextureTiling.cs
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
148
Examples/Shaders/VertexDisplacement.cs
Normal file
148
Examples/Shaders/VertexDisplacement.cs
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* 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 System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue