feat(shader): Update shader handling to support multiple shader keys across various components

This commit is contained in:
2026-01-07 12:27:20 +00:00
parent fbacb18f2e
commit 22f9a98ee1
13 changed files with 114 additions and 51 deletions

View File

@@ -741,7 +741,7 @@ local function create_static_cube(position, scale, color, shader_key)
vertices = vertices,
indices = cube_indices,
compute_model_matrix = compute_model_matrix,
shader_key = resolved_shader,
shader_keys = {resolved_shader},
}
end
@@ -758,7 +758,7 @@ local function create_skybox()
vertices = apply_color_to_vertices(skybox_color),
indices = (#cube_indices_double_sided > 0) and cube_indices_double_sided or cube_indices,
compute_model_matrix = compute_model_matrix,
shader_key = "skybox",
shader_keys = {"skybox"},
}
end
@@ -791,7 +791,7 @@ local function create_physics_cube()
vertices = apply_color_to_vertices(physics_state.cube_color),
indices = (#cube_indices_double_sided > 0) and cube_indices_double_sided or cube_indices,
compute_model_matrix = compute_model_matrix,
shader_key = shader_key,
shader_keys = {shader_key},
}
end
@@ -809,7 +809,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 = shader_key,
shader_keys = {shader_key},
}
end

View File

@@ -590,7 +590,7 @@ function get_scene_objects()
{
vertices = map_mesh.vertices,
indices = map_mesh.indices,
shader_key = map_shader_key,
shader_keys = {map_shader_key},
compute_model_matrix = function()
return map_model_matrix
end,

View File

@@ -251,7 +251,7 @@ local function createCube(position)
vertices = cubeVertices,
indices = cubeIndices,
compute_model_matrix = computeModel,
shader_key = "default",
shader_keys = {"default"},
}
end

View File

@@ -155,6 +155,42 @@ void GraphicsService::RenderScene(const std::vector<RenderCommand>& commands,
// Set the view-projection matrix for the frame
backend_->SetViewState(viewState);
if (commands.empty()) {
return;
}
if (!vertexBuffer_ || !indexBuffer_) {
logger_->Error("GraphicsService::RenderScene: Vertex/index buffers not uploaded");
return;
}
for (size_t commandIndex = 0; commandIndex < commands.size(); ++commandIndex) {
const auto& command = commands[commandIndex];
if (command.shaderKeys.empty()) {
logger_->Error("GraphicsService::RenderScene: Render command missing shader keys");
continue;
}
if (logger_) {
logger_->Trace("GraphicsService", "RenderScene",
"commandIndex=" + std::to_string(commandIndex) +
", shaderKeyCount=" + std::to_string(command.shaderKeys.size()));
}
for (const auto& shaderKey : command.shaderKeys) {
auto it = pipelines_.find(shaderKey);
if (it == pipelines_.end()) {
logger_->Error("GraphicsService::RenderScene: Missing pipeline for shaderKey=" + shaderKey);
continue;
}
backend_->Draw(device_,
it->second,
vertexBuffer_,
indexBuffer_,
command.indexOffset,
command.indexCount,
command.vertexOffset,
command.modelMatrix);
}
}
}
bool GraphicsService::EndFrame() {

View File

@@ -52,10 +52,10 @@ private:
std::shared_ptr<ILogger> logger_;
std::shared_ptr<IGraphicsBackend> backend_;
std::shared_ptr<IWindowService> windowService_;
GraphicsDeviceHandle device_;
GraphicsDeviceHandle device_ = nullptr;
std::unordered_map<std::string, GraphicsPipelineHandle> pipelines_;
GraphicsBufferHandle vertexBuffer_;
GraphicsBufferHandle indexBuffer_;
GraphicsBufferHandle vertexBuffer_ = nullptr;
GraphicsBufferHandle indexBuffer_ = nullptr;
// Other state
bool initialized_ = false;
};

View File

