Made MeshRenderer able to take a matrix transform for each mesh, and we are now able to draw 100 cubes.

Claude OPus helpes with implementation
This commit is contained in:
2026-02-21 23:27:27 -05:00
parent 8e83cd32f6
commit a7947bfa17
16 changed files with 73 additions and 35 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -4,6 +4,7 @@
cbuffer RootConstants : register(b0, space0) cbuffer RootConstants : register(b0, space0)
{ {
row_major float4x4 ViewProjection; row_major float4x4 ViewProjection;
row_major float4x4 Model;
uint BufferIndex; uint BufferIndex;
uint TextureIndex; uint TextureIndex;
uint VertexOffset; // Base vertex for indexed drawing with bindless buffers uint VertexOffset; // Base vertex for indexed drawing with bindless buffers

View File

@@ -19,7 +19,7 @@ Output main(uint vertexIndex : SV_VertexID)
float4 col = asfloat(buffer.Load4(offset + 12)); float4 col = asfloat(buffer.Load4(offset + 12));
//output.Position = float4(pos, 1.0f); //output.Position = float4(pos, 1.0f);
output.Position = mul(ViewProjection, float4(pos, 1.0f)); output.Position = mul(ViewProjection, mul(Model, float4(pos, 1.0f)));
output.Color = col; output.Color = col;
return output; return output;
} }

View File

@@ -8,33 +8,42 @@ namespace Juliet
struct Matrix struct Matrix
{ {
float m[4][4]; float m[4][4];
};
static Matrix Identity() [[nodiscard]] inline Matrix MatrixIdentity()
{ {
Matrix result = {}; Matrix result = {};
result.m[0][0] = 1.0f; result.m[0][0] = 1.0f;
result.m[1][1] = 1.0f; result.m[1][1] = 1.0f;
result.m[2][2] = 1.0f; result.m[2][2] = 1.0f;
result.m[3][3] = 1.0f; result.m[3][3] = 1.0f;
return result; return result;
} }
Matrix operator*(const Matrix& rhs) const [[nodiscard]] inline Matrix MatrixTranslation(float x, float y, float z)
{
Matrix result = MatrixIdentity();
result.m[0][3] = x;
result.m[1][3] = y;
result.m[2][3] = z;
return result;
}
[[nodiscard]] inline Matrix operator*(const Matrix& lhs, const Matrix& rhs)
{
Matrix result = {};
for (int i = 0; i < 4; ++i)
{ {
Matrix result = {}; for (int j = 0; j < 4; ++j)
for (int i = 0; i < 4; ++i)
{ {
for (int j = 0; j < 4; ++j) for (int k = 0; k < 4; ++k)
{ {
for (int k = 0; k < 4; ++k) result.m[i][j] += lhs.m[i][k] * rhs.m[k][j];
{
result.m[i][j] += m[i][k] * rhs.m[k][j];
}
} }
} }
return result;
} }
}; return result;
}
inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up) inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
{ {

View File

@@ -2,6 +2,7 @@
#include <Core/Common/CoreTypes.h> #include <Core/Common/CoreTypes.h>
#include <Core/Common/NonNullPtr.h> #include <Core/Common/NonNullPtr.h>
#include <Core/Math/Matrix.h>
#include <Juliet.h> #include <Juliet.h>
namespace Juliet namespace Juliet
@@ -16,5 +17,7 @@ namespace Juliet
index_t VertexOffset; index_t VertexOffset;
index_t IndexOffset; index_t IndexOffset;
Matrix Transform = MatrixIdentity();
}; };
} // namespace Juliet } // namespace Juliet

View File

@@ -43,6 +43,7 @@ namespace Juliet
struct PushData struct PushData
{ {
Matrix ViewProjection; Matrix ViewProjection;
Matrix Model;
uint32 BufferIndex; uint32 BufferIndex;
}; };
@@ -55,6 +56,7 @@ namespace Juliet
// Utils // Utils
[[nodiscard]] JULIET_API MeshID AddCube(); [[nodiscard]] JULIET_API MeshID AddCube();
[[nodiscard]] JULIET_API MeshID AddQuad(); [[nodiscard]] JULIET_API MeshID AddQuad();
JULIET_API void SetMeshTransform(MeshID id, const Matrix& transform);
#if ALLOW_SHADER_HOT_RELOAD #if ALLOW_SHADER_HOT_RELOAD
JULIET_API void ReloadMeshRendererShaders(); JULIET_API void ReloadMeshRendererShaders();

