[BMX] Small Raylib Test PBR

Started by Filax, April 12, 2025, 07:55:58

Previous topic - Next topic

Filax

I'm currently exploring RayLib, this awesome little library. And one of the examples that
demonstrated PBR is missing (or maybe I didn't see it...).

It's the PBR example, with its shader, which I found very interesting. I simplified the
example to avoid having to load media. Put the shaders at the root of the source code.

I'll take advantage of this thread to post all my progress in understanding this great library!

But it's not easy to understand all this shader stuff...  :'( ???


Code: BASIC
'SuperStrict

Framework Ray.GUI
Import Ray.Math
Import BRL.Math

' Constants
Const SCREEN_WIDTH:Int = 800
Const SCREEN_HEIGHT:Int = 450
Const MAX_LIGHTS:Int = 4
Const LIGHT_POINT:Int = 1

' Light structure
Type TLight
    Field position:RVector3
    Field target:RVector3
    Field color:RColor
    Field intensity:Float
    Field enabled:Int
    Field typeA:Int
    Field positionLoc:Int
    Field targetLoc:Int
    Field colorLoc:Int
    Field intensityLoc:Int
    Field enabledLoc:Int
    Field typeLoc:Int
End Type

' Create light
Function CreateLight:TLight(position:RVector3, target:RVector3, color:RColor, intensity:Float, shader:RShader, index:Int)
    Local light:TLight = New TLight
    light.position = position
    light.target = target
    light.color = color
    light.intensity = intensity
    light.enabled = 1
    light.typeA = LIGHT_POINT
    
    light.positionLoc = GetShaderLocation(shader, "lights[" + index + "].position")
    light.targetLoc = GetShaderLocation(shader, "lights[" + index + "].target")
    light.colorLoc = GetShaderLocation(shader, "lights[" + index + "].color")
    light.intensityLoc = GetShaderLocation(shader, "lights[" + index + "].intensity")
    light.enabledLoc = GetShaderLocation(shader, "lights[" + index + "].enabled")
    light.typeLoc = GetShaderLocation(Shader, "lights[" + Index + "].type")
    
    If light.positionLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].position not found")
    If light.targetLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].target not found")
    If light.colorLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].color not found")
    If light.intensityLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].intensity not found")
    If light.enabledLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].enabled not found")
    If light.typeLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].type not found")
    
    If light.positionLoc <> -1 And light.targetLoc <> -1 And light.colorLoc <> -1 And light.intensityLoc <> -1 And light.enabledLoc <> -1 And light.typeLoc <> -1 Then
        DebugLog("INFO: Light " + index + " initialized at Position (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ")")
    EndIf
    
    UpdateLightShader(light, shader)
    Return light
End Function

' Update light shader uniforms
Function UpdateLightShader(light:TLight, shader:RShader)
    SetShaderValue(shader, light.positionLoc, Varptr light.position.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, light.targetLoc, Varptr light.target.x, SHADER_UNIFORM_VEC3)
    Local colorVec4:RVector4 = ColorNormalize(light.color)
    SetShaderValue(shader, light.colorLoc, Varptr colorVec4.x, SHADER_UNIFORM_VEC4)
    SetShaderValue(shader, light.intensityLoc, Varptr light.intensity, SHADER_UNIFORM_FLOAT)
    SetShaderValue(shader, light.enabledLoc, Varptr light.enabled, SHADER_UNIFORM_INT)
    SetShaderValue(shader, light.typeLoc, Varptr light.typeA, SHADER_UNIFORM_INT)
    
    DebugLog("INFO: Light updated - Pos: (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ")")
End Function

