Split render material utility layers
This commit is contained in:
@@ -433,6 +433,8 @@ add_library(XCEngine STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/VisibleRenderItem.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/VisibleRenderObject.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/BuiltinPassContract.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderMaterialResolve.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderMaterialStateUtils.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderSceneUtility.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderPass.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderSceneExtractor.h
|
||||
|
||||
246
engine/include/XCEngine/Rendering/RenderMaterialResolve.h
Normal file
246
engine/include/XCEngine/Rendering/RenderMaterialResolve.h
Normal file
@@ -0,0 +1,246 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Components/MeshRendererComponent.h>
|
||||
#include <XCEngine/Core/Types.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||
#include <XCEngine/Rendering/BuiltinPassContract.h>
|
||||
#include <XCEngine/Rendering/VisibleRenderItem.h>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
|
||||
struct BuiltinForwardMaterialData {
|
||||
Math::Vector4 baseColorFactor = Math::Vector4::One();
|
||||
};
|
||||
|
||||
struct MaterialConstantLayoutView {
|
||||
const Resources::MaterialConstantFieldDesc* fields = nullptr;
|
||||
size_t count = 0;
|
||||
size_t size = 0;
|
||||
|
||||
bool IsValid() const {
|
||||
return fields != nullptr && count > 0 && size > 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct MaterialConstantPayloadView {
|
||||
const void* data = nullptr;
|
||||
size_t size = 0;
|
||||
MaterialConstantLayoutView layout = {};
|
||||
|
||||
bool IsValid() const {
|
||||
return data != nullptr && size > 0 && layout.IsValid() && layout.size == size;
|
||||
}
|
||||
};
|
||||
|
||||
inline const Resources::ShaderPropertyDesc* FindShaderPropertyBySemantic(
|
||||
const Resources::Material* material,
|
||||
const Containers::String& semantic) {
|
||||
if (material == nullptr || material->GetShader() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Containers::String normalizedSemantic = NormalizeBuiltinPassMetadataValue(semantic);
|
||||
for (const Resources::ShaderPropertyDesc& property : material->GetShader()->GetProperties()) {
|
||||
if (NormalizeBuiltinPassMetadataValue(property.semantic) == normalizedSemantic) {
|
||||
return &property;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline Math::Vector4 ResolveBuiltinBaseColorFactor(const Resources::Material* material) {
|
||||
if (material == nullptr) {
|
||||
return Math::Vector4::One();
|
||||
}
|
||||
|
||||
if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "BaseColor")) {
|
||||
if (material->HasProperty(property->name) &&
|
||||
(property->type == Resources::ShaderPropertyType::Color ||
|
||||
property->type == Resources::ShaderPropertyType::Vector)) {
|
||||
return material->GetFloat4(property->name);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* kBaseColorPropertyNames[] = {
|
||||
"baseColor",
|
||||
"_BaseColor",
|
||||
"color",
|
||||
"_Color"
|
||||
};
|
||||
|
||||
for (const char* propertyName : kBaseColorPropertyNames) {
|
||||
if (material->HasProperty(Containers::String(propertyName))) {
|
||||
return material->GetFloat4(Containers::String(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
Math::Vector4 baseColor = Math::Vector4::One();
|
||||
static const char* kOpacityPropertyNames[] = {
|
||||
"opacity",
|
||||
"_Opacity",
|
||||
"alpha",
|
||||
"_Alpha"
|
||||
};
|
||||
for (const char* propertyName : kOpacityPropertyNames) {
|
||||
if (material->HasProperty(Containers::String(propertyName))) {
|
||||
baseColor.w = material->GetFloat(Containers::String(propertyName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
inline const Resources::Texture* ResolveBuiltinBaseColorTexture(const Resources::Material* material) {
|
||||
if (material == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "BaseColorTexture")) {
|
||||
const Resources::ResourceHandle<Resources::Texture> textureHandle = material->GetTexture(property->name);
|
||||
if (textureHandle.Get() != nullptr && textureHandle->IsValid()) {
|
||||
return textureHandle.Get();
|
||||
}
|
||||
}
|
||||
|
||||
static const char* kTextureNames[] = {
|
||||
"baseColorTexture",
|
||||
"_BaseColorTexture",
|
||||
"_MainTex",
|
||||
"albedoTexture",
|
||||
"mainTexture",
|
||||
"texture"
|
||||
};
|
||||
|
||||
for (const char* textureName : kTextureNames) {
|
||||
const Resources::ResourceHandle<Resources::Texture> textureHandle =
|
||||
material->GetTexture(Containers::String(textureName));
|
||||
if (textureHandle.Get() != nullptr && textureHandle->IsValid()) {
|
||||
return textureHandle.Get();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline BuiltinForwardMaterialData BuildBuiltinForwardMaterialData(const Resources::Material* material) {
|
||||
BuiltinForwardMaterialData data = {};
|
||||
data.baseColorFactor = ResolveBuiltinBaseColorFactor(material);
|
||||
return data;
|
||||
}
|
||||
|
||||
inline MaterialConstantPayloadView ResolveSchemaMaterialConstantPayload(const Resources::Material* material) {
|
||||
if (material == nullptr || material->GetShader() == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const Containers::Array<Resources::MaterialConstantFieldDesc>& constantLayout = material->GetConstantLayout();
|
||||
const Containers::Array<Core::uint8>& constantBufferData = material->GetConstantBufferData();
|
||||
if (constantLayout.Empty() || constantBufferData.Empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
MaterialConstantLayoutView layoutView = {};
|
||||
layoutView.fields = constantLayout.Data();
|
||||
layoutView.count = constantLayout.Size();
|
||||
layoutView.size = constantBufferData.Size();
|
||||
|
||||
return { constantBufferData.Data(), constantBufferData.Size(), layoutView };
|
||||
}
|
||||
|
||||
inline const Resources::Material* ResolveMaterial(
|
||||
const Components::MeshRendererComponent* meshRenderer,
|
||||
const Resources::Mesh* mesh,
|
||||
Core::uint32 materialIndex) {
|
||||
if (meshRenderer != nullptr && materialIndex < meshRenderer->GetMaterialCount()) {
|
||||
if (const Resources::Material* material = meshRenderer->GetMaterial(materialIndex)) {
|
||||
return material;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh != nullptr && materialIndex < mesh->GetMaterials().Size()) {
|
||||
if (const Resources::Material* material = mesh->GetMaterials()[materialIndex]) {
|
||||
return material;
|
||||
}
|
||||
}
|
||||
|
||||
if (meshRenderer != nullptr && meshRenderer->GetMaterialCount() > 0) {
|
||||
if (const Resources::Material* material = meshRenderer->GetMaterial(0)) {
|
||||
return material;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh != nullptr && mesh->GetMaterials().Size() > 0) {
|
||||
return mesh->GetMaterials()[0];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline const Resources::Material* ResolveMaterial(const VisibleRenderItem& visibleItem) {
|
||||
if (visibleItem.material != nullptr) {
|
||||
return visibleItem.material;
|
||||
}
|
||||
|
||||
return ResolveMaterial(visibleItem.meshRenderer, visibleItem.mesh, visibleItem.materialIndex);
|
||||
}
|
||||
|
||||
inline Core::int32 ResolveMaterialRenderQueue(const Resources::Material* material) {
|
||||
return material != nullptr
|
||||
? material->GetRenderQueue()
|
||||
: static_cast<Core::int32>(Resources::MaterialRenderQueue::Geometry);
|
||||
}
|
||||
|
||||
inline bool IsTransparentRenderQueue(Core::int32 renderQueue) {
|
||||
return renderQueue >= static_cast<Core::int32>(Resources::MaterialRenderQueue::Transparent);
|
||||
}
|
||||
|
||||
inline bool MatchesBuiltinPass(const Resources::Material* material, BuiltinMaterialPass pass) {
|
||||
if (material == nullptr) {
|
||||
return pass == BuiltinMaterialPass::ForwardLit;
|
||||
}
|
||||
|
||||
const Containers::String shaderPass = material->GetShaderPass();
|
||||
const Containers::String lightMode = material->GetTag("LightMode");
|
||||
const bool hasMaterialShaderPass = !NormalizeBuiltinPassMetadataValue(shaderPass).Empty();
|
||||
const bool hasMaterialLightMode = !NormalizeBuiltinPassMetadataValue(lightMode).Empty();
|
||||
if (hasMaterialShaderPass || hasMaterialLightMode) {
|
||||
if (hasMaterialShaderPass &&
|
||||
!MatchesBuiltinPassName(shaderPass, pass)) {
|
||||
return false;
|
||||
}
|
||||
if (hasMaterialLightMode &&
|
||||
!MatchesBuiltinPassName(lightMode, pass)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const Resources::Shader* shader = material->GetShader();
|
||||
if (shader != nullptr) {
|
||||
bool shaderHasExplicitBuiltinMetadata = false;
|
||||
for (const Resources::ShaderPass& shaderPassEntry : shader->GetPasses()) {
|
||||
if (ShaderPassMatchesBuiltinPass(shaderPassEntry, pass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ShaderPassHasExplicitBuiltinMetadata(shaderPassEntry)) {
|
||||
shaderHasExplicitBuiltinMetadata = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shaderHasExplicitBuiltinMetadata) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return pass == BuiltinMaterialPass::ForwardLit;
|
||||
}
|
||||
|
||||
} // namespace Rendering
|
||||
} // namespace XCEngine
|
||||
178
engine/include/XCEngine/Rendering/RenderMaterialStateUtils.h
Normal file
178
engine/include/XCEngine/Rendering/RenderMaterialStateUtils.h
Normal file
@@ -0,0 +1,178 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/RHI/RHITypes.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
|
||||
inline RHI::CullMode ToRHICullMode(Resources::MaterialCullMode mode) {
|
||||
switch (mode) {
|
||||
case Resources::MaterialCullMode::Front:
|
||||
return RHI::CullMode::Front;
|
||||
case Resources::MaterialCullMode::Back:
|
||||
return RHI::CullMode::Back;
|
||||
case Resources::MaterialCullMode::None:
|
||||
default:
|
||||
return RHI::CullMode::None;
|
||||
}
|
||||
}
|
||||
|
||||
inline RHI::ComparisonFunc ToRHIComparisonFunc(Resources::MaterialComparisonFunc func) {
|
||||
switch (func) {
|
||||
case Resources::MaterialComparisonFunc::Never:
|
||||
return RHI::ComparisonFunc::Never;
|
||||
case Resources::MaterialComparisonFunc::Equal:
|
||||
return RHI::ComparisonFunc::Equal;
|
||||
case Resources::MaterialComparisonFunc::LessEqual:
|
||||
return RHI::ComparisonFunc::LessEqual;
|
||||
case Resources::MaterialComparisonFunc::Greater:
|
||||
return RHI::ComparisonFunc::Greater;
|
||||
case Resources::MaterialComparisonFunc::NotEqual:
|
||||
return RHI::ComparisonFunc::NotEqual;
|
||||
case Resources::MaterialComparisonFunc::GreaterEqual:
|
||||
return RHI::ComparisonFunc::GreaterEqual;
|
||||
case Resources::MaterialComparisonFunc::Always:
|
||||
return RHI::ComparisonFunc::Always;
|
||||
case Resources::MaterialComparisonFunc::Less:
|
||||
default:
|
||||
return RHI::ComparisonFunc::Less;
|
||||
}
|
||||
}
|
||||
|
||||
inline RHI::BlendFactor ToRHIBlendFactor(Resources::MaterialBlendFactor factor) {
|
||||
switch (factor) {
|
||||
case Resources::MaterialBlendFactor::Zero:
|
||||
return RHI::BlendFactor::Zero;
|
||||
case Resources::MaterialBlendFactor::SrcColor:
|
||||
return RHI::BlendFactor::SrcColor;
|
||||
case Resources::MaterialBlendFactor::InvSrcColor:
|
||||
return RHI::BlendFactor::InvSrcColor;
|
||||
case Resources::MaterialBlendFactor::SrcAlpha:
|
||||
return RHI::BlendFactor::SrcAlpha;
|
||||
case Resources::MaterialBlendFactor::InvSrcAlpha:
|
||||
return RHI::BlendFactor::InvSrcAlpha;
|
||||
case Resources::MaterialBlendFactor::DstAlpha:
|
||||
return RHI::BlendFactor::DstAlpha;
|
||||
case Resources::MaterialBlendFactor::InvDstAlpha:
|
||||
return RHI::BlendFactor::InvDstAlpha;
|
||||
case Resources::MaterialBlendFactor::DstColor:
|
||||
return RHI::BlendFactor::DstColor;
|
||||
case Resources::MaterialBlendFactor::InvDstColor:
|
||||
return RHI::BlendFactor::InvDstColor;
|
||||
case Resources::MaterialBlendFactor::SrcAlphaSat:
|
||||
return RHI::BlendFactor::SrcAlphaSat;
|
||||
case Resources::MaterialBlendFactor::BlendFactor:
|
||||
return RHI::BlendFactor::BlendFactor;
|
||||
case Resources::MaterialBlendFactor::InvBlendFactor:
|
||||
return RHI::BlendFactor::InvBlendFactor;
|
||||
case Resources::MaterialBlendFactor::Src1Color:
|
||||
return RHI::BlendFactor::Src1Color;
|
||||
case Resources::MaterialBlendFactor::InvSrc1Color:
|
||||
return RHI::BlendFactor::InvSrc1Color;
|
||||
case Resources::MaterialBlendFactor::Src1Alpha:
|
||||
return RHI::BlendFactor::Src1Alpha;
|
||||
case Resources::MaterialBlendFactor::InvSrc1Alpha:
|
||||
return RHI::BlendFactor::InvSrc1Alpha;
|
||||
case Resources::MaterialBlendFactor::One:
|
||||
default:
|
||||
return RHI::BlendFactor::One;
|
||||
}
|
||||
}
|
||||
|
||||
inline RHI::BlendOp ToRHIBlendOp(Resources::MaterialBlendOp op) {
|
||||
switch (op) {
|
||||
case Resources::MaterialBlendOp::Subtract:
|
||||
return RHI::BlendOp::Subtract;
|
||||
case Resources::MaterialBlendOp::ReverseSubtract:
|
||||
return RHI::BlendOp::ReverseSubtract;
|
||||
case Resources::MaterialBlendOp::Min:
|
||||
return RHI::BlendOp::Min;
|
||||
case Resources::MaterialBlendOp::Max:
|
||||
return RHI::BlendOp::Max;
|
||||
case Resources::MaterialBlendOp::Add:
|
||||
default:
|
||||
return RHI::BlendOp::Add;
|
||||
}
|
||||
}
|
||||
|
||||
inline RHI::RasterizerDesc BuildRasterizerState(const Resources::Material* material) {
|
||||
RHI::RasterizerDesc desc = {};
|
||||
desc.fillMode = static_cast<uint32_t>(RHI::FillMode::Solid);
|
||||
desc.cullMode = static_cast<uint32_t>(RHI::CullMode::None);
|
||||
desc.frontFace = static_cast<uint32_t>(RHI::FrontFace::CounterClockwise);
|
||||
desc.depthClipEnable = true;
|
||||
|
||||
if (material != nullptr) {
|
||||
const Resources::MaterialRenderState& renderState = material->GetRenderState();
|
||||
desc.cullMode = static_cast<uint32_t>(ToRHICullMode(renderState.cullMode));
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
inline RHI::BlendDesc BuildBlendState(const Resources::Material* material) {
|
||||
RHI::BlendDesc desc = {};
|
||||
if (material != nullptr) {
|
||||
const Resources::MaterialRenderState& renderState = material->GetRenderState();
|
||||
desc.blendEnable = renderState.blendEnable;
|
||||
desc.srcBlend = static_cast<uint32_t>(ToRHIBlendFactor(renderState.srcBlend));
|
||||
desc.dstBlend = static_cast<uint32_t>(ToRHIBlendFactor(renderState.dstBlend));
|
||||
desc.srcBlendAlpha = static_cast<uint32_t>(ToRHIBlendFactor(renderState.srcBlendAlpha));
|
||||
desc.dstBlendAlpha = static_cast<uint32_t>(ToRHIBlendFactor(renderState.dstBlendAlpha));
|
||||
desc.blendOp = static_cast<uint32_t>(ToRHIBlendOp(renderState.blendOp));
|
||||
desc.blendOpAlpha = static_cast<uint32_t>(ToRHIBlendOp(renderState.blendOpAlpha));
|
||||
desc.colorWriteMask = renderState.colorWriteMask;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
inline RHI::DepthStencilStateDesc BuildDepthStencilState(const Resources::Material* material) {
|
||||
RHI::DepthStencilStateDesc desc = {};
|
||||
desc.depthTestEnable = true;
|
||||
desc.depthWriteEnable = true;
|
||||
desc.depthFunc = static_cast<uint32_t>(RHI::ComparisonFunc::Less);
|
||||
desc.stencilEnable = false;
|
||||
|
||||
if (material != nullptr) {
|
||||
const Resources::MaterialRenderState& renderState = material->GetRenderState();
|
||||
desc.depthTestEnable = renderState.depthTestEnable;
|
||||
desc.depthWriteEnable = renderState.depthWriteEnable;
|
||||
desc.depthFunc = static_cast<uint32_t>(ToRHIComparisonFunc(renderState.depthFunc));
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
inline void ApplyMaterialRenderState(const Resources::Material* material, RHI::GraphicsPipelineDesc& pipelineDesc) {
|
||||
pipelineDesc.rasterizerState = BuildRasterizerState(material);
|
||||
pipelineDesc.blendState = BuildBlendState(material);
|
||||
pipelineDesc.depthStencilState = BuildDepthStencilState(material);
|
||||
}
|
||||
|
||||
struct MaterialRenderStateHash {
|
||||
size_t operator()(const Resources::MaterialRenderState& state) const noexcept {
|
||||
size_t hash = 2166136261u;
|
||||
auto combine = [&hash](size_t value) {
|
||||
hash ^= value + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
};
|
||||
|
||||
combine(static_cast<size_t>(state.blendEnable));
|
||||
combine(static_cast<size_t>(state.srcBlend));
|
||||
combine(static_cast<size_t>(state.dstBlend));
|
||||
combine(static_cast<size_t>(state.srcBlendAlpha));
|
||||
combine(static_cast<size_t>(state.dstBlendAlpha));
|
||||
combine(static_cast<size_t>(state.blendOp));
|
||||
combine(static_cast<size_t>(state.blendOpAlpha));
|
||||
combine(static_cast<size_t>(state.colorWriteMask));
|
||||
combine(static_cast<size_t>(state.depthTestEnable));
|
||||
combine(static_cast<size_t>(state.depthWriteEnable));
|
||||
combine(static_cast<size_t>(state.depthFunc));
|
||||
combine(static_cast<size_t>(state.cullMode));
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
} // namespace XCEngine
|
||||
@@ -1,419 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Components/MeshRendererComponent.h>
|
||||
#include <XCEngine/Core/Types.h>
|
||||
#include <XCEngine/RHI/RHITypes.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||
#include <XCEngine/Rendering/BuiltinPassContract.h>
|
||||
#include <XCEngine/Rendering/VisibleRenderItem.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
|
||||
struct BuiltinForwardMaterialData {
|
||||
Math::Vector4 baseColorFactor = Math::Vector4::One();
|
||||
};
|
||||
|
||||
struct MaterialConstantLayoutView {
|
||||
const Resources::MaterialConstantFieldDesc* fields = nullptr;
|
||||
size_t count = 0;
|
||||
size_t size = 0;
|
||||
|
||||
bool IsValid() const {
|
||||
return fields != nullptr && count > 0 && size > 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct MaterialConstantPayloadView {
|
||||
const void* data = nullptr;
|
||||
size_t size = 0;
|
||||
MaterialConstantLayoutView layout = {};
|
||||
|
||||
bool IsValid() const {
|
||||
return data != nullptr && size > 0 && layout.IsValid() && layout.size == size;
|
||||
}
|
||||
};
|
||||
|
||||
inline const Resources::ShaderPropertyDesc* FindShaderPropertyBySemantic(
|
||||
const Resources::Material* material,
|
||||
const Containers::String& semantic) {
|
||||
if (material == nullptr || material->GetShader() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Containers::String normalizedSemantic = NormalizeBuiltinPassMetadataValue(semantic);
|
||||
for (const Resources::ShaderPropertyDesc& property : material->GetShader()->GetProperties()) {
|
||||
if (NormalizeBuiltinPassMetadataValue(property.semantic) == normalizedSemantic) {
|
||||
return &property;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline Math::Vector4 ResolveBuiltinBaseColorFactor(const Resources::Material* material) {
|
||||
if (material == nullptr) {
|
||||
return Math::Vector4::One();
|
||||
}
|
||||
|
||||
if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "BaseColor")) {
|
||||
if (material->HasProperty(property->name) &&
|
||||
(property->type == Resources::ShaderPropertyType::Color ||
|
||||
property->type == Resources::ShaderPropertyType::Vector)) {
|
||||
return material->GetFloat4(property->name);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* kBaseColorPropertyNames[] = {
|
||||
"baseColor",
|
||||
"_BaseColor",
|
||||
"color",
|
||||
"_Color"
|
||||
};
|
||||
|
||||
for (const char* propertyName : kBaseColorPropertyNames) {
|
||||
if (material->HasProperty(Containers::String(propertyName))) {
|
||||
return material->GetFloat4(Containers::String(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
Math::Vector4 baseColor = Math::Vector4::One();
|
||||
static const char* kOpacityPropertyNames[] = {
|
||||
"opacity",
|
||||
"_Opacity",
|
||||
"alpha",
|
||||
"_Alpha"
|
||||
};
|
||||
for (const char* propertyName : kOpacityPropertyNames) {
|
||||
if (material->HasProperty(Containers::String(propertyName))) {
|
||||
baseColor.w = material->GetFloat(Containers::String(propertyName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
inline const Resources::Texture* ResolveBuiltinBaseColorTexture(const Resources::Material* material) {
|
||||
if (material == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "BaseColorTexture")) {
|
||||
const Resources::ResourceHandle<Resources::Texture> textureHandle = material->GetTexture(property->name);
|
||||
if (textureHandle.Get() != nullptr && textureHandle->IsValid()) {
|
||||
return textureHandle.Get();
|
||||
}
|
||||
}
|
||||
|
||||
static const char* kTextureNames[] = {
|
||||
"baseColorTexture",
|
||||
"_BaseColorTexture",
|
||||
"_MainTex",
|
||||
"albedoTexture",
|
||||
"mainTexture",
|
||||
"texture"
|
||||
};
|
||||
|
||||
for (const char* textureName : kTextureNames) {
|
||||
const Resources::ResourceHandle<Resources::Texture> textureHandle =
|
||||
material->GetTexture(Containers::String(textureName));
|
||||
if (textureHandle.Get() != nullptr && textureHandle->IsValid()) {
|
||||
return textureHandle.Get();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline BuiltinForwardMaterialData BuildBuiltinForwardMaterialData(const Resources::Material* material) {
|
||||
BuiltinForwardMaterialData data = {};
|
||||
data.baseColorFactor = ResolveBuiltinBaseColorFactor(material);
|
||||
return data;
|
||||
}
|
||||
|
||||
inline MaterialConstantPayloadView ResolveSchemaMaterialConstantPayload(const Resources::Material* material) {
|
||||
if (material == nullptr || material->GetShader() == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const Containers::Array<Resources::MaterialConstantFieldDesc>& constantLayout = material->GetConstantLayout();
|
||||
const Containers::Array<Core::uint8>& constantBufferData = material->GetConstantBufferData();
|
||||
if (constantLayout.Empty() || constantBufferData.Empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
MaterialConstantLayoutView layoutView = {};
|
||||
layoutView.fields = constantLayout.Data();
|
||||
layoutView.count = constantLayout.Size();
|
||||
layoutView.size = constantBufferData.Size();
|
||||
|
||||
return { constantBufferData.Data(), constantBufferData.Size(), layoutView };
|
||||
}
|
||||
|
||||
inline const Resources::Material* ResolveMaterial(
|
||||
const Components::MeshRendererComponent* meshRenderer,
|
||||
const Resources::Mesh* mesh,
|
||||
Core::uint32 materialIndex) {
|
||||
if (meshRenderer != nullptr && materialIndex < meshRenderer->GetMaterialCount()) {
|
||||
if (const Resources::Material* material = meshRenderer->GetMaterial(materialIndex)) {
|
||||
return material;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh != nullptr && materialIndex < mesh->GetMaterials().Size()) {
|
||||
if (const Resources::Material* material = mesh->GetMaterials()[materialIndex]) {
|
||||
return material;
|
||||
}
|
||||
}
|
||||
|
||||
if (meshRenderer != nullptr && meshRenderer->GetMaterialCount() > 0) {
|
||||
if (const Resources::Material* material = meshRenderer->GetMaterial(0)) {
|
||||
return material;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh != nullptr && mesh->GetMaterials().Size() > 0) {
|
||||
return mesh->GetMaterials()[0];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline const Resources::Material* ResolveMaterial(const VisibleRenderItem& visibleItem) {
|
||||
if (visibleItem.material != nullptr) {
|
||||
return visibleItem.material;
|
||||
}
|
||||
|
||||
return ResolveMaterial(visibleItem.meshRenderer, visibleItem.mesh, visibleItem.materialIndex);
|
||||
}
|
||||
|
||||
inline Core::int32 ResolveMaterialRenderQueue(const Resources::Material* material) {
|
||||
return material != nullptr
|
||||
? material->GetRenderQueue()
|
||||
: static_cast<Core::int32>(Resources::MaterialRenderQueue::Geometry);
|
||||
}
|
||||
|
||||
inline bool IsTransparentRenderQueue(Core::int32 renderQueue) {
|
||||
return renderQueue >= static_cast<Core::int32>(Resources::MaterialRenderQueue::Transparent);
|
||||
}
|
||||
|
||||
inline bool MatchesBuiltinPass(const Resources::Material* material, BuiltinMaterialPass pass) {
|
||||
if (material == nullptr) {
|
||||
return pass == BuiltinMaterialPass::ForwardLit;
|
||||
}
|
||||
|
||||
const Containers::String shaderPass = material->GetShaderPass();
|
||||
const Containers::String lightMode = material->GetTag("LightMode");
|
||||
const bool hasMaterialShaderPass = !NormalizeBuiltinPassMetadataValue(shaderPass).Empty();
|
||||
const bool hasMaterialLightMode = !NormalizeBuiltinPassMetadataValue(lightMode).Empty();
|
||||
if (hasMaterialShaderPass || hasMaterialLightMode) {
|
||||
if (hasMaterialShaderPass &&
|
||||
!MatchesBuiltinPassName(shaderPass, pass)) {
|
||||
return false;
|
||||
}
|
||||
if (hasMaterialLightMode &&
|
||||
!MatchesBuiltinPassName(lightMode, pass)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const Resources::Shader* shader = material->GetShader();
|
||||
if (shader != nullptr) {
|
||||
bool shaderHasExplicitBuiltinMetadata = false;
|
||||
for (const Resources::ShaderPass& shaderPassEntry : shader->GetPasses()) {
|
||||
if (ShaderPassMatchesBuiltinPass(shaderPassEntry, pass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ShaderPassHasExplicitBuiltinMetadata(shaderPassEntry)) {
|
||||
shaderHasExplicitBuiltinMetadata = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shaderHasExplicitBuiltinMetadata) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return pass == BuiltinMaterialPass::ForwardLit;
|
||||
}
|
||||
|
||||
inline RHI::CullMode ToRHICullMode(Resources::MaterialCullMode mode) {
|
||||
switch (mode) {
|
||||
case Resources::MaterialCullMode::Front:
|
||||
return RHI::CullMode::Front;
|
||||
case Resources::MaterialCullMode::Back:
|
||||
return RHI::CullMode::Back;
|
||||
case Resources::MaterialCullMode::None:
|
||||
default:
|
||||
return RHI::CullMode::None;
|
||||
}
|
||||
}
|
||||
|
||||
inline RHI::ComparisonFunc ToRHIComparisonFunc(Resources::MaterialComparisonFunc func) {
|
||||
switch (func) {
|
||||
case Resources::MaterialComparisonFunc::Never:
|
||||
return RHI::ComparisonFunc::Never;
|
||||
case Resources::MaterialComparisonFunc::Equal:
|
||||
return RHI::ComparisonFunc::Equal;
|
||||
case Resources::MaterialComparisonFunc::LessEqual:
|
||||
return RHI::ComparisonFunc::LessEqual;
|
||||
case Resources::MaterialComparisonFunc::Greater:
|
||||
return RHI::ComparisonFunc::Greater;
|
||||
case Resources::MaterialComparisonFunc::NotEqual:
|
||||
return RHI::ComparisonFunc::NotEqual;
|
||||
case Resources::MaterialComparisonFunc::GreaterEqual:
|
||||
return RHI::ComparisonFunc::GreaterEqual;
|
||||
case Resources::MaterialComparisonFunc::Always:
|
||||
return RHI::ComparisonFunc::Always;
|
||||
case Resources::MaterialComparisonFunc::Less:
|
||||
default:
|
||||
return RHI::ComparisonFunc::Less;
|
||||
}
|
||||
}
|
||||
|
||||
inline RHI::BlendFactor ToRHIBlendFactor(Resources::MaterialBlendFactor factor) {
|
||||
switch (factor) {
|
||||
case Resources::MaterialBlendFactor::Zero:
|
||||
return RHI::BlendFactor::Zero;
|
||||
case Resources::MaterialBlendFactor::SrcColor:
|
||||
return RHI::BlendFactor::SrcColor;
|
||||
case Resources::MaterialBlendFactor::InvSrcColor:
|
||||
return RHI::BlendFactor::InvSrcColor;
|
||||
case Resources::MaterialBlendFactor::SrcAlpha:
|
||||
return RHI::BlendFactor::SrcAlpha;
|
||||
case Resources::MaterialBlendFactor::InvSrcAlpha:
|
||||
return RHI::BlendFactor::InvSrcAlpha;
|
||||
case Resources::MaterialBlendFactor::DstAlpha:
|
||||
return RHI::BlendFactor::DstAlpha;
|
||||
case Resources::MaterialBlendFactor::InvDstAlpha:
|
||||
return RHI::BlendFactor::InvDstAlpha;
|
||||
case Resources::MaterialBlendFactor::DstColor:
|
||||
return RHI::BlendFactor::DstColor;
|
||||
case Resources::MaterialBlendFactor::InvDstColor:
|
||||
return RHI::BlendFactor::InvDstColor;
|
||||
case Resources::MaterialBlendFactor::SrcAlphaSat:
|
||||
return RHI::BlendFactor::SrcAlphaSat;
|
||||
case Resources::MaterialBlendFactor::BlendFactor:
|
||||
return RHI::BlendFactor::BlendFactor;
|
||||
case Resources::MaterialBlendFactor::InvBlendFactor:
|
||||
return RHI::BlendFactor::InvBlendFactor;
|
||||
case Resources::MaterialBlendFactor::Src1Color:
|
||||
return RHI::BlendFactor::Src1Color;
|
||||
case Resources::MaterialBlendFactor::InvSrc1Color:
|
||||
return RHI::BlendFactor::InvSrc1Color;
|
||||
case Resources::MaterialBlendFactor::Src1Alpha:
|
||||
return RHI::BlendFactor::Src1Alpha;
|
||||
case Resources::MaterialBlendFactor::InvSrc1Alpha:
|
||||
return RHI::BlendFactor::InvSrc1Alpha;
|
||||
case Resources::MaterialBlendFactor::One:
|
||||
default:
|
||||
return RHI::BlendFactor::One;
|
||||
}
|
||||
}
|
||||
|
||||
inline RHI::BlendOp ToRHIBlendOp(Resources::MaterialBlendOp op) {
|
||||
switch (op) {
|
||||
case Resources::MaterialBlendOp::Subtract:
|
||||
return RHI::BlendOp::Subtract;
|
||||
case Resources::MaterialBlendOp::ReverseSubtract:
|
||||
return RHI::BlendOp::ReverseSubtract;
|
||||
case Resources::MaterialBlendOp::Min:
|
||||
return RHI::BlendOp::Min;
|
||||
case Resources::MaterialBlendOp::Max:
|
||||
return RHI::BlendOp::Max;
|
||||
case Resources::MaterialBlendOp::Add:
|
||||
default:
|
||||
return RHI::BlendOp::Add;
|
||||
}
|
||||
}
|
||||
|
||||
inline RHI::RasterizerDesc BuildRasterizerState(const Resources::Material* material) {
|
||||
RHI::RasterizerDesc desc = {};
|
||||
desc.fillMode = static_cast<uint32_t>(RHI::FillMode::Solid);
|
||||
desc.cullMode = static_cast<uint32_t>(RHI::CullMode::None);
|
||||
desc.frontFace = static_cast<uint32_t>(RHI::FrontFace::CounterClockwise);
|
||||
desc.depthClipEnable = true;
|
||||
|
||||
if (material != nullptr) {
|
||||
const Resources::MaterialRenderState& renderState = material->GetRenderState();
|
||||
desc.cullMode = static_cast<uint32_t>(ToRHICullMode(renderState.cullMode));
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
inline RHI::BlendDesc BuildBlendState(const Resources::Material* material) {
|
||||
RHI::BlendDesc desc = {};
|
||||
if (material != nullptr) {
|
||||
const Resources::MaterialRenderState& renderState = material->GetRenderState();
|
||||
desc.blendEnable = renderState.blendEnable;
|
||||
desc.srcBlend = static_cast<uint32_t>(ToRHIBlendFactor(renderState.srcBlend));
|
||||
desc.dstBlend = static_cast<uint32_t>(ToRHIBlendFactor(renderState.dstBlend));
|
||||
desc.srcBlendAlpha = static_cast<uint32_t>(ToRHIBlendFactor(renderState.srcBlendAlpha));
|
||||
desc.dstBlendAlpha = static_cast<uint32_t>(ToRHIBlendFactor(renderState.dstBlendAlpha));
|
||||
desc.blendOp = static_cast<uint32_t>(ToRHIBlendOp(renderState.blendOp));
|
||||
desc.blendOpAlpha = static_cast<uint32_t>(ToRHIBlendOp(renderState.blendOpAlpha));
|
||||
desc.colorWriteMask = renderState.colorWriteMask;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
inline RHI::DepthStencilStateDesc BuildDepthStencilState(const Resources::Material* material) {
|
||||
RHI::DepthStencilStateDesc desc = {};
|
||||
desc.depthTestEnable = true;
|
||||
desc.depthWriteEnable = true;
|
||||
desc.depthFunc = static_cast<uint32_t>(RHI::ComparisonFunc::Less);
|
||||
desc.stencilEnable = false;
|
||||
|
||||
if (material != nullptr) {
|
||||
const Resources::MaterialRenderState& renderState = material->GetRenderState();
|
||||
desc.depthTestEnable = renderState.depthTestEnable;
|
||||
desc.depthWriteEnable = renderState.depthWriteEnable;
|
||||
desc.depthFunc = static_cast<uint32_t>(ToRHIComparisonFunc(renderState.depthFunc));
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
inline void ApplyMaterialRenderState(const Resources::Material* material, RHI::GraphicsPipelineDesc& pipelineDesc) {
|
||||
pipelineDesc.rasterizerState = BuildRasterizerState(material);
|
||||
pipelineDesc.blendState = BuildBlendState(material);
|
||||
pipelineDesc.depthStencilState = BuildDepthStencilState(material);
|
||||
}
|
||||
|
||||
struct MaterialRenderStateHash {
|
||||
size_t operator()(const Resources::MaterialRenderState& state) const noexcept {
|
||||
size_t hash = 2166136261u;
|
||||
auto combine = [&hash](size_t value) {
|
||||
hash ^= value + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
};
|
||||
|
||||
combine(static_cast<size_t>(state.blendEnable));
|
||||
combine(static_cast<size_t>(state.srcBlend));
|
||||
combine(static_cast<size_t>(state.dstBlend));
|
||||
combine(static_cast<size_t>(state.srcBlendAlpha));
|
||||
combine(static_cast<size_t>(state.dstBlendAlpha));
|
||||
combine(static_cast<size_t>(state.blendOp));
|
||||
combine(static_cast<size_t>(state.blendOpAlpha));
|
||||
combine(static_cast<size_t>(state.colorWriteMask));
|
||||
combine(static_cast<size_t>(state.depthTestEnable));
|
||||
combine(static_cast<size_t>(state.depthWriteEnable));
|
||||
combine(static_cast<size_t>(state.depthFunc));
|
||||
combine(static_cast<size_t>(state.cullMode));
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
} // namespace XCEngine
|
||||
#include <XCEngine/Rendering/RenderMaterialResolve.h>
|
||||
#include <XCEngine/Rendering/RenderMaterialStateUtils.h>
|
||||
|
||||
Reference in New Issue
Block a user