From 6d16287bcb2056abeae526386800765128cc8aa5 Mon Sep 17 00:00:00 2001 From: emil28092005 Date: Wed, 17 Jun 2026 18:07:13 +0300 Subject: [PATCH] fix: shadow map re-bind after DrawModelEx + transpose lightViewProj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bind shadow map on MaterialMapIndex.Emission (unit 1) per entity - Re-bind via Rlgl.ActiveTextureSlot(1)+EnableTexture after DrawModelEx (DrawModelEx resets texture state internally) - Transpose lightViewProj matrix (Raylib row-major → OpenGL column-major) - 66/66 tests, 145 FPS --- imgui.ini | 4 +-- src/Engine.Graphics.Raylib/RaylibRenderer.cs | 30 ++++++++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/imgui.ini b/imgui.ini index e0f93dd..0dd958a 100644 --- a/imgui.ini +++ b/imgui.ini @@ -14,7 +14,7 @@ Size=250,398 Collapsed=0 [Window][Inspector] -Pos=740,357 -Size=300,400 +Pos=740,354 +Size=300,403 Collapsed=0 diff --git a/src/Engine.Graphics.Raylib/RaylibRenderer.cs b/src/Engine.Graphics.Raylib/RaylibRenderer.cs index d41eed1..d485dcc 100644 --- a/src/Engine.Graphics.Raylib/RaylibRenderer.cs +++ b/src/Engine.Graphics.Raylib/RaylibRenderer.cs @@ -133,7 +133,10 @@ public sealed class RaylibRenderer : IRenderer Raylib.BeginMode3D(shadowCamera); // Grab light view/proj matrices AFTER BeginMode3D (like official example) - lightViewProj = Rlgl.GetMatrixModelview() * Rlgl.GetMatrixProjection(); + // Raylib matrices are row-major, need to transpose for OpenGL (column-major) + var lv = Rlgl.GetMatrixModelview(); + var lp = Rlgl.GetMatrixProjection(); + lightViewProj = Matrix4x4.Transpose(lv * lp); // Draw all shadow casters with the simple shadow shader world.Each((Entity e, ref EngineMesh mesh, ref EngineTransform transform) => @@ -175,17 +178,12 @@ public sealed class RaylibRenderer : IRenderer if (hasDirectionalLight && _lightViewProjLoc >= 0) { Raylib.SetShaderValueMatrix(_shader, _lightViewProjLoc, lightViewProj); - // Bind shadow map on texture unit 1, tell shader sampler to use it - if (_shadowMapLoc >= 0) - { - Rlgl.ActiveTextureSlot(1); - Rlgl.EnableTexture(_shadowDepthTex); - Raylib.SetShaderValue(_shader, _shadowMapLoc, 1, ShaderUniformDataType.Int); - } } Rlgl.DisableBackfaceCulling(); + var shadowTex = new Texture2D { Id = _shadowDepthTex, Width = ShadowMapSize, Height = ShadowMapSize, Mipmaps = 1, Format = PixelFormat.UncompressedR16 }; + world.Each((Entity e, ref EngineMesh mesh, ref EngineTransform transform) => { if (e.Name() == "Grid") @@ -199,7 +197,23 @@ public sealed class RaylibRenderer : IRenderer { var (axis, angle) = QuaternionToAxisAngle(rotation); SetMaterialUniforms(material, model); + + // Bind shadow map on Emission slot (texture unit 1) for each entity + if (hasDirectionalLight && _shadowMapLoc >= 0) + { + unsafe { Raylib.SetMaterialTexture(ref model.Materials[0], MaterialMapIndex.Emission, shadowTex); } + } + Raylib.DrawModelEx(model, position, axis, angle * 180.0f / MathF.PI, scale, Color.White); + + // Re-bind shadow map on unit 1 after DrawModelEx (it may have reset texture state) + if (hasDirectionalLight && _shadowMapLoc >= 0) + { + Rlgl.ActiveTextureSlot(1); + Rlgl.EnableTexture(_shadowDepthTex); + Raylib.SetShaderValue(_shader, _shadowMapLoc, 1, ShaderUniformDataType.Int); + Rlgl.ActiveTextureSlot(0); + } } });