' Main function
Function Main()
    ' Initialization
    SetConfigFlags(FLAG_MSAA_4X_HINT)
    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "BlitzMax [raylib] - Basic PBR")
    SetTargetFPS(60)
    
    ' Setup camera
    Local camera:RCamera = New RCamera
    camera.position = New RVector3(2.0, 2.0, 6.0)
    camera.target = New RVector3(0.0, 0.5, 0.0)
    camera.up = New RVector3(0.0, 1.0, 0.0)
    camera.fovy = 45.0
    camera.projection = CAMERA_PERSPECTIVE
    
    ' Load shader
    Local Shader:RShader = LoadShader("pbr.vs", "pbr.fs")
    If Not IsShaderValid(shader) Then
        DebugLog("ERROR: PBR shader not loaded")
        End
    EndIf
    
    ' Setup shader locations
    shader.locs[SHADER_LOC_MAP_ALBEDO] = GetShaderLocation(shader, "albedoMap")
    shader.locs[SHADER_LOC_MAP_METALNESS] = GetShaderLocation(shader, "mraMap")
    shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap")
    shader.locs[SHADER_LOC_MAP_EMISSION] = GetShaderLocation(shader, "emissiveMap")
    shader.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(shader, "albedoColor")
    shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos")
    
    If shader.locs[SHADER_LOC_MAP_ALBEDO] = -1 Then DebugLog("ERROR: Uniform albedoMap not found")
    If shader.locs[SHADER_LOC_MAP_METALNESS] = -1 Then DebugLog("ERROR: Uniform mraMap not found")
    If shader.locs[SHADER_LOC_MAP_NORMAL] = -1 Then DebugLog("ERROR: Uniform normalMap not found")
    If shader.locs[SHADER_LOC_MAP_EMISSION] = -1 Then DebugLog("ERROR: Uniform emissiveMap not found")
    If shader.locs[SHADER_LOC_COLOR_DIFFUSE] = -1 Then DebugLog("ERROR: Uniform albedoColor not found")
    If shader.locs[SHADER_LOC_VECTOR_VIEW] = -1 Then DebugLog("ERROR: Uniform viewPos not found")
    
    ' Setup light count
    Local lightCountLoc:Int = GetShaderLocation(shader, "numOfLights")
    Local maxLightCount:Int = MAX_LIGHTS
    SetShaderValue(shader, lightCountLoc, Varptr maxLightCount, SHADER_UNIFORM_INT)
    If lightCountLoc = -1 Then DebugLog("ERROR: Uniform numOfLights not found")
    
    ' Setup ambient
    Local ambientColor:RVector3 = New RVector3(26.0/255.0, 32.0/255.0, 135.0/255.0)
    Local ambientIntensity:Float = 0.02
    Local ambientLoc:Int = GetShaderLocation(shader, "ambient")
    SetShaderValue(shader, GetShaderLocation(shader, "ambientColor"), Varptr ambientColor.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, ambientLoc, Varptr ambientIntensity, SHADER_UNIFORM_FLOAT)
    If ambientLoc = -1 Then DebugLog("ERROR: Uniform ambient not found")
    
    ' Additional shader locations
    Local emissiveIntensityLoc:Int = GetShaderLocation(shader, "emissivePower")
    Local emissiveColorLoc:Int = GetShaderLocation(shader, "emissiveColor")
    Local textureTilingLoc:Int = GetShaderLocation(shader, "tiling")
    If emissiveIntensityLoc = -1 Then DebugLog("ERROR: Uniform emissivePower not found")
    If emissiveColorLoc = -1 Then DebugLog("ERROR: Uniform emissiveColor not found")
    If textureTilingLoc = -1 Then DebugLog("ERROR: Uniform tiling not found")
    
    ' Create models
    Local plane:RModel = LoadModelFromMesh(GenMeshPlane(10.0, 10.0, 10, 10))
    Local cube:RModel = LoadModelFromMesh(GenMeshCube(1.0, 1.0, 1.0))
    
    ' Assign shader
    plane.materials.shader = shader
    cube.materials.shader = shader
    
    ' Setup material properties
    plane.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
    plane.materials.maps[MATERIAL_MAP_METALNESS].value = 0.0
    plane.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.0
    plane.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
    plane.materials.maps[MATERIAL_MAP_EMISSION].color = BLACK
    
    cube.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
    cube.materials.maps[MATERIAL_MAP_METALNESS].value = 0.5
    cube.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.3
    cube.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
    cube.materials.maps[MATERIAL_MAP_EMISSION].color = BLACK
    
    ' Texture tiling
    Local tiling:RVector2 = New RVector2(0.5, 0.5)
    
    ' Create lights
    Global lights:TLight[MAX_LIGHTS]
    lights
 = CreateLight(New RVector3(-1.0, 1.0, -2.0), New RVector3(0.0, 0.0, 0.0), YELLOW, 4.0, shader, 0)
    lights[1] = CreateLight(New RVector3(2.0, 1.0, 1.0), New RVector3(0.0, 0.0, 0.0), GREEN, 3.3, shader, 1)
    lights[2] = CreateLight(New RVector3(-2.0, 1.0, 1.0), New RVector3(0.0, 0.0, 0.0), RED, 8.3, shader, 2)
    lights[3] = CreateLight(New RVector3(1.0, 1.0, -2.0), New RVector3(0.0, 0.0, 0.0), BLUE, 2.0, shader, 3)
    
    ' Enable texture usage
    Local usage:Int = 0 ' Pas de textures pour simplifier
    SetShaderValue(shader, GetShaderLocation(shader, "useTexAlbedo"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexNormal"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexMRA"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexEmissive"), Varptr usage, SHADER_UNIFORM_INT)
    
    ' Main loop
    While Not WindowShouldClose()
        ' Update
        UpdateCamera(camera, CAMERA_ORBITAL)
        
        ' Update view position
        SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], Varptr camera.position.x, SHADER_UNIFORM_VEC3)
        
        ' Toggle lights
        If IsKeyPressed(KEY_ONE)
            lights[2].enabled = Not lights[2].enabled
            UpdateLightShader(lights[2], shader)
        EndIf
        If IsKeyPressed(KEY_TWO)
            lights[1].enabled = Not lights[1].enabled
            UpdateLightShader(lights[1], shader)
        EndIf
        If IsKeyPressed(KEY_THREE)
            lights[3].enabled = Not lights[3].enabled
            UpdateLightShader(lights[3], shader)
        EndIf
        If IsKeyPressed(KEY_FOUR)
            lights.enabled = Not lights.enabled
            UpdateLightShader(lights, shader)
        EndIf
        
        ' Draw
        BeginDrawing()
            ClearBackground(BLACK)
            
            BeginMode3D(camera)
                ' Draw plane
                SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                Local planeEmissiveColor:RVector4 = ColorNormalize(plane.materials.maps[MATERIAL_MAP_EMISSION].color)
                SetShaderValue(shader, emissiveColorLoc, Varptr planeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                DrawModel(plane, New RVector3(0.0, 0.0, 0.0), 1.0, WHITE)
                
                ' Draw cube
                SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                Local cubeEmissiveColor:RVector4 = ColorNormalize(cube.materials.maps[MATERIAL_MAP_EMISSION].color)
                SetShaderValue(shader, emissiveColorLoc, Varptr cubeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                Local emissiveIntensity:Float = 0.01
                SetShaderValue(shader, emissiveIntensityLoc, Varptr emissiveIntensity, SHADER_UNIFORM_FLOAT)
                DrawModel(cube, New RVector3(0.0, 1.0, 0.0), 1.0, WHITE)
                
                ' Draw light spheres
                For Local i:Int = 0 Until MAX_LIGHTS
                    If lights[i].enabled
                        DrawSphereEx(lights[i].position, 0.2, 8, 8, lights[i].color)
                    Else
                        DrawSphereWires(lights[i].position, 0.2, 8, 8, ColorAlpha(lights[i].color, 0.3))
                    EndIf
                Next
            EndMode3D()
            
            DrawText("Toggle lights: [1][2][3][4]", 10, 40, 20, LIGHTGRAY)
            DrawFPS(10, 10)
        EndDrawing()
    Wend
    
    ' Cleanup
    UnloadModel(plane)
    UnloadModel(cube)
    UnloadShader(shader)
    CloseWindow()
End Function
Main()

PBR.FS:
Code: BASIC
#version 330

#define MAX_LIGHTS 4
#define LIGHT_POINT 1
#define PI 3.14159265358979323846

struct Light {
    int enabled;
    int type;
    vec3 position;
    vec3 target;
    vec4 color;
    float intensity;
};

// Input vertex attributes (from vertex shader)
in vec3 fragPosition;
in vec2 fragTexCoord;
in vec3 fragNormal;

// Output fragment color
out vec4 finalColor;

// Input uniform values
uniform int numOfLights;
uniform vec4 albedoColor;
uniform float metallicValue;
uniform float roughnessValue;
uniform float aoValue;
uniform vec3 viewPos;
uniform vec3 ambientColor;
uniform float ambient;
uniform Light lights[MAX_LIGHTS];

// Simplified Fresnel
vec3 SchlickFresnel(float hDotV, vec3 refl) {
    return refl + (1.0 - refl) * pow(clamp(1.0 - hDotV, 0.0, 1.0), 5.0);
}

// Simplified GGX distribution
float GgxDistribution(float nDotH, float roughness) {
    float a = roughness * roughness;
    float d = nDotH * nDotH * (a - 1.0) + 1.0;
    return a / (PI * d * d + 0.0000001);
}

// Simplified geometry term
float GeomSmith(float nDotV, float nDotL, float roughness) {
    float r = roughness + 1.0;
    float k = (r * r) / 8.0;
    float ggx1 = nDotV / (nDotV * (1.0 - k) + k);
    float ggx2 = nDotL / (nDotL * (1.0 - k) + k);
    return ggx1 * ggx2;
}

vec3 ComputePBR() {
    vec3 albedo = albedoColor.rgb;
    float metallic = clamp(metallicValue, 0.04, 1.0); // Avoid zero metallic
    float roughness = clamp(roughnessValue, 0.1, 1.0); // Avoid zero roughness
    float ao = clamp(aoValue, 0.0, 1.0);
    
    vec3 N = normalize(fragNormal); // Use raw normal, no TBN
    vec3 V = normalize(viewPos - fragPosition);
    
    vec3 baseRefl = mix(vec3(0.04), albedo, metallic);
    vec3 lightAccum = vec3(0.0);
    
    for (int i = 0; i < numOfLights; i++) {
        if (lights[i].enabled == 1 && lights[i].type == LIGHT_POINT) {
            vec3 L = normalize(lights[i].position - fragPosition);
            vec3 H = normalize(V + L);
            float dist = length(lights[i].position - fragPosition);
            float attenuation = 1.0 / (1.0 + 0.1 * dist + 0.01 * dist * dist); // Softer attenuation
            vec3 radiance = lights[i].color.rgb * lights[i].intensity * attenuation;
            
            float nDotV = max(dot(N, V), 0.0000001);
            float nDotL = max(dot(N, L), 0.0000001);
            float hDotV = max(dot(H, V), 0.0);
            float nDotH = max(dot(N, H), 0.0);
            
            float D = GgxDistribution(nDotH, roughness);
            float G = GeomSmith(nDotV, nDotL, roughness);
            vec3 F = SchlickFresnel(hDotV, baseRefl);
            
            vec3 spec = (D * G * F) / (4.0 * nDotV * nDotL + 0.0000001);
            vec3 kD = vec3(1.0) - F;
            kD *= 1.0 - metallic;
            
            lightAccum += (kD * albedo / PI + spec) * radiance * nDotL;
            
            // Add simple specular term (inspired by yesterday)
            vec3 halfDir = normalize(L + V);
            float specSimple = pow(clamp(dot(N, halfDir), 0.0, 1.0), 16.0);
            lightAccum += lights[i].color.rgb * specSimple * attenuation * 0.2;
        }
    }
    
    vec3 ambientFinal = ambientColor * albedo * ambient * ao;
    
    return ambientFinal + lightAccum;
}

void main() {
    vec3 color = ComputePBR();
    
    // Simplified tonemapping
    color = color / (color + vec3(1.0));
    
    // Gamma correction (match yesterday's style)
    color = pow(color, vec3(0.4545));
    
    finalColor = vec4(color, 1.0);
}


PBR.VS
Code: BASIC
#version 330

// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec3 vertexTangent;
in vec4 vertexColor;

// Input uniform values
uniform mat4 mvp;
uniform mat4 matModel;
uniform mat4 matNormal;
uniform vec3 lightPos;
uniform vec4 difColor;

// Output vertex attributes (to fragment shader)
out vec3 fragPosition;
out vec2 fragTexCoord;
out vec4 fragColor;
out vec3 fragNormal;
out mat3 TBN;

const float normalOffset = 0.1;

void main()
{
    // Compute binormal from vertex normal and tangent
    vec3 vertexBinormal = cross(vertexNormal, vertexTangent);
    
    // Compute fragment normal based on normal transformations
    mat3 normalMatrix = transpose(inverse(mat3(matModel)));
    
    // Compute fragment position based on model transformations
    fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f));

    fragTexCoord = vertexTexCoord*2.0;
    fragNormal = normalize(normalMatrix*vertexNormal);
    vec3 fragTangent = normalize(normalMatrix*vertexTangent);
    fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal);
    vec3 fragBinormal = normalize(normalMatrix*vertexBinormal);
    fragBinormal = cross(fragNormal, fragTangent);

    TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal));

    // Calculate final vertex position
    gl_Position = mvp*vec4(vertexPosition, 1.0);
}


Baggey

Hi @Filax awsome work! I needed to make a few alterations to get it to run and compile?

Runnable code BlitzmaxNG

Code: BASIC
'SuperStrict

Framework Ray.GUI
Import Ray.Math
Import BRL.Math

' Constants
Const SCREEN_WIDTH:Int = 800
Const SCREEN_HEIGHT:Int = 450
Const MAX_LIGHTS:Int = 4
Const LIGHT_POINT:Int = 1

' Light structure
Type TLight
    Field position:RVector3
    Field target:RVector3
    Field color:RColor
    Field intensity:Float
    Field enabled:Int
    Field typeA:Int
    Field positionLoc:Int
    Field targetLoc:Int
    Field colorLoc:Int
    Field intensityLoc:Int
    Field enabledLoc:Int
    Field typeLoc:Int
