refactor: route builtin forward pipeline through shader assets

This commit is contained in:
2026-04-02 19:00:48 +08:00
parent 86144416af
commit 9f7d8fd68d
8 changed files with 585 additions and 220 deletions

View File

@@ -6,6 +6,7 @@
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Resources/Material/Material.h>
#include <XCEngine/Resources/Mesh/Mesh.h>
#include <XCEngine/Resources/Shader/Shader.h>
#include <XCEngine/Resources/Texture/Texture.h>
#include <algorithm>
@@ -20,8 +21,10 @@ namespace {
constexpr const char* kBuiltinPrefix = "builtin://";
constexpr const char* kBuiltinMeshPrefix = "builtin://meshes/";
constexpr const char* kBuiltinMaterialPrefix = "builtin://materials/";
constexpr const char* kBuiltinShaderPrefix = "builtin://shaders/";
constexpr const char* kBuiltinTexturePrefix = "builtin://textures/";
constexpr const char* kBuiltinDefaultPrimitiveMaterialPath = "builtin://materials/default-primitive";
constexpr const char* kBuiltinForwardLitShaderPath = "builtin://shaders/forward-lit";
constexpr const char* kBuiltinDefaultPrimitiveTexturePath = "builtin://textures/default-primitive-albedo";
constexpr float kPi = 3.14159265358979323846f;
@@ -30,6 +33,187 @@ struct MeshBuffers {
std::vector<Core::uint32> indices;
};
const char kBuiltinForwardHlsl[] = R"(
Texture2D gBaseColorTexture : register(t1);
SamplerState gLinearSampler : register(s1);
cbuffer PerObjectConstants : register(b1) {
float4x4 gProjectionMatrix;
float4x4 gViewMatrix;
float4x4 gModelMatrix;
float4x4 gNormalMatrix;
float4 gMainLightDirectionAndIntensity;
float4 gMainLightColorAndFlags;
};
cbuffer MaterialConstants : register(b2) {
float4 gBaseColorFactor;
};
struct VSInput {
float3 position : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
};
struct PSInput {
float4 position : SV_POSITION;
float3 normalWS : TEXCOORD0;
float2 texcoord : TEXCOORD1;
};
PSInput MainVS(VSInput input) {
PSInput output;
float4 positionWS = mul(gModelMatrix, float4(input.position, 1.0f));
float4 positionVS = mul(gViewMatrix, positionWS);
output.position = mul(gProjectionMatrix, positionVS);
output.normalWS = mul((float3x3)gNormalMatrix, input.normal);
output.texcoord = input.texcoord;
return output;
}
float4 MainPS(PSInput input) : SV_TARGET {
float4 baseColor = gBaseColorTexture.Sample(gLinearSampler, input.texcoord) * gBaseColorFactor;
if (gMainLightColorAndFlags.a < 0.5f) {
return baseColor;
}
float3 normalWS = normalize(input.normalWS);
float3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz);
float diffuse = saturate(dot(normalWS, directionToLightWS));
float3 lighting = float3(0.28f, 0.28f, 0.28f) +
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w);
return float4(baseColor.rgb * lighting, baseColor.a);
}
)";
const char kBuiltinForwardVertexShader[] = R"(#version 430
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aTexCoord;
layout(std140, binding = 1) uniform PerObjectConstants {
mat4 gProjectionMatrix;
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
out vec3 vNormalWS;
out vec2 vTexCoord;
void main() {
vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0);
vec4 positionVS = gViewMatrix * positionWS;
gl_Position = gProjectionMatrix * positionVS;
vNormalWS = mat3(gNormalMatrix) * aNormal;
vTexCoord = aTexCoord;
}
)";
const char kBuiltinForwardFragmentShader[] = R"(#version 430
layout(binding = 1) uniform sampler2D uBaseColorTexture;
layout(std140, binding = 1) uniform PerObjectConstants {
mat4 gProjectionMatrix;
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
layout(std140, binding = 2) uniform MaterialConstants {
vec4 gBaseColorFactor;
};
in vec3 vNormalWS;
in vec2 vTexCoord;
layout(location = 0) out vec4 fragColor;
void main() {
vec4 baseColor = texture(uBaseColorTexture, vTexCoord) * gBaseColorFactor;
if (gMainLightColorAndFlags.w < 0.5) {
fragColor = baseColor;
return;
}
vec3 normalWS = normalize(vNormalWS);
vec3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz);
float diffuse = max(dot(normalWS, directionToLightWS), 0.0);
vec3 lighting = vec3(0.28) +
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w);
fragColor = vec4(baseColor.rgb * lighting, baseColor.a);
}
)";
const char kBuiltinForwardVulkanVertexShader[] = R"(#version 450
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aTexCoord;
layout(set = 1, binding = 0, std140) uniform PerObjectConstants {
mat4 gProjectionMatrix;
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
layout(location = 0) out vec3 vNormalWS;
layout(location = 1) out vec2 vTexCoord;
void main() {
vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0);
vec4 positionVS = gViewMatrix * positionWS;
gl_Position = gProjectionMatrix * positionVS;
vNormalWS = mat3(gNormalMatrix) * aNormal;
vTexCoord = aTexCoord;
}
)";
const char kBuiltinForwardVulkanFragmentShader[] = R"(#version 450
layout(set = 3, binding = 0) uniform texture2D uBaseColorTexture;
layout(set = 4, binding = 0) uniform sampler uLinearSampler;
layout(set = 1, binding = 0, std140) uniform PerObjectConstants {
mat4 gProjectionMatrix;
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
layout(set = 2, binding = 0, std140) uniform MaterialConstants {
vec4 gBaseColorFactor;
};
layout(location = 0) in vec3 vNormalWS;
layout(location = 1) in vec2 vTexCoord;
layout(location = 0) out vec4 fragColor;
void main() {
vec4 baseColor = texture(sampler2D(uBaseColorTexture, uLinearSampler), vTexCoord) * gBaseColorFactor;
if (gMainLightColorAndFlags.w < 0.5) {
fragColor = baseColor;
return;
}
vec3 normalWS = normalize(vNormalWS);
vec3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz);
float diffuse = max(dot(normalWS, directionToLightWS), 0.0);
vec3 lighting = vec3(0.28) +
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w);
fragColor = vec4(baseColor.rgb * lighting, baseColor.a);
}
)";
Math::Bounds ComputeBounds(const std::vector<StaticMeshVertex>& vertices) {
if (vertices.empty()) {
return Math::Bounds();
@@ -481,6 +665,117 @@ Mesh* BuildMeshResource(
return mesh;
}
void AddBuiltinShaderStageVariant(
Shader& shader,
const Containers::String& passName,
ShaderType stage,
ShaderLanguage language,
ShaderBackend backend,
const char* sourceCode,
const char* entryPoint,
const char* profile) {
ShaderStageVariant variant = {};
variant.stage = stage;
variant.language = language;
variant.backend = backend;
variant.sourceCode = Containers::String(sourceCode);
variant.entryPoint = Containers::String(entryPoint);
variant.profile = Containers::String(profile);
shader.AddPassVariant(passName, variant);
}
size_t CalculateBuiltinShaderMemorySize(const Shader& shader) {
size_t memorySize = sizeof(Shader) + shader.GetName().Length() + shader.GetPath().Length();
for (const ShaderPass& pass : shader.GetPasses()) {
memorySize += pass.name.Length();
for (const ShaderPassTagEntry& tag : pass.tags) {
memorySize += tag.name.Length();
memorySize += tag.value.Length();
}
for (const ShaderStageVariant& variant : pass.variants) {
memorySize += variant.entryPoint.Length();
memorySize += variant.profile.Length();
memorySize += variant.sourceCode.Length();
memorySize += variant.compiledBinary.Size();
}
}
return memorySize;
}
Shader* BuildBuiltinForwardLitShader(const Containers::String& path) {
auto* shader = new Shader();
IResource::ConstructParams params;
params.name = Containers::String("Builtin Forward Lit");
params.path = path;
params.guid = ResourceGUID::Generate(path);
params.memorySize = 0;
shader->Initialize(params);
const Containers::String passName("ForwardLit");
shader->SetPassTag(passName, "LightMode", "ForwardBase");
AddBuiltinShaderStageVariant(
*shader,
passName,
ShaderType::Vertex,
ShaderLanguage::HLSL,
ShaderBackend::D3D12,
kBuiltinForwardHlsl,
"MainVS",
"vs_5_0");
AddBuiltinShaderStageVariant(
*shader,
passName,
ShaderType::Fragment,
ShaderLanguage::HLSL,
ShaderBackend::D3D12,
kBuiltinForwardHlsl,
"MainPS",
"ps_5_0");
AddBuiltinShaderStageVariant(
*shader,
passName,
ShaderType::Vertex,
ShaderLanguage::GLSL,
ShaderBackend::OpenGL,
kBuiltinForwardVertexShader,
"main",
"vs_4_30");
AddBuiltinShaderStageVariant(
*shader,
passName,
ShaderType::Fragment,
ShaderLanguage::GLSL,
ShaderBackend::OpenGL,
kBuiltinForwardFragmentShader,
"main",
"fs_4_30");
AddBuiltinShaderStageVariant(
*shader,
passName,
ShaderType::Vertex,
ShaderLanguage::GLSL,
ShaderBackend::Vulkan,
kBuiltinForwardVulkanVertexShader,
"main",
"vs_4_50");
AddBuiltinShaderStageVariant(
*shader,
passName,
ShaderType::Fragment,
ShaderLanguage::GLSL,
ShaderBackend::Vulkan,
kBuiltinForwardVulkanFragmentShader,
"main",
"fs_4_50");
shader->m_memorySize = CalculateBuiltinShaderMemorySize(*shader);
return shader;
}
Material* BuildDefaultPrimitiveMaterial(const Containers::String& path) {
auto* material = new Material();
IResource::ConstructParams params;
@@ -494,6 +789,7 @@ Material* BuildDefaultPrimitiveMaterial(const Containers::String& path) {
renderState.cullMode = MaterialCullMode::Back;
material->SetRenderState(renderState);
material->SetRenderQueue(MaterialRenderQueue::Geometry);
material->SetShader(ResourceManager::Get().Load<Shader>(GetBuiltinForwardLitShaderPath()));
material->SetTexture(
Containers::String("baseColorTexture"),
ResourceManager::Get().Load<Texture>(GetBuiltinDefaultPrimitiveTexturePath()));
@@ -542,6 +838,10 @@ bool IsBuiltinMaterialPath(const Containers::String& path) {
return path.StartsWith(kBuiltinMaterialPrefix);
}
bool IsBuiltinShaderPath(const Containers::String& path) {
return path.StartsWith(kBuiltinShaderPrefix);
}
bool IsBuiltinTexturePath(const Containers::String& path) {
return path.StartsWith(kBuiltinTexturePrefix);
}
@@ -574,6 +874,10 @@ Containers::String GetBuiltinDefaultPrimitiveMaterialPath() {
return Containers::String(kBuiltinDefaultPrimitiveMaterialPath);
}
Containers::String GetBuiltinForwardLitShaderPath() {
return Containers::String(kBuiltinForwardLitShaderPath);
}
Containers::String GetBuiltinDefaultPrimitiveTexturePath() {
return Containers::String(kBuiltinDefaultPrimitiveTexturePath);
}
@@ -660,6 +964,19 @@ LoadResult CreateBuiltinMaterialResource(const Containers::String& path) {
return LoadResult(material);
}
LoadResult CreateBuiltinShaderResource(const Containers::String& path) {
if (path != GetBuiltinForwardLitShaderPath()) {
return LoadResult(Containers::String("Unknown builtin shader: ") + path);
}
Shader* shader = BuildBuiltinForwardLitShader(path);
if (shader == nullptr) {
return LoadResult(Containers::String("Failed to create builtin shader: ") + path);
}
return LoadResult(shader);
}
LoadResult CreateBuiltinTextureResource(const Containers::String& path) {
if (path != GetBuiltinDefaultPrimitiveTexturePath()) {
return LoadResult(Containers::String("Unknown builtin texture: ") + path);

View File

@@ -1,4 +1,5 @@
#include <XCEngine/Resources/Shader/ShaderLoader.h>
#include <XCEngine/Resources/BuiltinResources.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Core/Asset/ResourceTypes.h>
@@ -22,12 +23,20 @@ Containers::Array<Containers::String> ShaderLoader::GetSupportedExtensions() con
}
bool ShaderLoader::CanLoad(const Containers::String& path) const {
if (IsBuiltinShaderPath(path)) {
return true;
}
Containers::String ext = GetExtension(path);
return ext == "vert" || ext == "frag" || ext == "geom" ||
ext == "comp" || ext == "glsl" || ext == "hlsl" || ext == "shader";
}
LoadResult ShaderLoader::Load(const Containers::String& path, const ImportSettings* settings) {
if (IsBuiltinShaderPath(path)) {
return CreateBuiltinShaderResource(path);
}
Containers::Array<Core::uint8> data = ReadFileData(path);
if (data.Empty()) {
return LoadResult("Failed to read shader file: " + path);