mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 13:44:58 +00:00
feat: Enable MaterialX support and refactor rendering pipeline to utilize view state
This commit is contained in:
@@ -61,7 +61,7 @@
|
||||
"renderer": "vulkan"
|
||||
},
|
||||
"materialx": {
|
||||
"enabled": false,
|
||||
"enabled": true,
|
||||
"parameters_enabled": true,
|
||||
"document": "MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_carpaint.mtlx",
|
||||
"shader_key": "materialx",
|
||||
|
||||
@@ -510,6 +510,21 @@ local function update_audio_controls()
|
||||
end
|
||||
|
||||
local rotation_speed = 0.9
|
||||
local default_material_shader = "pbr"
|
||||
|
||||
local function resolve_material_shader()
|
||||
if type(config) ~= "table" then
|
||||
return default_material_shader
|
||||
end
|
||||
local materialx = config.materialx
|
||||
if type(materialx) ~= "table" or not materialx.enabled then
|
||||
return default_material_shader
|
||||
end
|
||||
if type(materialx.shader_key) == "string" and materialx.shader_key ~= "" then
|
||||
return materialx.shader_key
|
||||
end
|
||||
return "materialx"
|
||||
end
|
||||
|
||||
local function build_static_model_matrix(position, scale)
|
||||
local translation = math3d.translation(position[1], position[2], position[3])
|
||||
@@ -523,6 +538,7 @@ local function apply_color_to_vertices(color)
|
||||
local v = cube_vertices[i]
|
||||
colored_vertices[i] = {
|
||||
position = v.position,
|
||||
normal = v.normal,
|
||||
color = color,
|
||||
}
|
||||
end
|
||||
@@ -564,7 +580,8 @@ local function create_skybox()
|
||||
end
|
||||
|
||||
local function create_spinning_cube()
|
||||
log_debug("Spinning cube shader=pbr (MaterialX-driven)")
|
||||
local shader_key = resolve_material_shader()
|
||||
log_debug("Spinning cube shader=%s", shader_key)
|
||||
local function compute_model_matrix(time)
|
||||
local rotation = math3d.rotation_y(time * rotation_speed)
|
||||
local scale = scale_matrix(1.5, 1.5, 1.5) -- Make cube 3x3x3 units
|
||||
@@ -576,7 +593,7 @@ local function create_spinning_cube()
|
||||
vertices = cube_vertices,
|
||||
indices = (#cube_indices_double_sided > 0) and cube_indices_double_sided or cube_indices,
|
||||
compute_model_matrix = compute_model_matrix,
|
||||
shader_key = "pbr",
|
||||
shader_key = shader_key,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -764,7 +781,7 @@ function get_shader_paths()
|
||||
end
|
||||
|
||||
|
||||
function get_view_projection(aspect)
|
||||
local function build_view_state(aspect)
|
||||
local now = os.clock()
|
||||
local dt = 0.0
|
||||
if last_frame_time then
|
||||
@@ -789,7 +806,21 @@ function get_view_projection(aspect)
|
||||
|
||||
local view = math3d.look_at(camera.position, center, world_up)
|
||||
local projection = math3d.perspective(camera.fov, aspect, camera.near, camera.far)
|
||||
return math3d.multiply(projection, view)
|
||||
return {
|
||||
view = view,
|
||||
proj = projection,
|
||||
view_proj = math3d.multiply(projection, view),
|
||||
camera_pos = {camera.position[1], camera.position[2], camera.position[3]},
|
||||
}
|
||||
end
|
||||
|
||||
function get_view_state(aspect)
|
||||
return build_view_state(aspect)
|
||||
end
|
||||
|
||||
function get_view_projection(aspect)
|
||||
local state = build_view_state(aspect)
|
||||
return state.view_proj
|
||||
end
|
||||
|
||||
function get_gui_commands()
|
||||
|
||||
@@ -315,7 +315,8 @@ local vertex_color_source = [[
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 inPos;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
layout(location = 1) in vec3 inNormal;
|
||||
layout(location = 2) in vec3 inColor;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
|
||||
@@ -389,8 +390,8 @@ local shadow_vertex_source = [[
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
// layout(location = 2) in vec2 inTexCoord; // Not used
|
||||
layout(location = 1) in vec3 inNormal;
|
||||
layout(location = 2) in vec3 inColor;
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat4 model;
|
||||
@@ -594,7 +595,8 @@ local vertex_world_color_source = [[
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 inPos;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
layout(location = 1) in vec3 inNormal;
|
||||
layout(location = 2) in vec3 inColor;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
layout(location = 1) out vec3 fragWorldPos;
|
||||
@@ -1027,8 +1029,8 @@ local pbr_vertex_source = [[
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec3 inColor; // Color instead of normal
|
||||
layout(location = 2) in vec2 inTexCoord; // Not used for now
|
||||
layout(location = 1) in vec3 inNormal;
|
||||
layout(location = 2) in vec3 inColor;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
layout(location = 1) out vec3 fragWorldPos;
|
||||
@@ -1061,8 +1063,8 @@ void main() {
|
||||
gl_Position = pc.proj * pc.view * worldPos;
|
||||
|
||||
fragWorldPos = worldPos.xyz;
|
||||
fragNormal = normalize(mat3(pc.model) * vec3(0.0, 0.0, 1.0)); // Simple normal for flat shading
|
||||
fragTexCoord = vec2(0.0, 0.0); // Not used
|
||||
fragNormal = normalize(mat3(pc.model) * inNormal);
|
||||
fragTexCoord = vec2(0.0, 0.0);
|
||||
fragColor = inColor; // Use vertex color
|
||||
}
|
||||
]]
|
||||
|
||||
@@ -202,7 +202,8 @@ local function build_static_cube_variants()
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 inPos;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
layout(location = 1) in vec3 inNormal;
|
||||
layout(location = 2) in vec3 inColor;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace sdl3cpp::core {
|
||||
|
||||
struct Vertex {
|
||||
std::array<float, 3> position;
|
||||
std::array<float, 3> normal;
|
||||
std::array<float, 3> color;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_inverse.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
@@ -25,6 +28,31 @@ std::string ToLower(std::string value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
glm::mat4 ToMat4(const std::array<float, 16>& value) {
|
||||
return glm::make_mat4(value.data());
|
||||
}
|
||||
|
||||
bool IsIdentityMatrix(const std::array<float, 16>& value) {
|
||||
const float identity[16] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
if (value[i] != identity[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetUniformIfValid(bgfx::UniformHandle handle, const void* data, uint16_t count = 1) {
|
||||
if (bgfx::isValid(handle)) {
|
||||
bgfx::setUniform(handle, data, count);
|
||||
}
|
||||
}
|
||||
|
||||
bgfx::RendererType::Enum RendererFromString(const std::string& value) {
|
||||
const std::string lower = ToLower(value);
|
||||
if (lower == "vulkan") {
|
||||
@@ -48,8 +76,20 @@ BgfxGraphicsBackend::BgfxGraphicsBackend(std::shared_ptr<IConfigService> configS
|
||||
}
|
||||
vertexLayout_.begin()
|
||||
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
|
||||
.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float)
|
||||
.add(bgfx::Attrib::Color0, 3, bgfx::AttribType::Float)
|
||||
.end();
|
||||
|
||||
const std::array<float, 16> identity = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
viewState_.view = identity;
|
||||
viewState_.proj = identity;
|
||||
viewState_.viewProj = identity;
|
||||
viewState_.cameraPosition = {0.0f, 0.0f, 0.0f};
|
||||
}
|
||||
|
||||
BgfxGraphicsBackend::~BgfxGraphicsBackend() {
|
||||
@@ -134,6 +174,7 @@ void BgfxGraphicsBackend::Initialize(void* window, const GraphicsConfig& config)
|
||||
|
||||
bgfx::setViewClear(viewId_, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x1f1f1fff, 1.0f, 0);
|
||||
bgfx::setDebug(BGFX_DEBUG_TEXT);
|
||||
InitializeUniforms();
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
@@ -148,6 +189,7 @@ void BgfxGraphicsBackend::Shutdown() {
|
||||
|
||||
DestroyPipelines();
|
||||
DestroyBuffers();
|
||||
DestroyUniforms();
|
||||
bgfx::shutdown();
|
||||
initialized_ = false;
|
||||
}
|
||||
@@ -235,6 +277,64 @@ bgfx::ShaderHandle BgfxGraphicsBackend::CreateShader(const std::string& label,
|
||||
return bgfx::createShader(mem);
|
||||
}
|
||||
|
||||
void BgfxGraphicsBackend::InitializeUniforms() {
|
||||
materialXUniforms_.worldMatrix = bgfx::createUniform("u_worldMatrix", bgfx::UniformType::Mat4);
|
||||
materialXUniforms_.viewMatrix = bgfx::createUniform("u_viewMatrix", bgfx::UniformType::Mat4);
|
||||
materialXUniforms_.projectionMatrix = bgfx::createUniform("u_projectionMatrix", bgfx::UniformType::Mat4);
|
||||
materialXUniforms_.viewProjectionMatrix = bgfx::createUniform("u_viewProjectionMatrix", bgfx::UniformType::Mat4);
|
||||
materialXUniforms_.worldViewMatrix = bgfx::createUniform("u_worldViewMatrix", bgfx::UniformType::Mat4);
|
||||
materialXUniforms_.worldViewProjectionMatrix = bgfx::createUniform("u_worldViewProjectionMatrix", bgfx::UniformType::Mat4);
|
||||
materialXUniforms_.worldInverseTransposeMatrix = bgfx::createUniform("u_worldInverseTransposeMatrix", bgfx::UniformType::Mat4);
|
||||
materialXUniforms_.viewPosition = bgfx::createUniform("u_viewPosition", bgfx::UniformType::Vec4);
|
||||
}
|
||||
|
||||
void BgfxGraphicsBackend::DestroyUniforms() {
|
||||
bgfx::UniformHandle handles[] = {
|
||||
materialXUniforms_.worldMatrix,
|
||||
materialXUniforms_.viewMatrix,
|
||||
materialXUniforms_.projectionMatrix,
|
||||
materialXUniforms_.viewProjectionMatrix,
|
||||
materialXUniforms_.worldViewMatrix,
|
||||
materialXUniforms_.worldViewProjectionMatrix,
|
||||
materialXUniforms_.worldInverseTransposeMatrix,
|
||||
materialXUniforms_.viewPosition
|
||||
};
|
||||
for (bgfx::UniformHandle handle : handles) {
|
||||
if (bgfx::isValid(handle)) {
|
||||
bgfx::destroy(handle);
|
||||
}
|
||||
}
|
||||
materialXUniforms_ = MaterialXUniforms{};
|
||||
}
|
||||
|
||||
void BgfxGraphicsBackend::ApplyMaterialXUniforms(const std::array<float, 16>& modelMatrix) {
|
||||
glm::mat4 model = ToMat4(modelMatrix);
|
||||
glm::mat4 view = ToMat4(viewState_.view);
|
||||
glm::mat4 proj = ToMat4(viewState_.proj);
|
||||
glm::mat4 viewProj = (IsIdentityMatrix(viewState_.view) && IsIdentityMatrix(viewState_.proj))
|
||||
? ToMat4(viewState_.viewProj)
|
||||
: proj * view;
|
||||
glm::mat4 worldView = view * model;
|
||||
glm::mat4 worldViewProj = viewProj * model;
|
||||
glm::mat4 worldInverseTranspose = glm::transpose(glm::inverse(model));
|
||||
|
||||
SetUniformIfValid(materialXUniforms_.worldMatrix, glm::value_ptr(model));
|
||||
SetUniformIfValid(materialXUniforms_.viewMatrix, glm::value_ptr(view));
|
||||
SetUniformIfValid(materialXUniforms_.projectionMatrix, glm::value_ptr(proj));
|
||||
SetUniformIfValid(materialXUniforms_.viewProjectionMatrix, glm::value_ptr(viewProj));
|
||||
SetUniformIfValid(materialXUniforms_.worldViewMatrix, glm::value_ptr(worldView));
|
||||
SetUniformIfValid(materialXUniforms_.worldViewProjectionMatrix, glm::value_ptr(worldViewProj));
|
||||
SetUniformIfValid(materialXUniforms_.worldInverseTransposeMatrix, glm::value_ptr(worldInverseTranspose));
|
||||
|
||||
float viewPosition[4] = {
|
||||
viewState_.cameraPosition[0],
|
||||
viewState_.cameraPosition[1],
|
||||
viewState_.cameraPosition[2],
|
||||
1.0f
|
||||
};
|
||||
SetUniformIfValid(materialXUniforms_.viewPosition, viewPosition);
|
||||
}
|
||||
|
||||
GraphicsPipelineHandle BgfxGraphicsBackend::CreatePipeline(GraphicsDeviceHandle device,
|
||||
const std::string& shaderKey,
|
||||
const ShaderPaths& shaderPaths) {
|
||||
@@ -339,14 +439,7 @@ bool BgfxGraphicsBackend::BeginFrame(GraphicsDeviceHandle device) {
|
||||
if (!initialized_) {
|
||||
return false;
|
||||
}
|
||||
const float identity[16] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
bgfx::setViewRect(viewId_, 0, 0, viewportWidth_, viewportHeight_);
|
||||
bgfx::setViewTransform(viewId_, viewProj_.data(), identity);
|
||||
bgfx::touch(viewId_);
|
||||
return true;
|
||||
}
|
||||
@@ -359,8 +452,9 @@ bool BgfxGraphicsBackend::EndFrame(GraphicsDeviceHandle device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void BgfxGraphicsBackend::SetViewProjection(const std::array<float, 16>& viewProj) {
|
||||
viewProj_ = viewProj;
|
||||
void BgfxGraphicsBackend::SetViewState(const ViewState& viewState) {
|
||||
viewState_ = viewState;
|
||||
bgfx::setViewTransform(viewId_, viewState_.view.data(), viewState_.proj.data());
|
||||
}
|
||||
|
||||
void BgfxGraphicsBackend::Draw(GraphicsDeviceHandle device, GraphicsPipelineHandle pipeline,
|
||||
@@ -394,6 +488,7 @@ void BgfxGraphicsBackend::Draw(GraphicsDeviceHandle device, GraphicsPipelineHand
|
||||
}
|
||||
|
||||
bgfx::setTransform(modelMatrix.data());
|
||||
ApplyMaterialXUniforms(modelMatrix);
|
||||
bgfx::setVertexBuffer(0, vb->handle, startVertex, availableVertices);
|
||||
bgfx::setIndexBuffer(ib->handle, indexOffset, indexCount);
|
||||
bgfx::setState(BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_WRITE_Z |
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
void DestroyBuffer(GraphicsDeviceHandle device, GraphicsBufferHandle buffer) override;
|
||||
bool BeginFrame(GraphicsDeviceHandle device) override;
|
||||
bool EndFrame(GraphicsDeviceHandle device) override;
|
||||
void SetViewProjection(const std::array<float, 16>& viewProj) override;
|
||||
void SetViewState(const ViewState& viewState) override;
|
||||
void Draw(GraphicsDeviceHandle device, GraphicsPipelineHandle pipeline,
|
||||
GraphicsBufferHandle vertexBuffer, GraphicsBufferHandle indexBuffer,
|
||||
uint32_t indexOffset, uint32_t indexCount, int32_t vertexOffset,
|
||||
@@ -61,6 +61,17 @@ private:
|
||||
uint32_t indexCount = 0;
|
||||
};
|
||||
|
||||
struct MaterialXUniforms {
|
||||
bgfx::UniformHandle worldMatrix = BGFX_INVALID_HANDLE;
|
||||
bgfx::UniformHandle viewMatrix = BGFX_INVALID_HANDLE;
|
||||
bgfx::UniformHandle projectionMatrix = BGFX_INVALID_HANDLE;
|
||||
bgfx::UniformHandle viewProjectionMatrix = BGFX_INVALID_HANDLE;
|
||||
bgfx::UniformHandle worldViewMatrix = BGFX_INVALID_HANDLE;
|
||||
bgfx::UniformHandle worldViewProjectionMatrix = BGFX_INVALID_HANDLE;
|
||||
bgfx::UniformHandle worldInverseTransposeMatrix = BGFX_INVALID_HANDLE;
|
||||
bgfx::UniformHandle viewPosition = BGFX_INVALID_HANDLE;
|
||||
};
|
||||
|
||||
void SetupPlatformData(void* window);
|
||||
bgfx::RendererType::Enum ResolveRendererType() const;
|
||||
std::vector<uint8_t> ReadShaderSource(const std::string& path,
|
||||
@@ -68,6 +79,9 @@ private:
|
||||
bgfx::ShaderHandle CreateShader(const std::string& label,
|
||||
const std::string& source,
|
||||
bool isVertex) const;
|
||||
void InitializeUniforms();
|
||||
void DestroyUniforms();
|
||||
void ApplyMaterialXUniforms(const std::array<float, 16>& modelMatrix);
|
||||
void DestroyPipelines();
|
||||
void DestroyBuffers();
|
||||
|
||||
@@ -77,7 +91,8 @@ private:
|
||||
std::unordered_map<GraphicsPipelineHandle, std::unique_ptr<PipelineEntry>> pipelines_;
|
||||
std::unordered_map<GraphicsBufferHandle, std::unique_ptr<VertexBufferEntry>> vertexBuffers_;
|
||||
std::unordered_map<GraphicsBufferHandle, std::unique_ptr<IndexBufferEntry>> indexBuffers_;
|
||||
std::array<float, 16> viewProj_{};
|
||||
ViewState viewState_{};
|
||||
MaterialXUniforms materialXUniforms_{};
|
||||
uint32_t viewportWidth_ = 0;
|
||||
uint32_t viewportHeight_ = 0;
|
||||
bool initialized_ = false;
|
||||
|
||||
@@ -144,17 +144,17 @@ bool GraphicsService::BeginFrame() {
|
||||
}
|
||||
|
||||
void GraphicsService::RenderScene(const std::vector<RenderCommand>& commands,
|
||||
const std::array<float, 16>& viewProj) {
|
||||
const ViewState& viewState) {
|
||||
logger_->Trace("GraphicsService", "RenderScene",
|
||||
"commands.size=" + std::to_string(commands.size()) +
|
||||
", viewProj.size=" + std::to_string(viewProj.size()));
|
||||
", viewProj.size=" + std::to_string(viewState.viewProj.size()));
|
||||
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the view-projection matrix for the frame
|
||||
backend_->SetViewProjection(viewProj);
|
||||
backend_->SetViewState(viewState);
|
||||
|
||||
// Execute draw calls
|
||||
for (const auto& command : commands) {
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
void UploadIndexData(const std::vector<uint16_t>& indices) override;
|
||||
bool BeginFrame() override;
|
||||
void RenderScene(const std::vector<RenderCommand>& commands,
|
||||
const std::array<float, 16>& viewProj) override;
|
||||
const ViewState& viewState) override;
|
||||
bool EndFrame() override;
|
||||
void WaitIdle() override;
|
||||
GraphicsDeviceHandle GetDevice() const override;
|
||||
|
||||
@@ -461,8 +461,9 @@ bool GxmGraphicsBackend::EndFrame(GraphicsDeviceHandle device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GxmGraphicsBackend::SetViewProjection(const std::array<float, 16>& viewProj) {
|
||||
std::cout << "GXM: Setting view-projection matrix" << std::endl;
|
||||
void GxmGraphicsBackend::SetViewState(const ViewState& viewState) {
|
||||
std::cout << "GXM: Setting view state" << std::endl;
|
||||
(void)viewState;
|
||||
// Matrix will be set when drawing with specific pipeline
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
bool BeginFrame(GraphicsDeviceHandle device) override;
|
||||
bool EndFrame(GraphicsDeviceHandle device) override;
|
||||
|
||||
void SetViewProjection(const std::array<float, 16>& viewProj) override;
|
||||
void SetViewState(const ViewState& viewState) override;
|
||||
|
||||
void Draw(GraphicsDeviceHandle device, GraphicsPipelineHandle pipeline,
|
||||
GraphicsBufferHandle vertexBuffer, GraphicsBufferHandle indexBuffer,
|
||||
|
||||
@@ -53,7 +53,8 @@ bool MeshService::LoadFromFile(const std::string& requestedPath,
|
||||
Assimp::Importer importer;
|
||||
const aiScene* scene = importer.ReadFile(
|
||||
resolved.string(),
|
||||
aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_PreTransformVertices);
|
||||
aiProcess_Triangulate | aiProcess_JoinIdenticalVertices |
|
||||
aiProcess_PreTransformVertices | aiProcess_GenNormals);
|
||||
|
||||
if (!scene) {
|
||||
outError = importer.GetErrorString() ? importer.GetErrorString() : "Assimp failed to load mesh";
|
||||
@@ -72,9 +73,11 @@ bool MeshService::LoadFromFile(const std::string& requestedPath,
|
||||
}
|
||||
|
||||
outPayload.positions.clear();
|
||||
outPayload.normals.clear();
|
||||
outPayload.colors.clear();
|
||||
outPayload.indices.clear();
|
||||
outPayload.positions.reserve(mesh->mNumVertices);
|
||||
outPayload.normals.reserve(mesh->mNumVertices);
|
||||
outPayload.colors.reserve(mesh->mNumVertices);
|
||||
outPayload.indices.reserve(mesh->mNumFaces * 3);
|
||||
|
||||
@@ -93,6 +96,12 @@ bool MeshService::LoadFromFile(const std::string& requestedPath,
|
||||
const aiVector3D& vertex = mesh->mVertices[i];
|
||||
outPayload.positions.push_back({vertex.x, vertex.y, vertex.z});
|
||||
|
||||
aiVector3D normal(0.0f, 0.0f, 1.0f);
|
||||
if (mesh->HasNormals()) {
|
||||
normal = mesh->mNormals[i];
|
||||
}
|
||||
outPayload.normals.push_back({normal.x, normal.y, normal.z});
|
||||
|
||||
aiColor3D color = materialColor;
|
||||
if (mesh->HasVertexColors(0) && mesh->mColors[0]) {
|
||||
const aiColor4D& vertexColor = mesh->mColors[0][i];
|
||||
@@ -123,6 +132,7 @@ void MeshService::PushMeshToLua(lua_State* L, const MeshPayload& payload) {
|
||||
if (logger_) {
|
||||
logger_->Trace("MeshService", "PushMeshToLua",
|
||||
"positions.size=" + std::to_string(payload.positions.size()) +
|
||||
", normals.size=" + std::to_string(payload.normals.size()) +
|
||||
", colors.size=" + std::to_string(payload.colors.size()) +
|
||||
", indices.size=" + std::to_string(payload.indices.size()) +
|
||||
", luaStateIsNull=" + std::string(L ? "false" : "true"));
|
||||
@@ -140,6 +150,17 @@ void MeshService::PushMeshToLua(lua_State* L, const MeshPayload& payload) {
|
||||
}
|
||||
lua_setfield(L, -2, "position");
|
||||
|
||||
lua_newtable(L);
|
||||
std::array<float, 3> normal = {0.0f, 0.0f, 1.0f};
|
||||
if (vertexIndex < payload.normals.size()) {
|
||||
normal = payload.normals[vertexIndex];
|
||||
}
|
||||
for (int component = 0; component < 3; ++component) {
|
||||
lua_pushnumber(L, normal[component]);
|
||||
lua_rawseti(L, -2, component + 1);
|
||||
}
|
||||
lua_setfield(L, -2, "normal");
|
||||
|
||||
lua_newtable(L);
|
||||
for (int component = 0; component < 3; ++component) {
|
||||
lua_pushnumber(L, payload.colors[vertexIndex][component]);
|
||||
|
||||
@@ -101,9 +101,9 @@ void RenderCoordinatorService::RenderFrame(float time) {
|
||||
auto extent = graphicsService_->GetSwapchainExtent();
|
||||
float aspect = extent.second == 0 ? 1.0f
|
||||
: static_cast<float>(extent.first) / static_cast<float>(extent.second);
|
||||
auto viewProj = sceneScriptService_->GetViewProjectionMatrix(aspect);
|
||||
auto viewState = sceneScriptService_->GetViewState(aspect);
|
||||
|
||||
graphicsService_->RenderScene(renderCommands, viewProj);
|
||||
graphicsService_->RenderScene(renderCommands, viewState);
|
||||
}
|
||||
|
||||
if (!graphicsService_->EndFrame()) {
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include <lua.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -14,6 +17,46 @@
|
||||
namespace sdl3cpp::services::impl {
|
||||
namespace {
|
||||
|
||||
std::array<float, 16> MultiplyMatrices(const std::array<float, 16>& left,
|
||||
const std::array<float, 16>& right) {
|
||||
glm::mat4 leftMat = glm::make_mat4(left.data());
|
||||
glm::mat4 rightMat = glm::make_mat4(right.data());
|
||||
glm::mat4 combined = leftMat * rightMat;
|
||||
std::array<float, 16> result{};
|
||||
std::memcpy(result.data(), glm::value_ptr(combined), sizeof(float) * result.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ReadMatrixField(lua_State* L, int tableIndex, const char* field, std::array<float, 16>& target) {
|
||||
lua_getfield(L, tableIndex, field);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
return false;
|
||||
}
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error(std::string("Field '") + field + "' must be a 4x4 matrix");
|
||||
}
|
||||
target = lua::ReadMatrix(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadVector3Field(lua_State* L, int tableIndex, const char* field, std::array<float, 3>& target) {
|
||||
lua_getfield(L, tableIndex, field);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
return false;
|
||||
}
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error(std::string("Field '") + field + "' must be a vec3");
|
||||
}
|
||||
target = lua::ReadVector3(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<core::Vertex> ReadVertexArray(lua_State* L, int index, const std::shared_ptr<ILogger>& logger) {
|
||||
int absIndex = lua_absindex(L, index);
|
||||
if (!lua_istable(L, absIndex)) {
|
||||
@@ -44,6 +87,14 @@ std::vector<core::Vertex> ReadVertexArray(lua_State* L, int index, const std::sh
|
||||
vertex.position = lua::ReadVector3(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, vertexIndex, "normal");
|
||||
if (lua_istable(L, -1)) {
|
||||
vertex.normal = lua::ReadVector3(L, -1);
|
||||
} else {
|
||||
vertex.normal = {0.0f, 0.0f, 1.0f};
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, vertexIndex, "color");
|
||||
vertex.color = lua::ReadVector3(L, -1);
|
||||
lua_pop(L, 1);
|
||||
@@ -232,12 +283,66 @@ std::array<float, 16> SceneScriptService::ComputeModelMatrix(int functionRef, fl
|
||||
return matrix;
|
||||
}
|
||||
|
||||
std::array<float, 16> SceneScriptService::GetViewProjectionMatrix(float aspect) {
|
||||
ViewState SceneScriptService::GetViewState(float aspect) {
|
||||
if (logger_) {
|
||||
logger_->Trace("SceneScriptService", "GetViewProjectionMatrix", "aspect=" + std::to_string(aspect));
|
||||
logger_->Trace("SceneScriptService", "GetViewState", "aspect=" + std::to_string(aspect));
|
||||
}
|
||||
lua_State* L = GetLuaState();
|
||||
|
||||
ViewState state;
|
||||
state.view = lua::IdentityMatrix();
|
||||
state.proj = lua::IdentityMatrix();
|
||||
state.viewProj = lua::IdentityMatrix();
|
||||
state.cameraPosition = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
lua_getglobal(L, "get_view_state");
|
||||
if (lua_isfunction(L, -1)) {
|
||||
lua_pushnumber(L, aspect);
|
||||
if (lua_pcall(L, 1, 1, 0) != LUA_OK) {
|
||||
std::string message = lua::GetLuaError(L);
|
||||
lua_pop(L, 1);
|
||||
if (logger_) {
|
||||
logger_->Error("Lua get_view_state failed: " + message);
|
||||
}
|
||||
throw std::runtime_error("Lua get_view_state failed: " + message);
|
||||
}
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
if (logger_) {
|
||||
logger_->Error("'get_view_state' did not return a table");
|
||||
}
|
||||
throw std::runtime_error("'get_view_state' did not return a table");
|
||||
}
|
||||
bool hasView = false;
|
||||
bool hasProj = false;
|
||||
bool hasViewProj = false;
|
||||
|
||||
try {
|
||||
hasView = ReadMatrixField(L, -1, "view", state.view);
|
||||
hasProj = ReadMatrixField(L, -1, "proj", state.proj);
|
||||
hasViewProj = ReadMatrixField(L, -1, "view_proj", state.viewProj);
|
||||
if (!hasViewProj) {
|
||||
hasViewProj = ReadMatrixField(L, -1, "viewProj", state.viewProj);
|
||||
}
|
||||
ReadVector3Field(L, -1, "camera_pos", state.cameraPosition);
|
||||
ReadVector3Field(L, -1, "camera_position", state.cameraPosition);
|
||||
} catch (const std::exception& ex) {
|
||||
lua_pop(L, 1);
|
||||
if (logger_) {
|
||||
logger_->Error("Lua get_view_state returned invalid data: " + std::string(ex.what()));
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (!hasViewProj && hasView && hasProj) {
|
||||
state.viewProj = MultiplyMatrices(state.proj, state.view);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
lua_getglobal(L, "get_view_projection");
|
||||
if (!lua_isfunction(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
@@ -262,9 +367,9 @@ std::array<float, 16> SceneScriptService::GetViewProjectionMatrix(float aspect)
|
||||
}
|
||||
throw std::runtime_error("'get_view_projection' did not return a table");
|
||||
}
|
||||
std::array<float, 16> matrix = lua::ReadMatrix(L, -1);
|
||||
state.viewProj = lua::ReadMatrix(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return matrix;
|
||||
return state;
|
||||
}
|
||||
|
||||
lua_State* SceneScriptService::GetLuaState() const {
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
|
||||
std::vector<SceneObject> LoadSceneObjects() override;
|
||||
std::array<float, 16> ComputeModelMatrix(int functionRef, float time) override;
|
||||
std::array<float, 16> GetViewProjectionMatrix(float aspect) override;
|
||||
ViewState GetViewState(float aspect) override;
|
||||
|
||||
private:
|
||||
lua_State* GetLuaState() const;
|
||||
|
||||
@@ -34,6 +34,16 @@ struct ShaderPaths {
|
||||
bool disableDepthTest = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief View state used for per-frame uniforms.
|
||||
*/
|
||||
struct ViewState {
|
||||
std::array<float, 16> view{};
|
||||
std::array<float, 16> proj{};
|
||||
std::array<float, 16> viewProj{};
|
||||
std::array<float, 3> cameraPosition{};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Render command for a single draw call.
|
||||
*/
|
||||
|
||||
@@ -140,11 +140,11 @@ public:
|
||||
virtual bool EndFrame(GraphicsDeviceHandle device) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the view-projection matrix for the current frame.
|
||||
* @brief Set the view state for the current frame.
|
||||
*
|
||||
* @param viewProj View-projection matrix
|
||||
* @param viewState Per-frame view state
|
||||
*/
|
||||
virtual void SetViewProjection(const std::array<float, 16>& viewProj) = 0;
|
||||
virtual void SetViewState(const ViewState& viewState) = 0;
|
||||
|
||||
/**
|
||||
* @brief Draw with a pipeline.
|
||||
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
* @param viewProj View-projection matrix
|
||||
*/
|
||||
virtual void RenderScene(const std::vector<RenderCommand>& commands,
|
||||
const std::array<float, 16>& viewProj) = 0;
|
||||
const ViewState& viewState) = 0;
|
||||
|
||||
/**
|
||||
* @brief End the frame and present the rendered image.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "scene_types.hpp"
|
||||
#include <array>
|
||||
#include "graphics_types.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace sdl3cpp::services {
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
|
||||
virtual std::vector<SceneObject> LoadSceneObjects() = 0;
|
||||
virtual std::array<float, 16> ComputeModelMatrix(int functionRef, float time) = 0;
|
||||
virtual std::array<float, 16> GetViewProjectionMatrix(float aspect) = 0;
|
||||
virtual ViewState GetViewState(float aspect) = 0;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace sdl3cpp::services {
|
||||
|
||||
struct MeshPayload {
|
||||
std::vector<std::array<float, 3>> positions;
|
||||
std::vector<std::array<float, 3>> normals;
|
||||
std::vector<std::array<float, 3>> colors;
|
||||
std::vector<uint32_t> indices;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user