End Type

' Create light
Function CreateLight:TLight(position:RVector3, target:RVector3, color:RColor, intensity:Float, shader:RShader, index:Int)
    Local light:TLight = New TLight
    light.position = position
    light.target = target
    light.color = color
    light.intensity = intensity
    light.enabled = 1
    light.typeA = LIGHT_POINT
    
    light.positionLoc = GetShaderLocation(shader, "lights[" + index + "].position")
    light.targetLoc = GetShaderLocation(shader, "lights[" + index + "].target")
    light.colorLoc = GetShaderLocation(shader, "lights[" + index + "].color")
    light.intensityLoc = GetShaderLocation(shader, "lights[" + index + "].intensity")
    light.enabledLoc = GetShaderLocation(shader, "lights[" + index + "].enabled")
    light.typeLoc = GetShaderLocation(Shader, "lights[" + Index + "].type")
    
    If light.positionLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].position not found")
    If light.targetLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].target not found")
    If light.colorLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].color not found")
    If light.intensityLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].intensity not found")
    If light.enabledLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].enabled not found")
    If light.typeLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].type not found")
    
    If light.positionLoc <> -1 And light.targetLoc <> -1 And light.colorLoc <> -1 And light.intensityLoc <> -1 And light.enabledLoc <> -1 And light.typeLoc <> -1 Then
        DebugLog("INFO: Light " + index + " initialized at Position (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ")")
    EndIf
    
    UpdateLightShader(light, shader)
    Return light
End Function

' Update light shader uniforms
Function UpdateLightShader(light:TLight, shader:RShader)
    SetShaderValue(shader, light.positionLoc, Varptr light.position.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, light.targetLoc, Varptr light.target.x, SHADER_UNIFORM_VEC3)
    Local colorVec4:RVector4 = ColorNormalize(light.color)
    SetShaderValue(shader, light.colorLoc, Varptr colorVec4.x, SHADER_UNIFORM_VEC4)
    SetShaderValue(shader, light.intensityLoc, Varptr light.intensity, SHADER_UNIFORM_FLOAT)
    SetShaderValue(shader, light.enabledLoc, Varptr light.enabled, SHADER_UNIFORM_INT)
    SetShaderValue(shader, light.typeLoc, Varptr light.typeA, SHADER_UNIFORM_INT)
    
    DebugLog("INFO: Light updated - Pos: (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ")")
End Function

' Main function
Function Main()
    ' Initialization
    SetConfigFlags(FLAG_MSAA_4X_HINT)
    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "BlitzMax [raylib] - Basic PBR")
    SetTargetFPS(60)
    
    ' Setup camera
    Local camera:RCamera = New RCamera
    camera.position = New RVector3(2.0, 2.0, 6.0)
    camera.target = New RVector3(0.0, 0.5, 0.0)
    camera.up = New RVector3(0.0, 1.0, 0.0)
    camera.fovy = 45.0
    camera.projection = CAMERA_PERSPECTIVE
    
    ' Load shader
    Local Shader:RShader = LoadShader("pbr.vs", "pbr.fs")
    If Not IsShaderValid(shader) Then
        DebugLog("ERROR: PBR shader not loaded")
        End
    EndIf
    
    ' Setup shader locations
    shader.locs[SHADER_LOC_MAP_ALBEDO] = GetShaderLocation(shader, "albedoMap")
    shader.locs[SHADER_LOC_MAP_METALNESS] = GetShaderLocation(shader, "mraMap")
    shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap")
    shader.locs[SHADER_LOC_MAP_EMISSION] = GetShaderLocation(shader, "emissiveMap")
    shader.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(shader, "albedoColor")
    shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos")
    
    If shader.locs[SHADER_LOC_MAP_ALBEDO] = -1 Then DebugLog("ERROR: Uniform albedoMap not found")
    If shader.locs[SHADER_LOC_MAP_METALNESS] = -1 Then DebugLog("ERROR: Uniform mraMap not found")
    If shader.locs[SHADER_LOC_MAP_NORMAL] = -1 Then DebugLog("ERROR: Uniform normalMap not found")
    If shader.locs[SHADER_LOC_MAP_EMISSION] = -1 Then DebugLog("ERROR: Uniform emissiveMap not found")
    If shader.locs[SHADER_LOC_COLOR_DIFFUSE] = -1 Then DebugLog("ERROR: Uniform albedoColor not found")
    If shader.locs[SHADER_LOC_VECTOR_VIEW] = -1 Then DebugLog("ERROR: Uniform viewPos not found")
    
    ' Setup light count
    Local lightCountLoc:Int = GetShaderLocation(shader, "numOfLights")
    Local maxLightCount:Int = MAX_LIGHTS
    SetShaderValue(shader, lightCountLoc, Varptr maxLightCount, SHADER_UNIFORM_INT)
    If lightCountLoc = -1 Then DebugLog("ERROR: Uniform numOfLights not found")
    
    ' Setup ambient
    Local ambientColor:RVector3 = New RVector3(26.0/255.0, 32.0/255.0, 135.0/255.0)
    Local ambientIntensity:Float = 0.02
    Local ambientLoc:Int = GetShaderLocation(shader, "ambient")
    SetShaderValue(shader, GetShaderLocation(shader, "ambientColor"), Varptr ambientColor.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, ambientLoc, Varptr ambientIntensity, SHADER_UNIFORM_FLOAT)
    If ambientLoc = -1 Then DebugLog("ERROR: Uniform ambient not found")
    
    ' Additional shader locations
    Local emissiveIntensityLoc:Int = GetShaderLocation(shader, "emissivePower")
    Local emissiveColorLoc:Int = GetShaderLocation(shader, "emissiveColor")
    Local textureTilingLoc:Int = GetShaderLocation(shader, "tiling")
    If emissiveIntensityLoc = -1 Then DebugLog("ERROR: Uniform emissivePower not found")
    If emissiveColorLoc = -1 Then DebugLog("ERROR: Uniform emissiveColor not found")
    If textureTilingLoc = -1 Then DebugLog("ERROR: Uniform tiling not found")
    
    ' Create models
    Local plane:RModel = LoadModelFromMesh(GenMeshPlane(10.0, 10.0, 10, 10))
    Local cube:RModel = LoadModelFromMesh(GenMeshCube(1.0, 1.0, 1.0))
    
    ' Assign shader
    plane.materials.shader = shader
    cube.materials.shader = shader
    
    ' Setup material properties
    plane.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
    plane.materials.maps[MATERIAL_MAP_METALNESS].value = 0.0
    plane.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.0
    plane.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
    plane.materials.maps[MATERIAL_MAP_EMISSION].color = BLACK
    
    cube.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
    cube.materials.maps[MATERIAL_MAP_METALNESS].value = 0.5
    cube.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.3
    cube.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
    cube.materials.maps[MATERIAL_MAP_EMISSION].color = BLACK
    
    ' Texture tiling
    Local tiling:RVector2 = New RVector2(0.5, 0.5)
    
    ' Create lights
    Global lights:TLight[MAX_LIGHTS]
    lights[0] = CreateLight(New RVector3(-1.0, 1.0, -2.0), New RVector3(0.0, 0.0, 0.0), YELLOW, 4.0, shader, 0)
    lights[1] = CreateLight(New RVector3(2.0, 1.0, 1.0), New RVector3(0.0, 0.0, 0.0), GREEN, 3.3, shader, 1)
    lights[2] = CreateLight(New RVector3(-2.0, 1.0, 1.0), New RVector3(0.0, 0.0, 0.0), RED, 8.3, shader, 2)
    lights[3] = CreateLight(New RVector3(1.0, 1.0, -2.0), New RVector3(0.0, 0.0, 0.0), BLUE, 2.0, shader, 3)
    
    ' Enable texture usage
    Local usage:Int = 0 ' Pas de textures pour simplifier
    SetShaderValue(shader, GetShaderLocation(shader, "useTexAlbedo"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexNormal"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexMRA"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexEmissive"), Varptr usage, SHADER_UNIFORM_INT)
    
    ' Main loop
    While Not WindowShouldClose()
        ' Update
        UpdateCamera(camera, CAMERA_ORBITAL)
        
        ' Update view position
        SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], Varptr camera.position.x, SHADER_UNIFORM_VEC3)
        
        ' Toggle lights
        If IsKeyPressed(KEY_ONE)
            lights[2].enabled = Not lights[2].enabled
            UpdateLightShader(lights[2], shader)
        EndIf
        If IsKeyPressed(KEY_TWO)
            lights[1].enabled = Not lights[1].enabled
            UpdateLightShader(lights[1], shader)
        EndIf
        If IsKeyPressed(KEY_THREE)
            lights[3].enabled = Not lights[3].enabled
            UpdateLightShader(lights[3], shader)
        EndIf
        If IsKeyPressed(KEY_FOUR)
            lights[0].enabled = Not lights[0].enabled
            UpdateLightShader(lights[0], shader)
        EndIf
        
        ' Draw
        BeginDrawing()
            ClearBackground(BLACK)
            
            BeginMode3D(camera)
                ' Draw plane
                SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                Local planeEmissiveColor:RVector4 = ColorNormalize(plane.materials.maps[MATERIAL_MAP_EMISSION].color)
                SetShaderValue(shader, emissiveColorLoc, Varptr planeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                DrawModel(plane, New RVector3(0.0, 0.0, 0.0), 1.0, WHITE)
                
                ' Draw cube
                SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                Local cubeEmissiveColor:RVector4 = ColorNormalize(cube.materials.maps[MATERIAL_MAP_EMISSION].color)
                SetShaderValue(shader, emissiveColorLoc, Varptr cubeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                Local emissiveIntensity:Float = 0.01
                SetShaderValue(shader, emissiveIntensityLoc, Varptr emissiveIntensity, SHADER_UNIFORM_FLOAT)
                DrawModel(cube, New RVector3(0.0, 1.0, 0.0), 1.0, WHITE)
                
                ' Draw light spheres
                For Local i:Int = 0 Until MAX_LIGHTS
                    If lights[i].enabled
                        DrawSphereEx(lights[i].position, 0.2, 8, 8, lights[i].color)
                    Else
                        DrawSphereWires(lights[i].position, 0.2, 8, 8, ColorAlpha(lights[i].color, 0.3))
                    EndIf
                Next
            EndMode3D()
            
            DrawText("Toggle lights: [1][2][3][4]", 10, 40, 20, LIGHTGRAY)
            DrawFPS(10, 10)
        EndDrawing()
    Wend
    
    ' Cleanup
    UnloadModel(plane)
    UnloadModel(cube)
    UnloadShader(shader)
    CloseWindow()
End Function
Main()

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Filax

#2
Quote from: Baggey on April 12, 2025, 09:08:11Hi @Filax awsome work! I needed to make a few alterations to get it to run and compile?
Runnable code BlitzmaxNG
Code: BASIC
'SuperStrict
Framework Ray.GUI
Import Ray.Math
Import BRL.Math
' Constants
Const SCREEN_WIDTH:Int = 800
Const SCREEN_HEIGHT:Int = 450
Const MAX_LIGHTS:Int = 4
Const LIGHT_POINT:Int = 1
' Light structure
Type TLight
    Field position:RVector3
    Field target:RVector3
    Field color:RColor
    Field intensity:Float
    Field enabled:Int
    Field typeA:Int
    Field positionLoc:Int
    Field targetLoc:Int
    Field colorLoc:Int
    Field intensityLoc:Int
    Field enabledLoc:Int
    Field typeLoc:Int
End Type
' Create light
Function CreateLight:TLight(position:RVector3, target:RVector3, color:RColor, intensity:Float, shader:RShader, index:Int)
    Local light:TLight = New TLight
    light.position = position
    light.target = target
    light.color = color
    light.intensity = intensity
    light.enabled = 1
    light.typeA = LIGHT_POINT
    
    light.positionLoc = GetShaderLocation(shader, "lights[" + index + "].position")
    light.targetLoc = GetShaderLocation(shader, "lights[" + index + "].target")
    light.colorLoc = GetShaderLocation(shader, "lights[" + index + "].color")
    light.intensityLoc = GetShaderLocation(shader, "lights[" + index + "].intensity")
    light.enabledLoc = GetShaderLocation(shader, "lights[" + index + "].enabled")
    light.typeLoc = GetShaderLocation(Shader, "lights[" + Index + "].type")
    
    If light.positionLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].position not found")
    If light.targetLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].target not found")
    If light.colorLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].color not found")
    If light.intensityLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].intensity not found")
    If light.enabledLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].enabled not found")
    If light.typeLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].type not found")
    
    If light.positionLoc <> -1 And light.targetLoc <> -1 And light.colorLoc <> -1 And light.intensityLoc <> -1 And light.enabledLoc <> -1 And light.typeLoc <> -1 Then
        DebugLog("INFO: Light " + index + " initialized at Position (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ")")
    EndIf
    
    UpdateLightShader(light, shader)
    Return light
