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.
+1
View File
@@ -4,6 +4,7 @@
cbuffer RootConstants : register(b0, space0)
{
row_major float4x4 ViewProjection;
row_major float4x4 Model;
uint BufferIndex;
uint TextureIndex;
uint VertexOffset; // Base vertex for indexed drawing with bindless buffers
+1 -1
View File
@@ -19,7 +19,7 @@ Output main(uint vertexIndex : SV_VertexID)
float4 col = asfloat(buffer.Load4(offset + 12));
//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;
return output;
}
+28 -19
View File
@@ -8,33 +8,42 @@ namespace Juliet
struct Matrix
{
float m[4][4];
};
static Matrix Identity()
{
Matrix result = {};
result.m[0][0] = 1.0f;
result.m[1][1] = 1.0f;
result.m[2][2] = 1.0f;
result.m[3][3] = 1.0f;
return result;
}
[[nodiscard]] inline Matrix MatrixIdentity()
{
Matrix result = {};
result.m[0][0] = 1.0f;
result.m[1][1] = 1.0f;
result.m[2][2] = 1.0f;
result.m[3][3] = 1.0f;
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 i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
{
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] += m[i][k] * rhs.m[k][j];
}
result.m[i][j] += lhs.m[i][k] * rhs.m[k][j];
}
}
return result;
}
};
return result;
}
inline Matrix LookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
{
+3
View File
@@ -2,6 +2,7 @@
#include <Core/Common/CoreTypes.h>
#include <Core/Common/NonNullPtr.h>
#include <Core/Math/Matrix.h>
#include <Juliet.h>
namespace Juliet
@@ -16,5 +17,7 @@ namespace Juliet
index_t VertexOffset;
index_t IndexOffset;
Matrix Transform = MatrixIdentity();
};
} // namespace Juliet
+2
View File
@@ -43,6 +43,7 @@ namespace Juliet
struct PushData
{
Matrix ViewProjection;
Matrix Model;
uint32 BufferIndex;
};
@@ -55,6 +56,7 @@ namespace Juliet
// Utils
[[nodiscard]] JULIET_API MeshID AddCube();
[[nodiscard]] JULIET_API MeshID AddQuad();
JULIET_API void SetMeshTransform(MeshID id, const Matrix& transform);
#if ALLOW_SHADER_HOT_RELOAD
JULIET_API void ReloadMeshRendererShaders();
+1 -1
View File
@@ -123,7 +123,7 @@ namespace Juliet
{
// Find and destroy
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];
if (windowRef.ID == window->ID)
@@ -36,7 +36,7 @@ namespace Juliet::Win32
device->PumpEvents = PumpEvents;
device->Windows.Create(JULIET_DEBUG_ONLY("Display Windows"));
device->Windows.Create(arena JULIET_DEBUG_PARAM("Display Windows"));
return device;
}
+2 -2
View File
@@ -75,12 +75,12 @@ namespace Juliet
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)
{
previous = node->Previous;
JULIET_DEBUG_ONLY(DebugUnregisterArena(node);)
JULIET_DEBUG_ONLY(DebugArenaFreeBlock(node);)
Memory::OS_Release(node, node->Reserved);
@@ -68,6 +68,8 @@ namespace Juliet
{
arena->GlobalNext->GlobalPrev = arena->GlobalPrev;
}
arena->GlobalPrev = nullptr;
arena->GlobalNext = nullptr;
}
void DebugArenaSetDebugName(NonNullPtr<Arena> arena, const char* name)
+6 -2
View File
@@ -300,15 +300,17 @@ namespace Juliet
{
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
{
Matrix vp;
Matrix model;
uint32 bufferIndex;
uint32 vertexOffset; // Offset in vertices (not bytes)
uint32 padding[2];
} pushData;
pushData.vp = Camera_GetViewProjectionMatrix(camera);
pushData.model = MatrixIdentity();
pushData.bufferIndex = bufferIndex;
pushData.vertexOffset = 0; // Depth-tested vertices start at 0
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);
@@ -321,15 +323,17 @@ namespace Juliet
{
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
{
Matrix vp;
Matrix model;
uint32 bufferIndex;
uint32 vertexOffset; // Offset in vertices (not bytes)
uint32 padding[2];
} pushData;
pushData.vp = Camera_GetViewProjectionMatrix(camera);
pushData.model = MatrixIdentity();
pushData.bufferIndex = bufferIndex;
pushData.vertexOffset = kMaxDebugVertices / 2; // Overlay vertices start at half
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / sizeof(uint32), &pushData);
+7 -1
View File
@@ -187,12 +187,13 @@ namespace Juliet
uint32 vertexDescriptorIndex = GetDescriptorIndex(g_MeshRenderer.Device, g_MeshRenderer.VertexBuffer);
pushData.BufferIndex = vertexDescriptorIndex;
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
SetIndexBuffer(cmdList, g_MeshRenderer.IndexBuffer, IndexFormat::UInt16, g_MeshRenderer.Indices.Count, 0);
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),
static_cast<uint32>(mesh.VertexOffset), 0);
}
@@ -292,6 +293,11 @@ namespace Juliet
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
void ReloadMeshRendererShaders()
{
+19 -8
View File
@@ -109,7 +109,20 @@ void JulietApplication::Init()
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);
LoadMeshesOnGPU(loadCmd);
@@ -275,8 +288,6 @@ void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
pushData.ViewProjection = Camera_GetViewProjectionMatrix(GetDebugCamera());
RenderMeshes(pass, cmd, pushData);
// SetPushConstants(cmd, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
}
ColorTargetInfo JulietApplication::GetColorTargetInfo(Texture* swapchainTexture)
@@ -308,14 +319,14 @@ Camera JulietApplication::GetDebugCamera()
float currentOrbitTime = time * orbitSpeed;
// --- 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;
/* Uncomment for active zoom
float zoomAmplitude = 1.0f; // Oscillate between 1.5m and 3.5m away
//* Uncomment for active zoom
float zoomAmplitude = 10.0f; // Oscillate between 1.5m and 3.5m away
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
Camera cam = {};