rendering: strip redundant builtin material pass hints

This commit is contained in:
2026-04-07 09:30:36 +08:00
parent 945420f3bd
commit 5913462178
8 changed files with 327 additions and 17 deletions

View File

@@ -45,6 +45,23 @@ inline bool IsObjectIdPassName(const Containers::String& value) {
normalized == Containers::String("editorobjectid");
}
inline bool IsSkyboxPassName(const Containers::String& value) {
const Containers::String normalized = NormalizeBuiltinPassMetadataValue(value);
return normalized == Containers::String("skybox");
}
inline bool IsPostProcessPassName(const Containers::String& value) {
const Containers::String normalized = NormalizeBuiltinPassMetadataValue(value);
return normalized == Containers::String("postprocess") ||
normalized == Containers::String("colorscale");
}
inline bool IsFinalColorPassName(const Containers::String& value) {
const Containers::String normalized = NormalizeBuiltinPassMetadataValue(value);
return normalized == Containers::String("finaloutput") ||
normalized == Containers::String("finalcolor");
}
inline bool MatchesBuiltinPassName(
const Containers::String& value,
BuiltinMaterialPass pass) {
@@ -59,11 +76,61 @@ inline bool MatchesBuiltinPassName(
return IsShadowCasterPassName(value);
case BuiltinMaterialPass::ObjectId:
return IsObjectIdPassName(value);
case BuiltinMaterialPass::Skybox:
return IsSkyboxPassName(value);
case BuiltinMaterialPass::PostProcess:
return IsPostProcessPassName(value);
case BuiltinMaterialPass::FinalColor:
return IsFinalColorPassName(value);
default:
return false;
}
}
inline bool TryResolveBuiltinMaterialPassHint(
const Containers::String& value,
BuiltinMaterialPass& outPass) {
const Containers::String normalized = NormalizeBuiltinPassMetadataValue(value);
if (normalized.Empty()) {
return false;
}
if (IsForwardPassName(normalized)) {
outPass = BuiltinMaterialPass::ForwardLit;
return true;
}
if (IsUnlitPassName(normalized)) {
outPass = BuiltinMaterialPass::Unlit;
return true;
}
if (IsDepthOnlyPassName(normalized)) {
outPass = BuiltinMaterialPass::DepthOnly;
return true;
}
if (IsShadowCasterPassName(normalized)) {
outPass = BuiltinMaterialPass::ShadowCaster;
return true;
}
if (IsObjectIdPassName(normalized)) {
outPass = BuiltinMaterialPass::ObjectId;
return true;
}
if (IsSkyboxPassName(normalized)) {
outPass = BuiltinMaterialPass::Skybox;
return true;
}
if (IsPostProcessPassName(normalized)) {
outPass = BuiltinMaterialPass::PostProcess;
return true;
}
if (IsFinalColorPassName(normalized)) {
outPass = BuiltinMaterialPass::FinalColor;
return true;
}
return false;
}
inline bool ShaderPassHasExplicitBuiltinMetadata(const Resources::ShaderPass& shaderPass) {
if (!shaderPass.name.Empty() &&
shaderPass.name != Containers::String("Default")) {
@@ -116,6 +183,27 @@ inline bool ShaderPassMatchesBuiltinPass(
return hasMetadata;
}
inline bool IsRedundantLegacyMaterialShaderPassHint(
const Resources::Shader* shader,
const Containers::String& shaderPass) {
if (shader == nullptr) {
return false;
}
BuiltinMaterialPass builtinPass = BuiltinMaterialPass::ForwardLit;
if (!TryResolveBuiltinMaterialPassHint(shaderPass, builtinPass)) {
return false;
}
for (const Resources::ShaderPass& pass : shader->GetPasses()) {
if (ShaderPassMatchesBuiltinPass(pass, builtinPass)) {
return true;
}
}
return false;
}
inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic(
const Resources::ShaderResourceBindingDesc& binding) {
Containers::String semantic = NormalizeBuiltinPassMetadataValue(binding.semantic);
@@ -143,11 +231,34 @@ inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic(
return BuiltinPassResourceSemantic::ShadowReceiver;
}
if (semantic == Containers::String("environment") ||
semantic == Containers::String("environmentconstants")) {
return BuiltinPassResourceSemantic::Environment;
}
if (semantic == Containers::String("passconstants") ||
semantic == Containers::String("finalcolorconstants") ||
semantic == Containers::String("postprocessconstants")) {
return BuiltinPassResourceSemantic::PassConstants;
}
if (semantic == Containers::String("basecolortexture") ||
semantic == Containers::String("maintex")) {
return BuiltinPassResourceSemantic::BaseColorTexture;
}
if (semantic == Containers::String("sourcecolortexture")) {
return BuiltinPassResourceSemantic::SourceColorTexture;
}
if (semantic == Containers::String("skyboxpanoramictexture")) {
return BuiltinPassResourceSemantic::SkyboxPanoramicTexture;
}
if (semantic == Containers::String("skyboxtexture")) {
return BuiltinPassResourceSemantic::SkyboxTexture;
}
if (semantic == Containers::String("shadowmaptexture") ||
semantic == Containers::String("shadowmap")) {
return BuiltinPassResourceSemantic::ShadowMapTexture;
@@ -175,8 +286,18 @@ inline const char* BuiltinPassResourceSemanticToString(BuiltinPassResourceSemant
return "Lighting";
case BuiltinPassResourceSemantic::ShadowReceiver:
return "ShadowReceiver";
case BuiltinPassResourceSemantic::Environment:
return "Environment";
case BuiltinPassResourceSemantic::PassConstants:
return "PassConstants";
case BuiltinPassResourceSemantic::BaseColorTexture:
return "BaseColorTexture";
case BuiltinPassResourceSemantic::SourceColorTexture:
return "SourceColorTexture";
case BuiltinPassResourceSemantic::SkyboxPanoramicTexture:
return "SkyboxPanoramicTexture";
case BuiltinPassResourceSemantic::SkyboxTexture:
return "SkyboxTexture";
case BuiltinPassResourceSemantic::ShadowMapTexture:
return "ShadowMapTexture";
case BuiltinPassResourceSemantic::LinearClampSampler:
@@ -238,11 +359,16 @@ inline bool IsBuiltinPassResourceTypeCompatible(
case BuiltinPassResourceSemantic::Material:
case BuiltinPassResourceSemantic::Lighting:
case BuiltinPassResourceSemantic::ShadowReceiver:
case BuiltinPassResourceSemantic::Environment:
case BuiltinPassResourceSemantic::PassConstants:
return type == Resources::ShaderResourceType::ConstantBuffer;
case BuiltinPassResourceSemantic::BaseColorTexture:
case BuiltinPassResourceSemantic::SourceColorTexture:
case BuiltinPassResourceSemantic::SkyboxPanoramicTexture:
case BuiltinPassResourceSemantic::ShadowMapTexture:
return type == Resources::ShaderResourceType::Texture2D ||
type == Resources::ShaderResourceType::TextureCube;
return type == Resources::ShaderResourceType::Texture2D;
case BuiltinPassResourceSemantic::SkyboxTexture:
return type == Resources::ShaderResourceType::TextureCube;
case BuiltinPassResourceSemantic::LinearClampSampler:
case BuiltinPassResourceSemantic::ShadowMapSampler:
return type == Resources::ShaderResourceType::Sampler;

View File

@@ -2,6 +2,7 @@
#include <XCEngine/Core/Asset/ArtifactFormats.h>
#include <XCEngine/Debug/Logger.h>
#include <XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h>
#include <XCEngine/Resources/Material/MaterialLoader.h>
#include <XCEngine/Resources/Mesh/MeshLoader.h>
#include <XCEngine/Resources/Shader/ShaderLoader.h>
@@ -424,6 +425,19 @@ Containers::String ResolveTextureBindingPath(
return NormalizeArtifactPathString(material.GetTextureBindingPath(bindingIndex));
}
Containers::String ResolveSerializedMaterialShaderPass(const Material& material) {
const Containers::String& shaderPass = material.GetShaderPass();
if (shaderPass.Empty()) {
return Containers::String();
}
if (Rendering::IsRedundantLegacyMaterialShaderPassHint(material.GetShader(), shaderPass)) {
return Containers::String();
}
return shaderPass;
}
bool WriteMaterialArtifactFile(
const fs::path& artifactPath,
const Material& material,
@@ -445,7 +459,7 @@ bool WriteMaterialArtifactFile(
material.GetShader() != nullptr
? material.GetShader()->GetPath()
: Containers::String());
WriteString(output, material.GetShaderPass());
WriteString(output, ResolveSerializedMaterialShaderPass(material));
MaterialArtifactHeader header;
header.renderQueue = material.GetRenderQueue();

View File

@@ -1,6 +1,7 @@
#include <XCEngine/Resources/Material/MaterialLoader.h>
#include <XCEngine/Core/Asset/ArtifactFormats.h>
#include <XCEngine/Resources/BuiltinResources.h>
#include <XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Core/Asset/ResourceTypes.h>
#include <XCEngine/Resources/Shader/ShaderLoader.h>
@@ -1472,6 +1473,18 @@ bool MaterialFileExists(const Containers::String& path) {
return std::filesystem::exists(std::filesystem::path(resourceRoot.CStr()) / inputPath);
}
void ApplyMaterialShaderPassHint(Material* material, const Containers::String& shaderPass) {
if (material == nullptr || shaderPass.Empty()) {
return;
}
if (Rendering::IsRedundantLegacyMaterialShaderPassHint(material->GetShader(), shaderPass)) {
return;
}
material->SetShaderPass(shaderPass);
}
ResourceHandle<Shader> LoadShaderHandle(const Containers::String& shaderPath);
template<typename T>
@@ -1560,9 +1573,10 @@ LoadResult LoadMaterialArtifact(const Containers::String& path) {
const std::string magic(fileHeader.magic, fileHeader.magic + 7);
const bool isLegacySchema = magic == "XCMAT02" && fileHeader.schemaVersion == 2u;
const bool isSchemaV3 = magic == "XCMAT03" && fileHeader.schemaVersion == 3u;
const bool isCurrentSchema =
magic == "XCMAT03" && fileHeader.schemaVersion == kMaterialArtifactSchemaVersion;
if (!isLegacySchema && !isCurrentSchema) {
magic == "XCMAT04" && fileHeader.schemaVersion == kMaterialArtifactSchemaVersion;
if (!isLegacySchema && !isSchemaV3 && !isCurrentSchema) {
return LoadResult("Invalid material artifact magic: " + path);
}
@@ -1594,9 +1608,7 @@ LoadResult LoadMaterialArtifact(const Containers::String& path) {
material->SetShader(shaderHandle);
}
}
if (!shaderPass.Empty()) {
material->SetShaderPass(shaderPass);
}
ApplyMaterialShaderPassHint(material.get(), shaderPass);
MaterialArtifactHeader header = {};
if (isLegacySchema) {
@@ -1608,6 +1620,20 @@ LoadResult LoadMaterialArtifact(const Containers::String& path) {
header.renderQueue = legacyHeader.renderQueue;
header.renderState = legacyHeader.renderState;
header.tagCount = legacyHeader.tagCount;
header.hasRenderStateOverride = 1u;
header.propertyCount = legacyHeader.propertyCount;
header.textureBindingCount = legacyHeader.textureBindingCount;
} else if (isSchemaV3) {
MaterialArtifactHeaderV3 legacyHeader = {};
if (!ReadMaterialArtifactValue(data, offset, legacyHeader)) {
return LoadResult("Failed to parse material artifact body: " + path);
}
header.renderQueue = legacyHeader.renderQueue;
header.renderState = legacyHeader.renderState;
header.tagCount = legacyHeader.tagCount;
header.hasRenderStateOverride = 1u;
header.keywordCount = legacyHeader.keywordCount;
header.propertyCount = legacyHeader.propertyCount;
header.textureBindingCount = legacyHeader.textureBindingCount;
} else {
@@ -1618,6 +1644,7 @@ LoadResult LoadMaterialArtifact(const Containers::String& path) {
material->SetRenderQueue(header.renderQueue);
material->SetRenderState(header.renderState);
material->SetRenderStateOverrideEnabled(header.hasRenderStateOverride != 0u);
for (Core::uint32 tagIndex = 0; tagIndex < header.tagCount; ++tagIndex) {
Containers::String tagName;
@@ -1772,12 +1799,12 @@ bool MaterialLoader::ParseMaterialData(const Containers::Array<Core::uint8>& dat
if (!TryParseStringValue(jsonText, "shaderPass", shaderPass)) {
return false;
}
material->SetShaderPass(shaderPass);
ApplyMaterialShaderPassHint(material, shaderPass);
} else if (HasKey(jsonText, "pass")) {
if (!TryParseStringValue(jsonText, "pass", shaderPass)) {
return false;
}
material->SetShaderPass(shaderPass);
ApplyMaterialShaderPassHint(material, shaderPass);
}
if (HasKey(jsonText, "renderQueue")) {