End Function
' Update light shader uniforms
Function UpdateLightShader(light:TLight, shader:RShader)
    SetShaderValue(shader, light.positionLoc, Varptr light.position.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, light.targetLoc, Varptr light.target.x, SHADER_UNIFORM_VEC3)
    Local colorVec4:RVector4 = ColorNormalize(light.color)
    SetShaderValue(shader, light.colorLoc, Varptr colorVec4.x, SHADER_UNIFORM_VEC4)
    SetShaderValue(shader, light.intensityLoc, Varptr light.intensity, SHADER_UNIFORM_FLOAT)
    SetShaderValue(shader, light.enabledLoc, Varptr light.enabled, SHADER_UNIFORM_INT)
    SetShaderValue(shader, light.typeLoc, Varptr light.typeA, SHADER_UNIFORM_INT)
    
    DebugLog("INFO: Light updated - Pos: (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ")")
End Function
' Main function
Function Main()
    ' Initialization
    SetConfigFlags(FLAG_MSAA_4X_HINT)
    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "BlitzMax [raylib] - Basic PBR")
    SetTargetFPS(60)
    
    ' Setup camera
    Local camera:RCamera = New RCamera
    camera.position = New RVector3(2.0, 2.0, 6.0)
    camera.target = New RVector3(0.0, 0.5, 0.0)
    camera.up = New RVector3(0.0, 1.0, 0.0)
    camera.fovy = 45.0
    camera.projection = CAMERA_PERSPECTIVE
    
    ' Load shader
    Local Shader:RShader = LoadShader("pbr.vs", "pbr.fs")
    If Not IsShaderValid(shader) Then
        DebugLog("ERROR: PBR shader not loaded")
        End
    EndIf
    
    ' Setup shader locations
    shader.locs[SHADER_LOC_MAP_ALBEDO] = GetShaderLocation(shader, "albedoMap")
    shader.locs[SHADER_LOC_MAP_METALNESS] = GetShaderLocation(shader, "mraMap")
    shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap")
    shader.locs[SHADER_LOC_MAP_EMISSION] = GetShaderLocation(shader, "emissiveMap")
    shader.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(shader, "albedoColor")
    shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos")
    
    If shader.locs[SHADER_LOC_MAP_ALBEDO] = -1 Then DebugLog("ERROR: Uniform albedoMap not found")
    If shader.locs[SHADER_LOC_MAP_METALNESS] = -1 Then DebugLog("ERROR: Uniform mraMap not found")
    If shader.locs[SHADER_LOC_MAP_NORMAL] = -1 Then DebugLog("ERROR: Uniform normalMap not found")
    If shader.locs[SHADER_LOC_MAP_EMISSION] = -1 Then DebugLog("ERROR: Uniform emissiveMap not found")
    If shader.locs[SHADER_LOC_COLOR_DIFFUSE] = -1 Then DebugLog("ERROR: Uniform albedoColor not found")
    If shader.locs[SHADER_LOC_VECTOR_VIEW] = -1 Then DebugLog("ERROR: Uniform viewPos not found")
    
    ' Setup light count
    Local lightCountLoc:Int = GetShaderLocation(shader, "numOfLights")
    Local maxLightCount:Int = MAX_LIGHTS
    SetShaderValue(shader, lightCountLoc, Varptr maxLightCount, SHADER_UNIFORM_INT)
    If lightCountLoc = -1 Then DebugLog("ERROR: Uniform numOfLights not found")
    
    ' Setup ambient
    Local ambientColor:RVector3 = New RVector3(26.0/255.0, 32.0/255.0, 135.0/255.0)
    Local ambientIntensity:Float = 0.02
    Local ambientLoc:Int = GetShaderLocation(shader, "ambient")
    SetShaderValue(shader, GetShaderLocation(shader, "ambientColor"), Varptr ambientColor.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, ambientLoc, Varptr ambientIntensity, SHADER_UNIFORM_FLOAT)
    If ambientLoc = -1 Then DebugLog("ERROR: Uniform ambient not found")
    
    ' Additional shader locations
    Local emissiveIntensityLoc:Int = GetShaderLocation(shader, "emissivePower")
    Local emissiveColorLoc:Int = GetShaderLocation(shader, "emissiveColor")
    Local textureTilingLoc:Int = GetShaderLocation(shader, "tiling")
    If emissiveIntensityLoc = -1 Then DebugLog("ERROR: Uniform emissivePower not found")
    If emissiveColorLoc = -1 Then DebugLog("ERROR: Uniform emissiveColor not found")
    If textureTilingLoc = -1 Then DebugLog("ERROR: Uniform tiling not found")
    
    ' Create models
    Local plane:RModel = LoadModelFromMesh(GenMeshPlane(10.0, 10.0, 10, 10))
    Local cube:RModel = LoadModelFromMesh(GenMeshCube(1.0, 1.0, 1.0))
    
    ' Assign shader
    plane.materials.shader = shader
    cube.materials.shader = shader
    
    ' Setup material properties
    plane.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
    plane.materials.maps[MATERIAL_MAP_METALNESS].value = 0.0
    plane.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.0
    plane.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
    plane.materials.maps[MATERIAL_MAP_EMISSION].color = BLACK
    
    cube.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
    cube.materials.maps[MATERIAL_MAP_METALNESS].value = 0.5
    cube.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.3
    cube.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
    cube.materials.maps[MATERIAL_MAP_EMISSION].color = BLACK
    
    ' Texture tiling
    Local tiling:RVector2 = New RVector2(0.5, 0.5)
    
    ' Create lights
    Global lights:TLight[MAX_LIGHTS]
    lights[0] = CreateLight(New RVector3(-1.0, 1.0, -2.0), New RVector3(0.0, 0.0, 0.0), YELLOW, 4.0, shader, 0)
    lights[1] = CreateLight(New RVector3(2.0, 1.0, 1.0), New RVector3(0.0, 0.0, 0.0), GREEN, 3.3, shader, 1)
    lights[2] = CreateLight(New RVector3(-2.0, 1.0, 1.0), New RVector3(0.0, 0.0, 0.0), RED, 8.3, shader, 2)
    lights[3] = CreateLight(New RVector3(1.0, 1.0, -2.0), New RVector3(0.0, 0.0, 0.0), BLUE, 2.0, shader, 3)
    
    ' Enable texture usage
    Local usage:Int = 0 ' Pas de textures pour simplifier
    SetShaderValue(shader, GetShaderLocation(shader, "useTexAlbedo"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexNormal"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexMRA"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexEmissive"), Varptr usage, SHADER_UNIFORM_INT)
    
    ' Main loop
    While Not WindowShouldClose()
        ' Update
        UpdateCamera(camera, CAMERA_ORBITAL)
        
        ' Update view position
        SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], Varptr camera.position.x, SHADER_UNIFORM_VEC3)
        
        ' Toggle lights
        If IsKeyPressed(KEY_ONE)
            lights[2].enabled = Not lights[2].enabled
            UpdateLightShader(lights[2], shader)
        EndIf
        If IsKeyPressed(KEY_TWO)
            lights[1].enabled = Not lights[1].enabled
            UpdateLightShader(lights[1], shader)
        EndIf
        If IsKeyPressed(KEY_THREE)
            lights[3].enabled = Not lights[3].enabled
            UpdateLightShader(lights[3], shader)
        EndIf
        If IsKeyPressed(KEY_FOUR)
            lights[0].enabled = Not lights[0].enabled
            UpdateLightShader(lights[0], shader)
        EndIf
        
        ' Draw
        BeginDrawing()
            ClearBackground(BLACK)
            
            BeginMode3D(camera)
                ' Draw plane
                SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                Local planeEmissiveColor:RVector4 = ColorNormalize(plane.materials.maps[MATERIAL_MAP_EMISSION].color)
                SetShaderValue(shader, emissiveColorLoc, Varptr planeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                DrawModel(plane, New RVector3(0.0, 0.0, 0.0), 1.0, WHITE)
                
                ' Draw cube
                SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                Local cubeEmissiveColor:RVector4 = ColorNormalize(cube.materials.maps[MATERIAL_MAP_EMISSION].color)
                SetShaderValue(shader, emissiveColorLoc, Varptr cubeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                Local emissiveIntensity:Float = 0.01
                SetShaderValue(shader, emissiveIntensityLoc, Varptr emissiveIntensity, SHADER_UNIFORM_FLOAT)
                DrawModel(cube, New RVector3(0.0, 1.0, 0.0), 1.0, WHITE)
                
                ' Draw light spheres
                For Local i:Int = 0 Until MAX_LIGHTS
                    If lights[i].enabled
                        DrawSphereEx(lights[i].position, 0.2, 8, 8, lights[i].color)
                    Else
                        DrawSphereWires(lights[i].position, 0.2, 8, 8, ColorAlpha(lights[i].color, 0.3))
                    EndIf
                Next
            EndMode3D()
            
            DrawText("Toggle lights: [1][2][3][4]", 10, 40, 20, LIGHTGRAY)
            DrawFPS(10, 10)
        EndDrawing()
    Wend
    
    ' Cleanup
    UnloadModel(plane)
    UnloadModel(cube)
    UnloadShader(shader)
    CloseWindow()
End Function
Main()

Kind Regards Baggey

Thanks for the updates! Could someone please tell me which is the best Blitzmax currently? The one that's most updated? Because I'm lost...

Is it the one on Blitzmax.org or the famous Blitzmax NG? Which is more widely used? I'm using the Blitzmax.org version?!

Baggey

Unfortunately it's open source so there are now versions everywhere ::) 

It's still a very fast and powerful language though!

I use BlitzmaxNG 1.56 release 0.136

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!

Filax

#4
I try to include shadow inside the shader, but without result... If someone is better than me with shaders? I break my head on the shadow projection...

Code: BASIC
' Framework Ray.GUI
Import Ray.Math
Import BRL.Math

' Constants
Const SCREEN_WIDTH:Int = 1920
Const SCREEN_HEIGHT:Int = 1080
Const MAX_LIGHTS:Int = 4
Const LIGHT_POINT:Int = 1
Const DEG2RAD:Double = Pi / 180.0

' Light structure
Type TLight
    Field position:RVector3
    Field target:RVector3
    Field color:RColor
    Field intensity:Float
    Field enabled:Int
    Field typeA:Int
    Field positionLoc:Int
    Field targetLoc:Int
    Field colorLoc:Int
    Field intensityLoc:Int
    Field enabledLoc:Int
    Field typeLoc:Int
    Field shadowMap:RRenderTexture2D
    Field shadowMapLoc:Int
    Field lightVPLoc:Int
    Field castShadows:Int
    Field castShadowsLoc:Int
End Type

' Create light
Function CreateLight:TLight(position:RVector3, target:RVector3, color:RColor, intensity:Float, shader:RShader, index:Int)
    Local light:TLight = New TLight
    light.position = position
    light.target = target
    light.color = color
    light.intensity = intensity
    light.enabled = 1
    light.typeA = LIGHT_POINT
    light.castShadows = 0

    light.positionLoc = GetShaderLocation(shader, "lights[" + index + "].position")
    light.targetLoc = GetShaderLocation(shader, "lights[" + index + "].target")
    light.colorLoc = GetShaderLocation(shader, "lights[" + index + "].color")
    light.intensityLoc = GetShaderLocation(shader, "lights[" + index + "].intensity")
    light.enabledLoc = GetShaderLocation(shader, "lights[" + index + "].enabled")
    light.typeLoc = GetShaderLocation(shader, "lights[" + index + "].type")
    light.shadowMapLoc = GetShaderLocation(shader, "lights[" + index + "].shadowMap")
    light.lightVPLoc = GetShaderLocation(shader, "lights[" + index + "].lightVP")
    light.castShadowsLoc = GetShaderLocation(shader, "lights[" + index + "].castShadows")

    If light.positionLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].position not found")
    If light.targetLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].target not found")
    If light.colorLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].color not found")
    If light.intensityLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].intensity not found")
    If light.enabledLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].enabled not found")
    If light.typeLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].type not found")
    If light.shadowMapLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].shadowMap not found")
    If light.lightVPLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].lightVP not found")
    If light.castShadowsLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].castShadows not found")

    Local shadowMapWidth:Int = 2048
    Local shadowMapHeight:Int = 2048
    light.shadowMap = LoadRenderTexture(shadowMapWidth, shadowMapHeight)
    If Not IsRenderTextureValid(light.shadowMap) Then
        DebugLog("ERROR: Unable to create shadow map for light " + index)
    EndIf

    If light.positionLoc <> -1 And light.targetLoc <> -1 And light.colorLoc <> -1 And light.intensityLoc <> -1 And light.enabledLoc <> -1 And light.typeLoc <> -1 And light.castShadowsLoc <> -1 Then
        DebugLog("INFO: Light " + index + " initialized at position (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ")")
    EndIf

    UpdateLightShader(light, shader)
    Return light
