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)
{
row_major float4x4 ViewProjection;
row_major float4x4 Model;
uint BufferIndex;
uint TextureIndex;
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));
//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;
}

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)
{

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

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();

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)

View File

@@ -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;
}

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);

View File

@@ -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)

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);

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()
{

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 = {};