feat: materials, floor grid, specular lighting, orbit camera

- Add Material component with Albedo, Roughness, Metallic.
- MeshRenderer reads Material and tints vertex color; falls back to default.
- Add Blinn-Phong specular using camera position pushed via push constants.
- Add floor plane and grid mesh in Program.cs.
- Add OrbitCameraController with right-mouse orbit and mouse-wheel zoom.
- Forward SDL events to InputMapping from Sdl3Window.PumpEvents.
- Update main loop to update camera and aspect ratio on resize.
- Recompile SPIR-V shaders.
- Update CORTEX_ENGINE_ARCHITECTURE.md with Material, lighting, and orbit camera.
This commit is contained in:
emil28092005
2026-06-16 20:28:32 +03:00
parent 98a429710a
commit 751e403c0c
12 changed files with 252 additions and 35 deletions
+17 -14
View File
@@ -38,6 +38,8 @@ public sealed unsafe class MeshRenderer : IDisposable
public float Pad2;
public Vector3 AmbientColor;
public float Pad3;
public Vector3 CameraPosition;
public float Pad4;
}
private sealed class MeshBuffers : IDisposable
@@ -201,19 +203,19 @@ public sealed unsafe class MeshRenderer : IDisposable
_buffers[e] = buffers;
}
var bytes = BuildMeshVertices(mesh, transform);
var material = e.Has<Material>() ? e.Get<Material>() : Material.Default;
var bytes = BuildMeshVertices(mesh, transform, material);
buffers.VertexBuffer.Update(bytes);
var model = transform.GetMatrix();
var mvp = Matrix4x4.Multiply(Matrix4x4.Multiply(model, view), proj);
var mvpT = Matrix4x4.Transpose(mvp);
var mvp = Matrix4x4.Transpose(Matrix4x4.Multiply(view, proj));
var push = new PushConstants
{
Mvp = mvpT,
Mvp = mvp,
LightDirection = new Vector3(0.5f, -1.0f, -0.5f),
LightColor = new Vector3(1.0f, 0.95f, 0.8f),
AmbientColor = new Vector3(0.15f, 0.15f, 0.2f)
AmbientColor = new Vector3(0.15f, 0.15f, 0.2f),
CameraPosition = camera.Position
};
var pushSize = (uint)sizeof(PushConstants);
@@ -306,7 +308,7 @@ public sealed unsafe class MeshRenderer : IDisposable
new IndexBuffer(_context, indexBytes, (uint)mesh.Indices.Length));
}
private byte[] BuildMeshVertices(Mesh mesh, Transform transform)
private byte[] BuildMeshVertices(Mesh mesh, Transform transform, Material material)
{
var matrix = transform.GetMatrix();
var bytes = new byte[mesh.Vertices.Length * 9 * sizeof(float)];
@@ -316,14 +318,15 @@ public sealed unsafe class MeshRenderer : IDisposable
for (var i = 0; i < mesh.Vertices.Length; i++)
{
var v = mesh.Vertices[i];
var transformed = Vector3.Transform(v.Position, matrix);
var worldPos = Vector3.Transform(v.Position, matrix);
var normal = transform.TransformNormal(v.Normal);
dst[i * 9 + 0] = transformed.X;
dst[i * 9 + 1] = transformed.Y;
dst[i * 9 + 2] = transformed.Z;
dst[i * 9 + 3] = v.Color.X;
dst[i * 9 + 4] = v.Color.Y;
dst[i * 9 + 5] = v.Color.Z;
var color = v.Color * material.Albedo;
dst[i * 9 + 0] = worldPos.X;
dst[i * 9 + 1] = worldPos.Y;
dst[i * 9 + 2] = worldPos.Z;
dst[i * 9 + 3] = color.X;
dst[i * 9 + 4] = color.Y;
dst[i * 9 + 5] = color.Z;
dst[i * 9 + 6] = normal.X;
dst[i * 9 + 7] = normal.Y;
dst[i * 9 + 8] = normal.Z;
+8 -1
View File
@@ -15,17 +15,24 @@ layout(push_constant) uniform PushConstants
float pad2;
vec3 ambientColor;
float pad3;
vec3 cameraPosition;
float pad4;
} push;
void main()
{
vec3 normal = normalize(fragNormal);
vec3 lightDir = normalize(-push.lightDirection);
vec3 viewDir = normalize(push.cameraPosition - fragWorldPos);
vec3 halfDir = normalize(lightDir + viewDir);
float diff = max(dot(normal, lightDir), 0.0);
float spec = pow(max(dot(normal, halfDir), 0.0), 64.0) * 0.5;
vec3 diffuse = push.lightColor * diff;
vec3 specular = push.lightColor * spec;
vec3 ambient = push.ambientColor;
vec3 result = (ambient + diffuse) * fragColor;
vec3 result = (ambient + diffuse + specular) * fragColor;
outColor = vec4(result, 1.0);
}
Binary file not shown.
Binary file not shown.
+2
View File
@@ -17,6 +17,8 @@ layout(push_constant) uniform PushConstants
float pad2;
vec3 ambientColor;
float pad3;
vec3 cameraPosition;
float pad4;
} push;
void main()
+1 -1
View File
@@ -59,7 +59,7 @@ public sealed unsafe class VulkanPipeline : IDisposable
{
StageFlags = ShaderStageFlags.VertexBit | ShaderStageFlags.FragmentBit,
Offset = 0,
Size = (uint)(28 * sizeof(float))
Size = (uint)(32 * sizeof(float))
};
var createInfo = new PipelineLayoutCreateInfo