End Function

' Update light shader uniforms
Function UpdateLightShader(light:TLight, shader:RShader)
    SetShaderValue(shader, light.positionLoc, Varptr light.position.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, light.targetLoc, Varptr light.target.x, SHADER_UNIFORM_VEC3)
    Local colorVec4:RVector4 = ColorNormalize(light.color)
    SetShaderValue(shader, light.colorLoc, Varptr colorVec4.x, SHADER_UNIFORM_VEC4)
    SetShaderValue(shader, light.intensityLoc, Varptr light.intensity, SHADER_UNIFORM_FLOAT)
    SetShaderValue(shader, light.enabledLoc, Varptr light.enabled, SHADER_UNIFORM_INT)
    SetShaderValue(shader, light.typeLoc, Varptr light.typeA, SHADER_UNIFORM_INT)
    SetShaderValue(shader, light.castShadowsLoc, Varptr light.castShadows, SHADER_UNIFORM_INT)

    If IsRenderTextureValid(light.shadowMap) Then
        SetShaderValueTexture(shader, light.shadowMapLoc, light.shadowMap.texture)
    EndIf

    DebugLog("INFO: Light updated - Pos: (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ") Shadows: " + light.castShadows)
End Function

' Main function
Function Main()
    SetConfigFlags(FLAG_MSAA_4X_HINT)
    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "BlitzMax [raylib] - Basic PBR with Shadows")
    SetTargetFPS(60)

    Local camera:RCamera = New RCamera
    camera.position = New RVector3(2.0, 2.0, 6.0)
    camera.target = New RVector3(0.0, 0.5, 0.0)
    camera.up = New RVector3(0.0, 1.0, 0.0)
    camera.fovy = 45.0
    camera.projection = CAMERA_PERSPECTIVE

    Local shader:RShader = LoadShader("pbr.vs", "pbr.fs")
    If Not IsShaderValid(shader) Then
        DebugLog("ERROR: Unable to load PBR shader. Using default rendering.")
    Else
        DebugLog("INFO: PBR shader loaded successfully")
    EndIf

    shader.locs[SHADER_LOC_MAP_ALBEDO] = GetShaderLocation(shader, "albedoMap")
    shader.locs[SHADER_LOC_MAP_METALNESS] = GetShaderLocation(shader, "mraMap")
    shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap")
    shader.locs[SHADER_LOC_MAP_EMISSION] = GetShaderLocation(shader, "emissiveMap")
    shader.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(shader, "albedoColor")
    shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos")

    Local lightCountLoc:Int = GetShaderLocation(shader, "numOfLights")
    Local maxLightCount:Int = MAX_LIGHTS
    SetShaderValue(shader, lightCountLoc, Varptr maxLightCount, SHADER_UNIFORM_INT)

    Local ambientColor:RVector3 = New RVector3(26.0/255.0, 32.0/255.0, 135.0/255.0)
    Local ambientIntensity:Float = 0.02
    Local ambientLoc:Int = GetShaderLocation(shader, "ambient")
    SetShaderValue(shader, GetShaderLocation(shader, "ambientColor"), Varptr ambientColor.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, ambientLoc, Varptr ambientIntensity, SHADER_UNIFORM_FLOAT)

    Local emissiveIntensityLoc:Int = GetShaderLocation(shader, "emissivePower")
    Local emissiveColorLoc:Int = GetShaderLocation(shader, "emissiveColor")
    Local textureTilingLoc:Int = GetShaderLocation(shader, "tiling")

    Local plane:RModel = LoadModelFromMesh(GenMeshPlane(10.0, 10.0, 10, 10))
    Local cube:RModel = LoadModelFromMesh(GenMeshCube(1.0, 1.0, 1.0))

    If IsShaderValid(shader) Then
        plane.materials.shader = shader
        cube.materials.shader = shader

        plane.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
        plane.materials.maps[MATERIAL_MAP_METALNESS].value = 0.0
        plane.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.0
        plane.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
        plane.materials.maps[MATERIAL_MAP_EMISSION].color = BLACK

        cube.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
        cube.materials.maps[MATERIAL_MAP_METALNESS].value = 0.5
        cube.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.3
        cube.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
        cube.materials.maps[MATERIAL_MAP_EMISSION].Color = Black
    EndIf

    Local tiling:RVector2 = New RVector2(0.5, 0.5)