@@ -237,12 +237,29 @@ std::vector<SceneObject> SceneScriptService::LoadSceneObjects() {
object.computeModelMatrixRef = -1;
}
lua_getfield(L, -1, "shader_key");
if (lua_isstring(L, -1)) {
object.shaderKey = lua_tostring(L, -1);
object.shaderKeys.clear();
lua_getfield(L, -1, "shader_keys");
if (lua_istable(L, -1)) {
const size_t count = lua_rawlen(L, -1);
object.shaderKeys.reserve(count);
for (size_t keyIndex = 1; keyIndex <= count; ++keyIndex) {
lua_rawgeti(L, -1, static_cast<int>(keyIndex));
if (lua_isstring(L, -1)) {
object.shaderKeys.emplace_back(lua_tostring(L, -1));
}
lua_pop(L, 1);
}
}
lua_pop(L, 1);
if (object.shaderKeys.empty()) {
lua_getfield(L, -1, "shader_key");
if (lua_isstring(L, -1)) {
object.shaderKeys.emplace_back(lua_tostring(L, -1));
}
lua_pop(L, 1);
}
objects.push_back(std::move(object));
lua_pop(L, 1);
}

View File

@@ -73,12 +73,18 @@ void SceneService::LoadScene(const std::vector<SceneObject>& objects) {
}
throw std::runtime_error("Scene object missing vertex or index data");
}
if (obj.shaderKeys.empty()) {
if (logger_) {
logger_->Error("Scene object missing shader keys");
}
throw std::runtime_error("Scene object missing shader keys");
}
auto entity = registry_->create();
sceneEntities_.push_back(entity);
registry_->emplace<SceneTag>(entity);
registry_->emplace<MeshComponent>(entity, obj.vertices, obj.indices);
registry_->emplace<RenderComponent>(entity, obj.computeModelMatrixRef, obj.shaderKey);
registry_->emplace<RenderComponent>(entity, obj.computeModelMatrixRef, obj.shaderKeys);
}
for (const auto entity : sceneEntities_) {
@@ -118,7 +124,7 @@ void SceneService::LoadScene(const std::vector<SceneObject>& objects) {
drawInfo.indexCount = static_cast<uint32_t>(mesh.indices.size());
drawInfo.vertexOffset = static_cast<int32_t>(vertexOffset);
drawInfo.computeModelMatrixRef = render.computeModelMatrixRef;
drawInfo.shaderKey = render.shaderKey;
drawInfo.shaderKeys = render.shaderKeys;
drawInfos_.push_back(std::move(drawInfo));
}
@@ -156,7 +162,7 @@ std::vector<RenderCommand> SceneService::GetRenderCommands(float time) const {
cmd.indexOffset = drawInfo.indexOffset;
cmd.indexCount = drawInfo.indexCount;
cmd.vertexOffset = drawInfo.vertexOffset;
cmd.shaderKey = drawInfo.shaderKey;
cmd.shaderKeys = drawInfo.shaderKeys;
cmd.modelMatrix = scriptService_->ComputeModelMatrix(drawInfo.computeModelMatrixRef, time);
commands.push_back(cmd);
}

View File

@@ -48,7 +48,7 @@ private:
struct RenderComponent {
int computeModelMatrixRef = -1;
std::string shaderKey;
std::vector<std::string> shaderKeys;
};
struct SceneDrawInfo {
@@ -56,7 +56,7 @@ private:
uint32_t indexCount = 0;
int32_t vertexOffset = 0;
int computeModelMatrixRef = -1;
std::string shaderKey;
std::vector<std::string> shaderKeys;
};
void ClearSceneEntities();

View File

@@ -34,43 +34,44 @@ std::unordered_map<std::string, ShaderPaths> ShaderScriptService::LoadShaderPath
if (configService_) {
const auto& materialConfig = configService_->GetMaterialXConfig();
const auto& materialOverrides = configService_->GetMaterialXMaterialConfigs();
if (!materialOverrides.empty()) {
for (const auto& overrideConfig : materialOverrides) {
if (!overrideConfig.enabled) {
continue;
}
MaterialXConfig resolvedConfig = materialConfig;
resolvedConfig.enabled = true;
resolvedConfig.documentPath = overrideConfig.documentPath;
resolvedConfig.shaderKey = overrideConfig.shaderKey;
resolvedConfig.materialName = overrideConfig.materialName;
resolvedConfig.useConstantColor = overrideConfig.useConstantColor;
resolvedConfig.constantColor = overrideConfig.constantColor;
try {
ShaderPaths materialShader = materialxGenerator_.Generate(
resolvedConfig,
engineService_ ? engineService_->GetScriptDirectory() : std::filesystem::path{});
if (!resolvedConfig.shaderKey.empty()) {
shaderMap[resolvedConfig.shaderKey] = std::move(materialShader);
}
} catch (const std::exception& ex) {
if (logger_) {
logger_->Error("MaterialX shader generation failed for key=" +
overrideConfig.shaderKey + ": " + std::string(ex.what()));
}
}
if (materialOverrides.empty()) {
if (logger_) {
logger_->Error("MaterialX shader generation requires materialx_materials entries");
}
throw std::runtime_error("MaterialX shader generation requires materialx_materials entries");
}
if (logger_) {
logger_->Trace("ShaderScriptService", "LoadShaderPathsMap",
"materialOverrides=" + std::to_string(materialOverrides.size()));
}
for (const auto& overrideConfig : materialOverrides) {
if (!overrideConfig.enabled) {
continue;
}
MaterialXConfig resolvedConfig = materialConfig;
resolvedConfig.enabled = true;
resolvedConfig.documentPath = overrideConfig.documentPath;
resolvedConfig.shaderKey = overrideConfig.shaderKey;
resolvedConfig.materialName = overrideConfig.materialName;
resolvedConfig.useConstantColor = overrideConfig.useConstantColor;
resolvedConfig.constantColor = overrideConfig.constantColor;
if (logger_) {
logger_->Trace("ShaderScriptService", "LoadShaderPathsMap",
"materialKey=" + resolvedConfig.shaderKey +
", document=" + resolvedConfig.documentPath.string() +
", material=" + resolvedConfig.materialName);
}
} else if (materialConfig.enabled) {
try {
ShaderPaths materialShader = materialxGenerator_.Generate(
materialConfig,
resolvedConfig,
engineService_ ? engineService_->GetScriptDirectory() : std::filesystem::path{});
if (!materialConfig.shaderKey.empty()) {
shaderMap[materialConfig.shaderKey] = std::move(materialShader);
if (!resolvedConfig.shaderKey.empty()) {
shaderMap[resolvedConfig.shaderKey] = std::move(materialShader);
}
} catch (const std::exception& ex) {
if (logger_) {
logger_->Error("MaterialX shader generation failed: " + std::string(ex.what()));
logger_->Error("MaterialX shader generation failed for key=" +
overrideConfig.shaderKey + ": " + std::string(ex.what()));
}
}
}

View File

@@ -56,7 +56,7 @@ struct RenderCommand {
uint32_t indexOffset;
uint32_t indexCount;
int32_t vertexOffset;
std::string shaderKey;
std::vector<std::string> shaderKeys;
std::array<float, 16> modelMatrix;
};

View File

@@ -11,7 +11,7 @@ struct SceneObject {
std::vector<core::Vertex> vertices;
std::vector<uint16_t> indices;
int computeModelMatrixRef = -1;
std::string shaderKey = "default";
std::vector<std::string> shaderKeys;
};
} // namespace sdl3cpp::services

View File

@@ -19,7 +19,7 @@ function get_scene_objects()
compute_model_matrix = function(time)
return identity_matrix()
end,
shader_key = "test",
shader_keys = {"test"},
},
}
end

View File

@@ -78,7 +78,10 @@ int main() {
const auto& object = objects.front();
Assert(object.vertices.size() == 3, "scene object should yield three vertices", failures);
Assert(object.indices.size() == 3, "scene object should yield three indices", failures);
Assert(object.shaderKey == "test", "shader key should match fixture", failures);
Assert(object.shaderKeys.size() == 1, "shader keys should contain one entry", failures);
if (!object.shaderKeys.empty()) {
Assert(object.shaderKeys.front() == "test", "shader key should match fixture", failures);
}
const std::vector<uint16_t> expectedIndices{0, 1, 2};
Assert(object.indices == expectedIndices, "indices should be zero-based", failures);
Assert(object.computeModelMatrixRef >= 0,