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:
@@ -261,6 +261,13 @@ public struct Camera : IComponent
|
||||
public float Far;
|
||||
}
|
||||
|
||||
public struct Material : IComponent
|
||||
{
|
||||
public Vector3 Albedo;
|
||||
public float Roughness;
|
||||
public float Metallic;
|
||||
}
|
||||
|
||||
public struct SemanticClass : IComponent
|
||||
{
|
||||
public byte ClassId; // 0=environment, 1=enemy, 2=player, 3=interactive, 4=trigger
|
||||
@@ -283,7 +290,17 @@ When the AI generates a C# script, the engine:
|
||||
|
||||
**Important caveat:** Flecs stores component type metadata in its native C memory. If old C# types are still referenced by Flecs, the old `AssemblyLoadContext` cannot be fully unloaded. The migration step must remove old components and re-add them as the new types.
|
||||
|
||||
### 4.5 SystemSlotRegistry
|
||||
### 4.5 Rendering & Shading
|
||||
|
||||
The renderer uses a simple forward-lit pipeline:
|
||||
|
||||
- **Vertex format**: position, color, normal.
|
||||
- **Per-entity**: Mesh + Transform + optional Material.
|
||||
- **Per-frame constants** via push constants: MVP matrix, light direction/color, ambient color, camera position.
|
||||
- **Lighting model**: directional light with ambient + diffuse + Blinn-Phong specular.
|
||||
- **Material**: CPU-side tint; `Material.Albedo` multiplies vertex color, `Roughness` and `Metallic` reserved for future PBR extension.
|
||||
|
||||
### 4.6 SystemSlotRegistry
|
||||
|
||||
```csharp
|
||||
public class SystemSlotRegistry
|
||||
@@ -490,7 +507,9 @@ In Release (NativeAOT), the MCP server and ASP.NET Core are excluded. The AI can
|
||||
│ │ ├── EngineApp.cs # Entry point, main loop
|
||||
│ │ ├── Sdl3Window.cs # SDL3 window wrapper
|
||||
│ │ ├── Timing.cs # DeltaTime, fixed timestep
|
||||
│ │ └── InputMapping.cs # Keyboard, mouse, gamepad input
|
||||
│ │ ├── InputMapping.cs # Keyboard, mouse, gamepad input
|
||||
│ │ ├── OrbitCameraController.cs # Mouse orbit camera
|
||||
│ │ └── Components/ # Transform, Camera, Material, Mesh
|
||||
│ │
|
||||
│ ├── Engine.Data/
|
||||
│ │ ├── GameObject.cs # Thin struct facade
|
||||
@@ -657,13 +676,13 @@ Stack:
|
||||
- ModelContextProtocol for AI tool integration
|
||||
|
||||
Rules:
|
||||
1. All state lives in ECS components. GameObject is a struct facade.
|
||||
2. All AI mutations go through AiGateway.
|
||||
1. All state lives in ECS components (Transform, Camera, Mesh, Material).
|
||||
2. All AI mutations go through Engine.AI (AiCommandProcessor / MCP tools).
|
||||
3. All Dev-Mode AI scripts must be AOT-compatible and avoid unsafe, Reflection.Emit, Assembly.Load, File I/O.
|
||||
4. All systems are registered in SystemSlotRegistry and tagged with [Slot("name")].
|
||||
5. Use Roslyn syntax trees for validation before compilation.
|
||||
6. Prefer Flecs native reflection (ecs_world_to_json) over C# reflection.
|
||||
7. Keep modules isolated; do not create circular dependencies between Engine.Core, Engine.Data, Engine.Graphics, Engine.Diagnostics, Engine.AiGateway, Engine.Editor.
|
||||
7. Keep modules isolated; do not create circular dependencies between Engine.Core, Engine.Graphics, Engine.AI.
|
||||
|
||||
Current file context: [insert path here]
|
||||
```
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using Engine.AI;
|
||||
@@ -17,12 +18,12 @@ class Program
|
||||
{
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Cortex Engine Step 6 — MCP integration...");
|
||||
Console.WriteLine("Cortex Engine — Materials, Grid, Lighting, Orbit Camera...");
|
||||
|
||||
try
|
||||
{
|
||||
using var world = World.Create();
|
||||
using var window = new Sdl3Window("Cortex Engine — Step 6", 1280, 720);
|
||||
using var window = new Sdl3Window("Cortex Engine", 1280, 720);
|
||||
var timing = new Timing();
|
||||
var input = new InputMapping();
|
||||
using var vulkan = new VulkanContext(window, enableValidation: false);
|
||||
@@ -35,13 +36,9 @@ class Program
|
||||
var processor = new AiCommandProcessor(world, LoadModel, path => renderer.RequestScreenshot(path));
|
||||
var queue = new AiCommandQueue(processor);
|
||||
|
||||
var model = world.Entity("Model")
|
||||
.Set(new Transform(new Vector3(0.0f, 0.0f, 0.0f), Quaternion.Identity, new Vector3(0.5f)))
|
||||
.Set(mesh);
|
||||
|
||||
var camera = world.Entity("Camera")
|
||||
var cameraEntity = world.Entity("Camera")
|
||||
.Set(new Camera(
|
||||
new Vector3(0.0f, 0.0f, -2.0f),
|
||||
new Vector3(0.0f, 1.5f, -3.0f),
|
||||
Vector3.Zero,
|
||||
Vector3.UnitY,
|
||||
MathF.PI / 4.0f,
|
||||
@@ -49,12 +46,34 @@ class Program
|
||||
0.1f,
|
||||
100.0f));
|
||||
|
||||
var orbit = new OrbitCameraController(cameraEntity, Vector3.Zero);
|
||||
|
||||
var model = world.Entity("Model")
|
||||
.Set(new Transform(new Vector3(0.0f, 0.5f, 0.0f), Quaternion.Identity, new Vector3(0.5f)))
|
||||
.Set(mesh)
|
||||
.Set(new Material(new Vector3(0.9f, 0.6f, 0.3f), roughness: 0.4f, metallic: 0.1f));
|
||||
|
||||
var floor = world.Entity("Floor")
|
||||
.Set(new Transform(new Vector3(0.0f, 0.0f, 0.0f), Quaternion.Identity, Vector3.One))
|
||||
.Set(CreateFloorMesh(20.0f, new Vector3(0.08f, 0.08f, 0.1f)))
|
||||
.Set(new Material(new Vector3(0.08f, 0.08f, 0.1f), roughness: 0.9f, metallic: 0.0f));
|
||||
|
||||
var grid = world.Entity("Grid")
|
||||
.Set(new Transform(new Vector3(0.0f, 0.01f, 0.0f), Quaternion.Identity, Vector3.One))
|
||||
.Set(CreateGridMesh(20, 0.5f, new Vector3(0.5f, 0.5f, 0.55f)))
|
||||
.Set(new Material(new Vector3(0.5f, 0.5f, 0.55f), roughness: 0.9f, metallic: 0.0f));
|
||||
|
||||
// Demo: local AI commands processed on the main thread.
|
||||
Console.WriteLine("AI demo commands:");
|
||||
Console.WriteLine(processor.Process("""{ "type": "list_entities" }""").Message);
|
||||
Console.WriteLine(processor.Process("""{ "type": "spawn_model", "name": "SecondCube", "modelPath": "Content/cube.obj", "position": [0.8, 0, 0], "scale": [0.3, 0.3, 0.3] }""").Message);
|
||||
Console.WriteLine(processor.Process("""{ "type": "list_entities" }""").Message);
|
||||
Console.WriteLine(processor.Process("""{ "type": "set_transform", "name": "SecondCube", "position": [0.8, 0.5, 0], "rotation": [0, 0, 0, 1], "scale": [0.3, 0.3, 0.3] }""").Message);
|
||||
|
||||
var secondCube = world.Lookup("SecondCube");
|
||||
if ((ulong)secondCube.Id != 0)
|
||||
secondCube.Set(new Material(new Vector3(0.3f, 0.7f, 0.9f), roughness: 0.3f, metallic: 0.2f));
|
||||
|
||||
Console.WriteLine(processor.Process("""{ "type": "list_entities" }""").Message);
|
||||
Console.WriteLine(processor.Process("""{ "type": "capture_screenshot", "outputPath": "Screenshots/demo.png" }""").Message);
|
||||
|
||||
#if !RELEASE_AOT
|
||||
@@ -81,7 +100,7 @@ class Program
|
||||
while (!window.ShouldClose)
|
||||
{
|
||||
timing.Tick();
|
||||
window.PumpEvents();
|
||||
window.PumpEvents(input);
|
||||
input.BeginFrame();
|
||||
|
||||
// Drain any commands that arrived from the MCP server.
|
||||
@@ -94,12 +113,17 @@ class Program
|
||||
lastWidth = window.Width;
|
||||
lastHeight = window.Height;
|
||||
swapchain.Recreate(lastWidth, lastHeight);
|
||||
ref var camera = ref cameraEntity.Ensure<Camera>();
|
||||
camera.AspectRatio = (float)lastWidth / lastHeight;
|
||||
}
|
||||
|
||||
// Update orbit camera from mouse input.
|
||||
orbit.Update(input, (float)timing.DeltaTime);
|
||||
|
||||
// Slowly rotate the model so we can see it in 3D.
|
||||
ref var transform = ref model.Ensure<Transform>();
|
||||
transform.Rotation = Quaternion.CreateFromAxisAngle(Vector3.UnitY, (float)timing.TotalTime * 0.5f)
|
||||
* Quaternion.CreateFromAxisAngle(Vector3.UnitX, (float)timing.TotalTime * 0.25f);
|
||||
ref var modelTransform = ref model.Ensure<Transform>();
|
||||
modelTransform.Rotation = Quaternion.CreateFromAxisAngle(Vector3.UnitY, (float)timing.TotalTime * 0.5f)
|
||||
* Quaternion.CreateFromAxisAngle(Vector3.UnitX, (float)timing.TotalTime * 0.25f);
|
||||
|
||||
renderer.RenderWorld(world);
|
||||
|
||||
@@ -135,6 +159,57 @@ class Program
|
||||
: ObjLoader.Load(path, new Vector3(0.7f, 0.6f, 0.5f));
|
||||
}
|
||||
|
||||
private static Mesh CreateGridMesh(int lines, float spacing, Vector3 color)
|
||||
{
|
||||
var vertices = new List<Vertex>();
|
||||
var indices = new List<uint>();
|
||||
var extent = lines * spacing;
|
||||
var normal = Vector3.UnitY;
|
||||
var halfWidth = 0.02f;
|
||||
|
||||
for (var i = -lines; i <= lines; i++)
|
||||
{
|
||||
var offset = i * spacing;
|
||||
|
||||
// Line parallel to X axis as a thin quad.
|
||||
var baseIndex = (uint)vertices.Count;
|
||||
vertices.Add(new Vertex(new Vector3(-extent, 0, offset - halfWidth), color, normal));
|
||||
vertices.Add(new Vertex(new Vector3(extent, 0, offset - halfWidth), color, normal));
|
||||
vertices.Add(new Vertex(new Vector3(extent, 0, offset + halfWidth), color, normal));
|
||||
vertices.Add(new Vertex(new Vector3(-extent, 0, offset + halfWidth), color, normal));
|
||||
indices.Add(baseIndex); indices.Add(baseIndex + 1); indices.Add(baseIndex + 2);
|
||||
indices.Add(baseIndex); indices.Add(baseIndex + 2); indices.Add(baseIndex + 3);
|
||||
|
||||
// Line parallel to Z axis as a thin quad.
|
||||
baseIndex = (uint)vertices.Count;
|
||||
vertices.Add(new Vertex(new Vector3(offset - halfWidth, 0, -extent), color, normal));
|
||||
vertices.Add(new Vertex(new Vector3(offset + halfWidth, 0, -extent), color, normal));
|
||||
vertices.Add(new Vertex(new Vector3(offset + halfWidth, 0, extent), color, normal));
|
||||
vertices.Add(new Vertex(new Vector3(offset - halfWidth, 0, extent), color, normal));
|
||||
indices.Add(baseIndex); indices.Add(baseIndex + 1); indices.Add(baseIndex + 2);
|
||||
indices.Add(baseIndex); indices.Add(baseIndex + 2); indices.Add(baseIndex + 3);
|
||||
}
|
||||
|
||||
return new Mesh(vertices.ToArray(), indices.ToArray());
|
||||
}
|
||||
|
||||
private static Mesh CreateFloorMesh(float size, Vector3 color)
|
||||
{
|
||||
var half = size / 2.0f;
|
||||
var normal = Vector3.UnitY;
|
||||
|
||||
var vertices = new Vertex[]
|
||||
{
|
||||
new(new Vector3(-half, 0, -half), color, normal),
|
||||
new(new Vector3(half, 0, -half), color, normal),
|
||||
new(new Vector3(half, 0, half), color, normal),
|
||||
new(new Vector3(-half, 0, half), color, normal)
|
||||
};
|
||||
|
||||
var indices = new uint[] { 0, 1, 2, 0, 2, 3 };
|
||||
return new Mesh(vertices, indices);
|
||||
}
|
||||
|
||||
private static (string modelPath, int mcpPort) ParseArgs(string[] args)
|
||||
{
|
||||
var modelPath = FindModelPath(args);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Engine.Core.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Material component for simple PBR-like rendering.
|
||||
/// Used by the renderer to tint the vertex color and control shading.
|
||||
/// </summary>
|
||||
public record struct Material
|
||||
{
|
||||
public Vector3 Albedo;
|
||||
public float Roughness;
|
||||
public float Metallic;
|
||||
|
||||
public Material(Vector3? albedo = null, float roughness = 0.5f, float metallic = 0.0f)
|
||||
{
|
||||
Albedo = albedo ?? new Vector3(0.7f, 0.6f, 0.5f);
|
||||
Roughness = roughness;
|
||||
Metallic = metallic;
|
||||
}
|
||||
|
||||
public static Material Default => new(new Vector3(0.7f, 0.6f, 0.5f), 0.5f, 0.0f);
|
||||
}
|
||||
@@ -18,11 +18,13 @@ public sealed class InputMapping
|
||||
public bool MouseLeft { get; private set; }
|
||||
public bool MouseRight { get; private set; }
|
||||
public bool MouseMiddle { get; private set; }
|
||||
public float MouseWheelDelta { get; private set; }
|
||||
|
||||
public void BeginFrame()
|
||||
{
|
||||
_keysPressed.Clear();
|
||||
_keysReleased.Clear();
|
||||
MouseWheelDelta = 0;
|
||||
}
|
||||
|
||||
public void ProcessEvent(SDL_Event evt)
|
||||
@@ -52,6 +54,10 @@ public sealed class InputMapping
|
||||
case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
SetMouseButton(evt.button.button, false);
|
||||
break;
|
||||
|
||||
case SDL_EventType.SDL_EVENT_MOUSE_WHEEL:
|
||||
MouseWheelDelta += evt.wheel.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using Flecs.NET.Core;
|
||||
|
||||
namespace Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Orbit camera controller. Right mouse drag rotates around the target,
|
||||
/// mouse wheel zooms in/out.
|
||||
/// </summary>
|
||||
public sealed class OrbitCameraController
|
||||
{
|
||||
private readonly Entity _cameraEntity;
|
||||
private float _distance;
|
||||
private float _yaw;
|
||||
private float _pitch;
|
||||
private readonly Vector3 _target;
|
||||
private int _lastMouseX;
|
||||
private int _lastMouseY;
|
||||
private bool _isDragging;
|
||||
|
||||
public OrbitCameraController(Entity cameraEntity, Vector3? target = null)
|
||||
{
|
||||
_cameraEntity = cameraEntity;
|
||||
var camera = cameraEntity.Get<Components.Camera>();
|
||||
_target = target ?? Vector3.Zero;
|
||||
_distance = Vector3.Distance(camera.Position, _target);
|
||||
|
||||
var direction = Vector3.Normalize(camera.Position - _target);
|
||||
_pitch = MathF.Asin(-direction.Y);
|
||||
_yaw = MathF.Atan2(direction.X, direction.Z);
|
||||
}
|
||||
|
||||
public void Update(InputMapping input, float deltaTime)
|
||||
{
|
||||
if (input.MouseRight)
|
||||
{
|
||||
if (!_isDragging)
|
||||
{
|
||||
_isDragging = true;
|
||||
_lastMouseX = input.MouseX;
|
||||
_lastMouseY = input.MouseY;
|
||||
}
|
||||
else
|
||||
{
|
||||
var dx = input.MouseX - _lastMouseX;
|
||||
var dy = input.MouseY - _lastMouseY;
|
||||
_yaw -= dx * 0.005f;
|
||||
_pitch -= dy * 0.005f;
|
||||
_pitch = Math.Clamp(_pitch, -MathF.PI / 2.0f + 0.1f, MathF.PI / 2.0f - 0.1f);
|
||||
_lastMouseX = input.MouseX;
|
||||
_lastMouseY = input.MouseY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_isDragging = false;
|
||||
}
|
||||
|
||||
if (input.MouseWheelDelta != 0)
|
||||
{
|
||||
_distance *= 1.0f - input.MouseWheelDelta * 0.1f;
|
||||
_distance = Math.Clamp(_distance, 0.5f, 50.0f);
|
||||
}
|
||||
|
||||
UpdateCamera();
|
||||
}
|
||||
|
||||
private void UpdateCamera()
|
||||
{
|
||||
var x = _distance * MathF.Cos(_pitch) * MathF.Sin(_yaw);
|
||||
var y = _distance * MathF.Sin(_pitch);
|
||||
var z = _distance * MathF.Cos(_pitch) * MathF.Cos(_yaw);
|
||||
|
||||
var camera = _cameraEntity.Get<Components.Camera>();
|
||||
camera.Position = _target + new Vector3(x, y, z);
|
||||
camera.Target = _target;
|
||||
_cameraEntity.Set(camera);
|
||||
}
|
||||
}
|
||||
@@ -45,11 +45,13 @@ public sealed unsafe class Sdl3Window : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public void PumpEvents()
|
||||
public void PumpEvents(InputMapping? input = null)
|
||||
{
|
||||
SDL_Event evt;
|
||||
while (SDL3.SDL_PollEvent(&evt))
|
||||
{
|
||||
input?.ProcessEvent(evt);
|
||||
|
||||
switch ((SDL_EventType)evt.type)
|
||||
{
|
||||
case SDL_EventType.SDL_EVENT_QUIT:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
@@ -17,6 +17,8 @@ layout(push_constant) uniform PushConstants
|
||||
float pad2;
|
||||
vec3 ambientColor;
|
||||
float pad3;
|
||||
vec3 cameraPosition;
|
||||
float pad4;
|
||||
} push;
|
||||
|
||||
void main()
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user