' Creation of lights (with adjusted green light)'
Global lights:TLight[MAX_LIGHTS]
lights
 = CreateLight(New RVector3(0.0, 5.0, 0.0), New RVector3(0.0, 0.5, 0.0), YELLOW, 8.0, shader, 0)
lights[1] = CreateLight(New RVector3(2.0, 1.5, 1.0), New RVector3(0.0, 0.5, 0.0), GREEN, 3.3, shader, 1)
lights[2] = CreateLight(New RVector3(-2.0, 0.5, 1.0), New RVector3(0.0, 0.5, 0.0), RED, 8.3, shader, 2)
lights[3] = CreateLight(New RVector3(1.0, 0.5, -2.0), New RVector3(0.0, 0.5, 0.0), BLUE, 2.0, shader, 3)
lights.enabled = 0 ' Test with green only
lights[2].enabled = 0
lights[3].enabled = 0
    Local usage:Int = 0
    SetShaderValue(shader, GetShaderLocation(shader, "useTexAlbedo"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexNormal"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexMRA"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexEmissive"), Varptr usage, SHADER_UNIFORM_INT)
    Local shadowsEnabled:Int = 0
    Local depthShader:RShader = LoadShader("depth.vs", "depth.fs")
    If Not IsShaderValid(depthShader) Then
        DebugLog("ERROR: Unable to load depth shader")
    Else
        DebugLog("INFO: Depth shader loaded successfully")
    EndIf
    While Not WindowShouldClose()
        UpdateCamera(camera, CAMERA_ORBITAL)
        If IsShaderValid(shader) Then
            SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], Varptr camera.position.x, SHADER_UNIFORM_VEC3)
        EndIf
        If IsKeyPressed(KEY_ONE)
            lights[2].enabled = Not lights[2].enabled
            UpdateLightShader(lights[2], shader)
        EndIf
        If IsKeyPressed(KEY_TWO)
            lights[1].enabled = Not lights[1].enabled
            UpdateLightShader(lights[1], shader)
        EndIf
        If IsKeyPressed(KEY_THREE)
            lights[3].enabled = Not lights[3].enabled
            UpdateLightShader(lights[3], shader)
        EndIf
        If IsKeyPressed(KEY_FOUR)
            lights.enabled = Not lights.enabled
            UpdateLightShader(lights, shader)
        EndIf
        If IsKeyPressed(KEY_S)
            shadowsEnabled = Not shadowsEnabled
           ' DebugLog("Shadows " + (shadowsEnabled ? "enabled" : "disabled"))
            For Local i:Int = 0 Until MAX_LIGHTS
                lights[i].castShadows = shadowsEnabled
                UpdateLightShader(lights[i], shader)
            Next
        EndIf
        Local lightCamera:RCamera = New RCamera
' Shadow map rendering loop
For Local i:Int = 0 Until MAX_LIGHTS
    If lights[i].enabled And lights[i].castShadows And IsShaderValid(depthShader)
        lightCamera.position = lights[i].position
        lightCamera.target = New RVector3(0.0, 0.5, 0.0)
        lightCamera.up = New RVector3(0.0, 1.0, 0.0)
        lightCamera.fovy = 120.0
        lightCamera.projection = CAMERA_PERSPECTIVE
        Local viewMatrix:RMatrix = MatrixLookAt(lights[i].position, New RVector3(0.0, 0.5, 0.0), New RVector3(0.0, 1.0, 0.0))
        Local projMatrix:RMatrix = MatrixPerspective(120.0 * DEG2RAD, 1.0, 0.001, 200.0)
        Local lightVP:RMatrix = MatrixMultiply(viewMatrix, projMatrix)
        If IsShaderValid(shader) Then
            SetShaderValueMatrix(shader, lights[i].lightVPLoc, lightVP)
            DebugLog("Light " + i + " position: (" + lights[i].position.x + ", " + lights[i].position.y + ", " + lights[i].position.z + ")")
            DebugLog("Light " + i + " VP matrix: [" + lightVP.m0 + ", " + lightVP.m1 + ", ..., " + lightVP.m15 + "]")
        EndIf
        BeginTextureMode(lights[i].shadowMap)
            ClearBackground(New RColor(255, 255, 255, 255))
            BeginMode3D(lightCamera)
                plane.materials.shader = depthShader
                cube.materials.shader = depthShader
                DebugLog("Rendering plane for light " + i)
                DrawModel(plane, New RVector3(0.0, 0.0, 0.0), 1.0, WHITE)
                DebugLog("Rendering cube for light " + i)
                DrawModel(cube, New RVector3(0.0, 1.0, 0.0), 1.0, WHITE)
                plane.materials.shader = shader
                cube.materials.shader = shader
            EndMode3D()
         '  Local glError:Int = glGetError()
        '   If glError <> 0 Then DebugLog("OpenGL error after rendering shadow map for light " + i + ": " + glError)
            DebugLog("Shadow map rendered for light " + i + " - Texture ID: " + lights[i].shadowMap.texture.id)
        EndTextureMode()
    EndIf