View File

@@ -123,7 +123,7 @@ namespace Juliet
{ {
// Find and destroy // Find and destroy
VectorArena<Window>& windows = g_CurrentDisplayDevice->Windows; VectorArena<Window>& windows = g_CurrentDisplayDevice->Windows;
for (index_t idx = windows.Size() - 1; idx != 0; --idx) for (index_t idx = windows.Size(); idx-- > 0;)
{ {
Window& windowRef = windows[idx]; Window& windowRef = windows[idx];
if (windowRef.ID == window->ID) if (windowRef.ID == window->ID)

View File

@@ -36,7 +36,7 @@ namespace Juliet::Win32
device->PumpEvents = PumpEvents; device->PumpEvents = PumpEvents;
device->Windows.Create(JULIET_DEBUG_ONLY("Display Windows")); device->Windows.Create(arena JULIET_DEBUG_PARAM("Display Windows"));
return device; return device;
} }

View File

@@ -75,12 +75,12 @@ namespace Juliet
void ArenaRelease(NonNullPtr<Arena> arena) void ArenaRelease(NonNullPtr<Arena> arena)
{ {
JULIET_DEBUG_ONLY(DebugUnregisterArena(arena);) // Release active blocks (Current chain)
for (Arena *node = arena->Current, *previous = nullptr; node != nullptr; node = previous) for (Arena *node = arena->Current, *previous = nullptr; node != nullptr; node = previous)
{ {
previous = node->Previous; previous = node->Previous;
JULIET_DEBUG_ONLY(DebugUnregisterArena(node);)
JULIET_DEBUG_ONLY(DebugArenaFreeBlock(node);) JULIET_DEBUG_ONLY(DebugArenaFreeBlock(node);)
Memory::OS_Release(node, node->Reserved); Memory::OS_Release(node, node->Reserved);

View File

@@ -68,6 +68,8 @@ namespace Juliet
{ {
arena->GlobalNext->GlobalPrev = arena->GlobalPrev; arena->GlobalNext->GlobalPrev = arena->GlobalPrev;
} }
arena->GlobalPrev = nullptr;
arena->GlobalNext = nullptr;
} }
void DebugArenaSetDebugName(NonNullPtr<Arena> arena, const char* name) void DebugArenaSetDebugName(NonNullPtr<Arena> arena, const char* name)

View File

@@ -300,15 +300,17 @@ namespace Juliet
{ {
BindGraphicsPipeline(renderPass, g_DebugState.DepthTestedPipeline); BindGraphicsPipeline(renderPass, g_DebugState.DepthTestedPipeline);
// Pack VP matrix + buffer index into push constants // Pack VP matrix + Model (identity for debug) + buffer index into push constants
struct struct
{ {
Matrix vp; Matrix vp;
Matrix model;
uint32 bufferIndex; uint32 bufferIndex;
uint32 vertexOffset; // Offset in vertices (not bytes) uint32 vertexOffset; // Offset in vertices (not bytes)
uint32 padding[2]; uint32 padding[2];
} pushData; } pushData;
pushData.vp = Camera_GetViewProjectionMatrix(camera); pushData.vp = Camera_GetViewProjectionMatrix(camera);
pushData.model = MatrixIdentity();
pushData.bufferIndex = bufferIndex; pushData.bufferIndex = bufferIndex;
pushData.vertexOffset = 0; // Depth-tested vertices start at 0 pushData.vertexOffset = 0; // Depth-tested vertices start at 0
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData); SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);
@@ -321,15 +323,17 @@ namespace Juliet
{ {
BindGraphicsPipeline(renderPass, g_DebugState.OverlayPipeline); BindGraphicsPipeline(renderPass, g_DebugState.OverlayPipeline);
// Pack VP matrix + buffer index into push constants // Pack VP matrix + Model (identity for debug) + buffer index into push constants
struct struct
{ {
Matrix vp; Matrix vp;
Matrix model;
uint32 bufferIndex; uint32 bufferIndex;
uint32 vertexOffset; // Offset in vertices (not bytes) uint32 vertexOffset; // Offset in vertices (not bytes)
uint32 padding[2]; uint32 padding[2];
} pushData; } pushData;
pushData.vp = Camera_GetViewProjectionMatrix(camera); pushData.vp = Camera_GetViewProjectionMatrix(camera);
pushData.model = MatrixIdentity();
pushData.bufferIndex = bufferIndex; pushData.bufferIndex = bufferIndex;
pushData.vertexOffset = kMaxDebugVertices / 2; // Overlay vertices start at half pushData.vertexOffset = kMaxDebugVertices / 2; // Overlay vertices start at half
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData); SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);

View File

@@ -187,12 +187,13 @@ namespace Juliet
uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer); uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer);
pushData.BufferIndex = vertexDescriptorIndex; pushData.BufferIndex = vertexDescriptorIndex;
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0); SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0);
for (Mesh& mesh : g_MeshRenderer.Meshes) for (Mesh& mesh : g_MeshRenderer.Meshes)
{ {
pushData.Model = mesh.Transform;
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
DrawIndexedPrimitives(pass, static_cast<uint32>(mesh.IndexCount), 1, static_cast<uint32>(mesh.IndexOffset), DrawIndexedPrimitives(pass, static_cast<uint32>(mesh.IndexCount), 1, static_cast<uint32>(mesh.IndexOffset),
static_cast<uint32>(mesh.VertexOffset), 0); static_cast<uint32>(mesh.VertexOffset), 0);
} }
@@ -292,6 +293,11 @@ namespace Juliet
return g_MeshRenderer.Meshes.Count - 1; return g_MeshRenderer.Meshes.Count - 1;
} }
void SetMeshTransform(MeshID id, const Matrix& transform)
{
Assert(id < static_cast<MeshID>(g_MeshRenderer.Meshes.Count), "Invalid MeshID");
g_MeshRenderer.Meshes.Data[id].Transform = transform;
}
#if ALLOW_SHADER_HOT_RELOAD #if ALLOW_SHADER_HOT_RELOAD
void ReloadMeshRendererShaders() void ReloadMeshRendererShaders()
{ {

View File

@@ -109,7 +109,20 @@ void JulietApplication::Init()
Running = false; Running = false;
} }
std::ignore = AddCube(); constexpr int kGridSize = 10;
constexpr float kSpacing = 2.5f;
constexpr float kOffset = (kGridSize - 1) * kSpacing * 0.5f;
for (int row = 0; row < kGridSize; ++row)
{
for (int col = 0; col < kGridSize; ++col)
{
MeshID cube = AddCube();
float x = static_cast<float>(col) * kSpacing - kOffset;
float y = static_cast<float>(row) * kSpacing - kOffset;
SetMeshTransform(cube, MatrixTranslation(x, y, 0.0f));
}
}
CommandList* loadCmd = AcquireCommandList(GraphicsDevice); CommandList* loadCmd = AcquireCommandList(GraphicsDevice);
LoadMeshesOnGPU(loadCmd); LoadMeshesOnGPU(loadCmd);
@@ -275,8 +288,6 @@ void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
pushData.ViewProjection = Camera_GetViewProjectionMatrix(GetDebugCamera()); pushData.ViewProjection = Camera_GetViewProjectionMatrix(GetDebugCamera());
RenderMeshes(pass, cmd, pushData); RenderMeshes(pass, cmd, pushData);
// SetPushConstants(cmd, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
} }
ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture) ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture)
@@ -308,14 +319,14 @@ Camera JulietApplication::GetDebugCamera()
float currentOrbitTime = time * orbitSpeed; float currentOrbitTime = time * orbitSpeed;
// --- Adjusted for 1-Meter Scale --- // --- Adjusted for 1-Meter Scale ---
float baseRadius = 2.5f; // Hover 2.5 meters away (down from 15.0f) float baseRadius = 25.0f; // Increased to see 10x10 cube grid
float radius = baseRadius; float radius = baseRadius;
/* Uncomment for active zoom //* Uncomment for active zoom
float zoomAmplitude = 1.0f; // Oscillate between 1.5m and 3.5m away float zoomAmplitude = 10.0f; // Oscillate between 1.5m and 3.5m away
float zoomSpeed = 0.8f; float zoomSpeed = 0.8f;
radius = baseRadius + (sinf(time * zoomSpeed) * zoomAmplitude); radius = baseRadius + (sinf(time * zoomSpeed) * zoomAmplitude);
*/ //*/
float zHeight = radius * 0.5f; // Keep a nice downward viewing angle float zHeight = radius * 0.5f; // Keep a nice downward viewing angle
Camera cam = {}; Camera cam = {};