Shaders
Shaders are GPU programs that transform vertices and determine pixel colors. They run on the graphics card in parallel, making them efficient for complex visual effects.
What They Are
- Vertex shaders transform 3D model vertices into screen space
- Fragment shaders (also called pixel shaders) determine the final color of each pixel
- Shaders (in raylib terminology) package vertex+fragment pairs with parameters
Why Use Them
Use shaders when you need visual effects beyond what built-in rendering provides:
- Custom lighting models (toon shading, stylized PBR)
- Post-processing effects (bloom, tone mapping, color grading)
- Special effects (holograms, distortion, pixelation)
- Optimized rendering for specific art styles
When to Write Them
You don't need custom shaders to start. Mibo.Raylib's built-in renderers work without them:
- 2D games: Use
Graphics2Dwith standard raylib drawing (no shaders required) - 3D games: Use
Graphics3Dwith standard raylib model rendering (works without custom shaders)
Write shaders when: - You have specific visual requirements - You need performance optimizations for your target hardware - You're building advanced rendering features
Loading Shaders
Shaders are GLSL strings loaded at runtime using Raylib.LoadShaderFromMemory or Raylib.LoadShader. There is no content pipeline — shaders are plain .fs/.vs files or embedded strings.
open Raylib_cs
// Load from file
let myShader = Raylib.LoadShader("shaders/vertex.vs", "shaders/fragment.fs")
// Or load from memory (GLSL strings)
let fragCode = """
#version 330
in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 finalColor;
uniform vec4 tint;
void main() {
vec4 texel = texture(texture0, fragTexCoord);
finalColor = texel * tint;
}
"""
let myShader = Raylib.LoadShaderFromMemory(null, fragCode)
Setting Parameters
Set shader parameters using Raylib.SetShaderValue:
open System.Numerics
open System.Runtime.InteropServices
open Raylib_cs
// Set a float uniform
let loc = Raylib.GetShaderLocation(myShader, "tint")
let mutable value = 1.0f
use p = fixed &value
Raylib.SetShaderValue(myShader, loc, NativePtr.toVoidPtr p, ShaderUniformDataType.Float)
// Set a matrix uniform (no fixed needed)
let world = Matrix4x4.Identity
let matLoc = Raylib.GetShaderLocation(myShader, "world")
Raylib.SetShaderValueMatrix(myShader, matLoc, world)
Uniform Type |
|
|---|---|
|
|
|
|
|
|
|
|
|
|
_IMPORTANT_: The project uses
[<DisableRuntimeMarshalling>]. This affects howSetShaderValueworks — see the critical warning below.
DisableRuntimeMarshalling and SetShaderValue
Because the project uses [<DisableRuntimeMarshalling>], you must use fixed + NativePtr.toVoidPtr when passing scalar, vector, or struct values to SetShaderValue. Passing raw values directly as void* arguments causes the runtime to treat the value itself as a memory address, leading to access violations.
DO NOT do this:
// WRONG — runtime treats the int value as a pointer address
Raylib.SetShaderValue(shader, loc, 1, ShaderUniformDataType.Int)
// WRONG — runtime treats the float value as a pointer address
Raylib.SetShaderValue(shader, loc, 0.5f, ShaderUniformDataType.Float)
// WRONG — runtime treats the Vector3 as a pointer address
Raylib.SetShaderValue(shader, loc, Vector3.One, ShaderUniformDataType.Vec3)
ALWAYS pin the value and pass a pointer:
open System.Runtime.InteropServices
let setShaderInt (shader: Shader) (loc: int) (value: int) =
use p = fixed &value
Raylib.SetShaderValue(shader, loc, NativePtr.toVoidPtr p, ShaderUniformDataType.Int)
let setShaderFloat (shader: Shader) (loc: int) (value: float32) =
use p = fixed &value
Raylib.SetShaderValue(shader, loc, NativePtr.toVoidPtr p, ShaderUniformDataType.Float)
let setShaderVec3 (shader: Shader) (loc: int) (value: Vector3) =
use p = fixed &value
Raylib.SetShaderValue(shader, loc, NativePtr.toVoidPtr p, ShaderUniformDataType.Vec3)
let setShaderVec4 (shader: Shader) (loc: int) (value: Vector4) =
use p = fixed &value
Raylib.SetShaderValue(shader, loc, NativePtr.toVoidPtr p, ShaderUniformDataType.Vec4)
Exceptions:
SetShaderValueMatrixtakesMatrix4x4directly (notvoid*) — this works correctly withoutfixed.Rlgl.SetUniform(raw rlgl) also requiresfixed + NativePtr.toVoidPtr.
Where to Learn More
Shader binding contracts (what parameters each shader type expects) are documented in the rendering sections:
- 2D rendering shaders: See Rendering 2D overview for shader contracts
See also: raylib shaders documentation
[<Struct>] type Matrix4x4 = new: value: Matrix3x2 -> unit + 1 overload member Equals: other: Matrix4x4 -> bool + 1 overload member GetDeterminant: unit -> float32 member GetElement: row: int * column: int -> float32 member GetHashCode: unit -> int member GetRow: index: int -> Vector4 member ToString: unit -> string member WithElement: row: int * column: int * value: float32 -> Matrix4x4 member WithRow: index: int * value: Vector4 -> Matrix4x4 static member ( * ) : value1: Matrix4x4 * value2: Matrix4x4 -> Matrix4x4 + 1 overload ...
<summary>Represents a 4x4 matrix.</summary>
--------------------
Matrix4x4 ()
Matrix4x4(value: Matrix3x2) : Matrix4x4
Matrix4x4(m11: float32, m12: float32, m13: float32, m14: float32, m21: float32, m22: float32, m23: float32, m24: float32, m31: float32, m32: float32, m33: float32, m34: float32, m41: float32, m42: float32, m43: float32, m44: float32) : Matrix4x4
<summary>Gets the multiplicative identity matrix.</summary>
<returns>Gets the multiplicative identity matrix.</returns>
[<Struct>] type Vector3 = new: value: Vector2 * z: float32 -> unit + 3 overloads member CopyTo: array: float32 array -> unit + 2 overloads member Equals: other: Vector3 -> bool + 2 overloads member GetHashCode: unit -> int member Length: unit -> float32 member LengthSquared: unit -> float32 member ToString: unit -> string + 2 overloads member TryCopyTo: destination: Span<float32> -> bool static member (&&&) : left: Vector3 * right: Vector3 -> Vector3 static member ( * ) : left: Vector3 * right: Vector3 -> Vector3 + 2 overloads ...
<summary>Represents a vector with three single-precision floating-point values.</summary>
--------------------
Vector3 ()
Vector3(value: float32) : Vector3
Vector3(values: System.ReadOnlySpan<float32>) : Vector3
Vector3(value: Vector2, z: float32) : Vector3
Vector3(x: float32, y: float32, z: float32) : Vector3
<summary>Gets a vector whose 3 elements are equal to one.</summary>
<returns>A vector whose three elements are equal to one (that is, it returns the vector <code data-dev-comment-type="c">(1,1,1)</code>).</returns>
val int: value: 'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
val float32: value: 'T -> float32 (requires member op_Explicit)
--------------------
type float32 = System.Single
--------------------
type float32<'Measure> = float32
[<Struct>] type Vector4 = new: value: Vector2 * z: float32 * w: float32 -> unit + 4 overloads member CopyTo: array: float32 array -> unit + 2 overloads member Equals: other: Vector4 -> bool + 2 overloads member GetHashCode: unit -> int member Length: unit -> float32 member LengthSquared: unit -> float32 member ToString: unit -> string + 2 overloads member TryCopyTo: destination: Span<float32> -> bool static member (&&&) : left: Vector4 * right: Vector4 -> Vector4 static member ( * ) : left: Vector4 * right: Vector4 -> Vector4 + 2 overloads ...
<summary>Represents a vector with four single-precision floating-point values.</summary>
--------------------
Vector4 ()
Vector4(value: float32) : Vector4
Vector4(values: System.ReadOnlySpan<float32>) : Vector4
Vector4(value: Vector3, w: float32) : Vector4
Vector4(value: Vector2, z: float32, w: float32) : Vector4
Vector4(x: float32, y: float32, z: float32, w: float32) : Vector4
Mibo.Raylib