Next
        BeginDrawing()
            ClearBackground(BLACK)
            BeginMode3D(camera)
                If IsShaderValid(shader) Then
                    SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                    Local planeEmissiveColor:RVector4 = ColorNormalize(plane.materials.maps[MATERIAL_MAP_EMISSION].color)
                    SetShaderValue(shader, emissiveColorLoc, Varptr planeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                EndIf
                DrawModel(plane, New RVector3(0.0, 0.0, 0.0), 1.0, WHITE)
                If IsShaderValid(shader) Then
                    SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                    Local cubeEmissiveColor:RVector4 = ColorNormalize(cube.materials.maps[MATERIAL_MAP_EMISSION].color)
                    SetShaderValue(shader, emissiveColorLoc, Varptr cubeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                    Local emissiveIntensity:Float = 0.01
                    SetShaderValue(shader, emissiveIntensityLoc, Varptr emissiveIntensity, SHADER_UNIFORM_FLOAT)
                EndIf
                DrawModel(cube, New RVector3(0.0, 1.0, 0.0), 1.0, WHITE)
                For Local i:Int = 0 Until MAX_LIGHTS
                    If lights[i].enabled
                        DrawSphereEx(lights[i].position, 0.2, 8, 8, lights[i].color)
                    Else
                        DrawSphereWires(lights[i].position, 0.2, 8, 8, ColorAlpha(lights[i].color, 0.3))
                    EndIf
                Next
            EndMode3D()
' Display of shadow maps
For Local i:Int = 0 Until MAX_LIGHTS
    If lights[i].enabled And lights[i].castShadows
        DrawRectangle(5 + i * 110, 65, 100, 100, New RColor(50, 50, 50, 255))
        DrawTextureRec(lights[i].shadowMap.texture, New RRectangle(0, 0, 256, -256), New RVector2(10 + i * 110, 70), WHITE)
        DrawRectangleLines(5 + i * 110, 65, 100, 100, lights[i].color)
        DrawText("Light " + i, 10 + i * 110, 40, 20, YELLOW)
        DebugLog("Displaying shadow map for light " + i)
    EndIf
Next
            DrawText("Toggle lights: [1][2][3][4] - Toggle shadows: [S]", 10, 40, 20, LIGHTGRAY)
            DrawFPS(10, 10)
        EndDrawing()
    Wend
    For Local i:Int = 0 Until MAX_LIGHTS
        UnloadRenderTexture(lights[i].shadowMap)
    Next
    UnloadModel(plane)
    UnloadModel(cube)
    UnloadShader(shader)
    UnloadShader(depthShader)
    CloseWindow()
End Function
Main()



Baggey

I got it running in BlitzmaxNG for you! Have no idea if it does what it is supposed too!?  ;)

Code: BASIC
' Framework Ray.GUI
Import Ray.Math
Import BRL.Math

' Constants
Const SCREEN_WIDTH:Int = 1920
Const SCREEN_HEIGHT:Int = 1080
Const MAX_LIGHTS:Int = 4
Const LIGHT_POINT:Int = 1
Const DEG2RAD:Double = Pi / 180.0

' Light structure
Type TLight
    Field position:RVector3
    Field target:RVector3
    Field color:RColor
    Field intensity:Float
    Field enabled:Int
    Field typeA:Int
    Field positionLoc:Int
    Field targetLoc:Int
    Field colorLoc:Int
    Field intensityLoc:Int
    Field enabledLoc:Int
    Field typeLoc:Int
    Field shadowMap:RRenderTexture2D
    Field shadowMapLoc:Int
    Field lightVPLoc:Int
    Field castShadows:Int
    Field castShadowsLoc:Int
End Type

' Create light
Function CreateLight:TLight(position:RVector3, target:RVector3, color:RColor, intensity:Float, shader:RShader, index:Int)
    Local light:TLight = New TLight
    light.position = position
    light.target = target
    light.color = color
    light.intensity = intensity
    light.enabled = 1
    light.typeA = LIGHT_POINT
    light.castShadows = 0

    light.positionLoc = GetShaderLocation(shader, "lights[" + index + "].position")
    light.targetLoc = GetShaderLocation(shader, "lights[" + index + "].target")
    light.colorLoc = GetShaderLocation(shader, "lights[" + index + "].color")
    light.intensityLoc = GetShaderLocation(shader, "lights[" + index + "].intensity")
    light.enabledLoc = GetShaderLocation(shader, "lights[" + index + "].enabled")
    light.typeLoc = GetShaderLocation(shader, "lights[" + index + "].type")
    light.shadowMapLoc = GetShaderLocation(shader, "lights[" + index + "].shadowMap")
    light.lightVPLoc = GetShaderLocation(shader, "lights[" + index + "].lightVP")
    light.castShadowsLoc = GetShaderLocation(shader, "lights[" + index + "].castShadows")

    If light.positionLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].position not found")
    If light.targetLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].target not found")
    If light.colorLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].color not found")
    If light.intensityLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].intensity not found")
    If light.enabledLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].enabled not found")
    If light.typeLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].type not found")
    If light.shadowMapLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].shadowMap not found")
    If light.lightVPLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].lightVP not found")
    If light.castShadowsLoc = -1 Then DebugLog("ERROR: Uniform lights[" + index + "].castShadows not found")

    Local shadowMapWidth:Int = 2048
    Local shadowMapHeight:Int = 2048
    light.shadowMap = LoadRenderTexture(shadowMapWidth, shadowMapHeight)
    If Not IsRenderTextureValid(light.shadowMap) Then
        DebugLog("ERROR: Unable to create shadow map for light " + index)
    EndIf

    If light.positionLoc <> -1 And light.targetLoc <> -1 And light.colorLoc <> -1 And light.intensityLoc <> -1 And light.enabledLoc <> -1 And light.typeLoc <> -1 And light.castShadowsLoc <> -1 Then
        DebugLog("INFO: Light " + index + " initialized at position (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ")")
    EndIf

    UpdateLightShader(light, shader)
    Return light
End Function

' Update light shader uniforms
Function UpdateLightShader(light:TLight, shader:RShader)
    SetShaderValue(shader, light.positionLoc, Varptr light.position.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, light.targetLoc, Varptr light.target.x, SHADER_UNIFORM_VEC3)
    Local colorVec4:RVector4 = ColorNormalize(light.color)
    SetShaderValue(shader, light.colorLoc, Varptr colorVec4.x, SHADER_UNIFORM_VEC4)
    SetShaderValue(shader, light.intensityLoc, Varptr light.intensity, SHADER_UNIFORM_FLOAT)
    SetShaderValue(shader, light.enabledLoc, Varptr light.enabled, SHADER_UNIFORM_INT)
    SetShaderValue(shader, light.typeLoc, Varptr light.typeA, SHADER_UNIFORM_INT)
    SetShaderValue(shader, light.castShadowsLoc, Varptr light.castShadows, SHADER_UNIFORM_INT)

    If IsRenderTextureValid(light.shadowMap) Then
        SetShaderValueTexture(shader, light.shadowMapLoc, light.shadowMap.texture)
    EndIf

    DebugLog("INFO: Light updated - Pos: (" + light.position.x + ", " + light.position.y + ", " + light.position.z + ") Shadows: " + light.castShadows)
End Function

' Main function
Function Main()
    SetConfigFlags(FLAG_MSAA_4X_HINT)
    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "BlitzMax [raylib] - Basic PBR with Shadows")
    SetTargetFPS(60)

    Local camera:RCamera = New RCamera
    camera.position = New RVector3(2.0, 2.0, 6.0)
    camera.target = New RVector3(0.0, 0.5, 0.0)
    camera.up = New RVector3(0.0, 1.0, 0.0)
    camera.fovy = 45.0
    camera.projection = CAMERA_PERSPECTIVE

    Local shader:RShader = LoadShader("pbr.vs", "pbr.fs")
    If Not IsShaderValid(shader) Then
        DebugLog("ERROR: Unable to load PBR shader. Using default rendering.")
    Else
        DebugLog("INFO: PBR shader loaded successfully")
    EndIf

    shader.locs[SHADER_LOC_MAP_ALBEDO] = GetShaderLocation(shader, "albedoMap")
    shader.locs[SHADER_LOC_MAP_METALNESS] = GetShaderLocation(shader, "mraMap")
    shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap")
    shader.locs[SHADER_LOC_MAP_EMISSION] = GetShaderLocation(shader, "emissiveMap")
    shader.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(shader, "albedoColor")
    shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos")

    Local lightCountLoc:Int = GetShaderLocation(shader, "numOfLights")
    Local maxLightCount:Int = MAX_LIGHTS
    SetShaderValue(shader, lightCountLoc, Varptr maxLightCount, SHADER_UNIFORM_INT)

    Local ambientColor:RVector3 = New RVector3(26.0/255.0, 32.0/255.0, 135.0/255.0)
    Local ambientIntensity:Float = 0.02
    Local ambientLoc:Int = GetShaderLocation(shader, "ambient")
    SetShaderValue(shader, GetShaderLocation(shader, "ambientColor"), Varptr ambientColor.x, SHADER_UNIFORM_VEC3)
    SetShaderValue(shader, ambientLoc, Varptr ambientIntensity, SHADER_UNIFORM_FLOAT)

    Local emissiveIntensityLoc:Int = GetShaderLocation(shader, "emissivePower")
    Local emissiveColorLoc:Int = GetShaderLocation(shader, "emissiveColor")
    Local textureTilingLoc:Int = GetShaderLocation(shader, "tiling")

    Local plane:RModel = LoadModelFromMesh(GenMeshPlane(10.0, 10.0, 10, 10))
    Local cube:RModel = LoadModelFromMesh(GenMeshCube(1.0, 1.0, 1.0))

    If IsShaderValid(shader) Then
        plane.materials.shader = shader
        cube.materials.shader = shader

        plane.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
        plane.materials.maps[MATERIAL_MAP_METALNESS].value = 0.0
        plane.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.0
        plane.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
        plane.materials.maps[MATERIAL_MAP_EMISSION].color = BLACK

        cube.materials.maps[MATERIAL_MAP_ALBEDO].color = WHITE
        cube.materials.maps[MATERIAL_MAP_METALNESS].value = 0.5
        cube.materials.maps[MATERIAL_MAP_ROUGHNESS].value = 0.3
        cube.materials.maps[MATERIAL_MAP_OCCLUSION].value = 1.0
        cube.materials.maps[MATERIAL_MAP_EMISSION].Color = Black
    EndIf

    Local tiling:RVector2 = New RVector2(0.5, 0.5)

' Creation of lights (with adjusted green light)'
Global lights:TLight[MAX_LIGHTS]
lights[0] = CreateLight(New RVector3(0.0, 5.0, 0.0), New RVector3(0.0, 0.5, 0.0), YELLOW, 8.0, shader, 0)
lights[1] = CreateLight(New RVector3(2.0, 1.5, 1.0), New RVector3(0.0, 0.5, 0.0), GREEN, 3.3, shader, 1)
lights[2] = CreateLight(New RVector3(-2.0, 0.5, 1.0), New RVector3(0.0, 0.5, 0.0), RED, 8.3, shader, 2)
lights[3] = CreateLight(New RVector3(1.0, 0.5, -2.0), New RVector3(0.0, 0.5, 0.0), BLUE, 2.0, shader, 3)
lights[1].enabled = 0 ' Test with green only
lights[2].enabled = 0
lights[3].enabled = 0
    Local usage:Int = 0
    SetShaderValue(shader, GetShaderLocation(shader, "useTexAlbedo"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexNormal"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexMRA"), Varptr usage, SHADER_UNIFORM_INT)
    SetShaderValue(shader, GetShaderLocation(shader, "useTexEmissive"), Varptr usage, SHADER_UNIFORM_INT)
    Local shadowsEnabled:Int = 0
    Local depthShader:RShader = LoadShader("depth.vs", "depth.fs")
    If Not IsShaderValid(depthShader) Then
        DebugLog("ERROR: Unable to load depth shader")
    Else
        DebugLog("INFO: Depth shader loaded successfully")
    EndIf
    While Not WindowShouldClose()
        UpdateCamera(camera, CAMERA_ORBITAL)
        If IsShaderValid(shader) Then
            SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], Varptr camera.position.x, SHADER_UNIFORM_VEC3)
        EndIf
        If IsKeyPressed(KEY_ONE)
            lights[2].enabled = Not lights[2].enabled
            UpdateLightShader(lights[2], shader)
        EndIf
        If IsKeyPressed(KEY_TWO)
            lights[1].enabled = Not lights[1].enabled
            UpdateLightShader(lights[1], shader)
        EndIf
        If IsKeyPressed(KEY_THREE)
            lights[3].enabled = Not lights[3].enabled
            UpdateLightShader(lights[3], shader)
        EndIf
        If IsKeyPressed(KEY_FOUR)
            lights[0].enabled = Not lights[0].enabled
            UpdateLightShader(lights[0], shader)
        EndIf
        If IsKeyPressed(KEY_FIVE)
            shadowsEnabled = Not shadowsEnabled
           ' DebugLog("Shadows " + (shadowsEnabled ? "enabled" : "disabled"))
            For Local i:Int = 0 Until MAX_LIGHTS
                lights[i].castShadows = shadowsEnabled
                UpdateLightShader(lights[i], shader)
            Next
        EndIf
        Local lightCamera:RCamera = New RCamera
' Shadow map rendering loop
For Local i:Int = 0 Until MAX_LIGHTS
    If lights[i].enabled And lights[i].castShadows And IsShaderValid(depthShader)
        lightCamera.position = lights[i].position
        lightCamera.target = New RVector3(0.0, 0.5, 0.0)
        lightCamera.up = New RVector3(0.0, 1.0, 0.0)
        lightCamera.fovy = 120.0
        lightCamera.projection = CAMERA_PERSPECTIVE
        Local viewMatrix:RMatrix = MatrixLookAt(lights[i].position, New RVector3(0.0, 0.5, 0.0), New RVector3(0.0, 1.0, 0.0))
        Local projMatrix:RMatrix = MatrixPerspective(120.0 * DEG2RAD, 1.0, 0.001, 200.0)
        Local lightVP:RMatrix = MatrixMultiply(viewMatrix, projMatrix)
        If IsShaderValid(shader) Then
            SetShaderValueMatrix(shader, lights[i].lightVPLoc, lightVP)
            DebugLog("Light " + i + " position: (" + lights[i].position.x + ", " + lights[i].position.y + ", " + lights[i].position.z + ")")
            DebugLog("Light " + i + " VP matrix: [" + lightVP.m0 + ", " + lightVP.m1 + ", ..., " + lightVP.m15 + "]")
        EndIf
        BeginTextureMode(lights[i].shadowMap)
            ClearBackground(New RColor(255, 255, 255, 255))
            BeginMode3D(lightCamera)
                plane.materials.shader = depthShader
                cube.materials.shader = depthShader
                DebugLog("Rendering plane for light " + i)
                DrawModel(plane, New RVector3(0.0, 0.0, 0.0), 1.0, WHITE)
                DebugLog("Rendering cube for light " + i)
                DrawModel(cube, New RVector3(0.0, 1.0, 0.0), 1.0, WHITE)
                plane.materials.shader = shader
                cube.materials.shader = shader
            EndMode3D()
         '  Local glError:Int = glGetError()
        '   If glError <> 0 Then DebugLog("OpenGL error after rendering shadow map for light " + i + ": " + glError)
            DebugLog("Shadow map rendered for light " + i + " - Texture ID: " + lights[i].shadowMap.texture.id)
        EndTextureMode()
    EndIf
Next
        BeginDrawing()
            ClearBackground(BLACK)
            BeginMode3D(camera)
                If IsShaderValid(shader) Then
                    SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                    Local planeEmissiveColor:RVector4 = ColorNormalize(plane.materials.maps[MATERIAL_MAP_EMISSION].color)
                    SetShaderValue(shader, emissiveColorLoc, Varptr planeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                EndIf
                DrawModel(plane, New RVector3(0.0, 0.0, 0.0), 1.0, WHITE)
                If IsShaderValid(shader) Then
                    SetShaderValue(shader, textureTilingLoc, Varptr tiling.x, SHADER_UNIFORM_VEC2)
                    Local cubeEmissiveColor:RVector4 = ColorNormalize(cube.materials.maps[MATERIAL_MAP_EMISSION].color)
                    SetShaderValue(shader, emissiveColorLoc, Varptr cubeEmissiveColor.x, SHADER_UNIFORM_VEC4)
                    Local emissiveIntensity:Float = 0.01
                    SetShaderValue(shader, emissiveIntensityLoc, Varptr emissiveIntensity, SHADER_UNIFORM_FLOAT)
                EndIf
                DrawModel(cube, New RVector3(0.0, 1.0, 0.0), 1.0, WHITE)
                For Local i:Int = 0 Until MAX_LIGHTS
                    If lights[i].enabled
                        DrawSphereEx(lights[i].position, 0.2, 8, 8, lights[i].color)
                    Else
                        DrawSphereWires(lights[i].position, 0.2, 8, 8, ColorAlpha(lights[i].color, 0.3))
                    EndIf
                Next
            EndMode3D()
' Display of shadow maps
For Local i:Int = 0 Until MAX_LIGHTS
    If lights[i].enabled And lights[i].castShadows
        DrawRectangle(5 + i * 110, 65, 100, 100, New RColor(50, 50, 50, 255))
        DrawTextureRec(lights[i].shadowMap.texture, New RRectangle(0, 0, 256, -256), New RVector2(10 + i * 110, 70), WHITE)
        DrawRectangleLines(5 + i * 110, 65, 100, 100, lights[i].color)
        DrawText("Light " + i, 10 + i * 110, 40, 20, YELLOW)
        DebugLog("Displaying shadow map for light " + i)
    EndIf
Next
            DrawText("Toggle lights: [1][2][3][4] - Toggle shadows: [S]", 10, 40, 20, LIGHTGRAY)
            DrawFPS(10, 10)
        EndDrawing()
    Wend
    For Local i:Int = 0 Until MAX_LIGHTS
        UnloadRenderTexture(lights[i].shadowMap)
    Next
    UnloadModel(plane)
    UnloadModel(cube)
    UnloadShader(shader)
    UnloadShader(depthShader)
    CloseWindow()
End Function
Main()

Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on 2 x HP Z24's . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Raspberry Pi Black Edition! , ZX Spectrum 48k, C64, Enterprise 128K, The SID chip. Im Misunderstood!