rendering: add builtin alpha-test pass support
This commit is contained in:
@@ -1,7 +1,20 @@
|
||||
// XC_BUILTIN_DEPTH_ONLY_OPENGL_PS
|
||||
#version 430
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(binding = 0) uniform sampler2D uBaseColorTexture;
|
||||
|
||||
layout(std140, binding = 1) uniform MaterialConstants {
|
||||
vec4 gBaseColorFactor;
|
||||
vec4 gAlphaCutoffParams;
|
||||
};
|
||||
|
||||
in vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
fragColor = vec4(0.0);
|
||||
#ifdef XC_ALPHA_TEST
|
||||
vec4 baseColor = texture(uBaseColorTexture, vTexCoord) * gBaseColorFactor;
|
||||
if (baseColor.a < gAlphaCutoffParams.x) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
// XC_BUILTIN_DEPTH_ONLY_VULKAN_PS
|
||||
#version 450
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(set = 2, binding = 0) uniform texture2D uBaseColorTexture;
|
||||
layout(set = 3, binding = 0) uniform sampler uLinearSampler;
|
||||
|
||||
layout(set = 1, binding = 0, std140) uniform MaterialConstants {
|
||||
vec4 gBaseColorFactor;
|
||||
vec4 gAlphaCutoffParams;
|
||||
};
|
||||
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
fragColor = vec4(0.0);
|
||||
#ifdef XC_ALPHA_TEST
|
||||
vec4 baseColor = texture(sampler2D(uBaseColorTexture, uLinearSampler), vTexCoord) * gBaseColorFactor;
|
||||
if (baseColor.a < gAlphaCutoffParams.x) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
// XC_BUILTIN_DEPTH_ONLY_D3D12_PS
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION;
|
||||
Texture2D gBaseColorTexture : register(t0);
|
||||
SamplerState gLinearSampler : register(s0);
|
||||
|
||||
cbuffer MaterialConstants : register(b1) {
|
||||
float4 gBaseColorFactor;
|
||||
float4 gAlphaCutoffParams;
|
||||
};
|
||||
|
||||
float4 MainPS(PSInput input) : SV_TARGET {
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
void MainPS(PSInput input) {
|
||||
#ifdef XC_ALPHA_TEST
|
||||
float4 baseColor = gBaseColorTexture.Sample(gLinearSampler, input.texcoord) * gBaseColorFactor;
|
||||
clip(baseColor.a - gAlphaCutoffParams.x);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
Shader "Builtin Depth Only"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_BaseColor ("Base Color", Color) = (1,1,1,1) [Semantic(BaseColor)]
|
||||
_Cutoff ("Alpha Cutoff", Range) = 0.5 [Semantic(AlphaCutoff)]
|
||||
_MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)]
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Pass
|
||||
@@ -9,10 +15,14 @@ Shader "Builtin Depth Only"
|
||||
Resources
|
||||
{
|
||||
PerObjectConstants (ConstantBuffer, 0, 0) [Semantic(PerObject)]
|
||||
MaterialConstants (ConstantBuffer, 1, 0) [Semantic(Material)]
|
||||
BaseColorTexture (Texture2D, 2, 0) [Semantic(BaseColorTexture)]
|
||||
LinearClampSampler (Sampler, 3, 0) [Semantic(LinearClampSampler)]
|
||||
}
|
||||
HLSLPROGRAM
|
||||
#pragma vertex MainVS
|
||||
#pragma fragment MainPS
|
||||
#pragma shader_feature_local _ XC_ALPHA_TEST
|
||||
#pragma backend D3D12 HLSL "depth-only.vs.hlsl" "depth-only.ps.hlsl" vs_5_0 ps_5_0
|
||||
#pragma backend OpenGL GLSL "depth-only.vert.glsl" "depth-only.frag.glsl"
|
||||
#pragma backend Vulkan GLSL "depth-only.vert.vk.glsl" "depth-only.frag.vk.glsl"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// XC_BUILTIN_DEPTH_ONLY_OPENGL_VS
|
||||
#version 430
|
||||
layout(location = 0) in vec3 aPosition;
|
||||
layout(location = 2) in vec2 aTexCoord;
|
||||
|
||||
layout(std140, binding = 0) uniform PerObjectConstants {
|
||||
mat4 gProjectionMatrix;
|
||||
@@ -8,8 +9,11 @@ layout(std140, binding = 0) uniform PerObjectConstants {
|
||||
mat4 gModelMatrix;
|
||||
};
|
||||
|
||||
out vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0);
|
||||
vec4 positionVS = gViewMatrix * positionWS;
|
||||
gl_Position = gProjectionMatrix * positionVS;
|
||||
vTexCoord = aTexCoord;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// XC_BUILTIN_DEPTH_ONLY_VULKAN_VS
|
||||
#version 450
|
||||
layout(location = 0) in vec3 aPosition;
|
||||
layout(location = 2) in vec2 aTexCoord;
|
||||
|
||||
layout(set = 0, binding = 0, std140) uniform PerObjectConstants {
|
||||
mat4 gProjectionMatrix;
|
||||
@@ -8,8 +9,11 @@ layout(set = 0, binding = 0, std140) uniform PerObjectConstants {
|
||||
mat4 gModelMatrix;
|
||||
};
|
||||
|
||||
layout(location = 0) out vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0);
|
||||
vec4 positionVS = gViewMatrix * positionWS;
|
||||
gl_Position = gProjectionMatrix * positionVS;
|
||||
vTexCoord = aTexCoord;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,12 @@ cbuffer PerObjectConstants : register(b0) {
|
||||
|
||||
struct VSInput {
|
||||
float3 position : POSITION;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
PSInput MainVS(VSInput input) {
|
||||
@@ -18,5 +20,6 @@ PSInput MainVS(VSInput input) {
|
||||
float4 positionWS = mul(gModelMatrix, float4(input.position, 1.0));
|
||||
float4 positionVS = mul(gViewMatrix, positionWS);
|
||||
output.position = mul(gProjectionMatrix, positionVS);
|
||||
output.texcoord = input.texcoord;
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ layout(std140, binding = 1) uniform LightingConstants {
|
||||
|
||||
layout(std140, binding = 2) uniform MaterialConstants {
|
||||
vec4 gBaseColorFactor;
|
||||
vec4 gAlphaCutoffParams;
|
||||
};
|
||||
|
||||
layout(std140, binding = 3) uniform ShadowReceiverConstants {
|
||||
@@ -137,6 +138,11 @@ vec3 EvaluateAdditionalLight(AdditionalLightData light, vec3 normalWS, vec3 posi
|
||||
|
||||
void main() {
|
||||
vec4 baseColor = texture(uBaseColorTexture, vTexCoord) * gBaseColorFactor;
|
||||
#ifdef XC_ALPHA_TEST
|
||||
if (baseColor.a < gAlphaCutoffParams.x) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
int additionalLightCount = min(int(gLightingParams.x + 0.5), XC_MAX_ADDITIONAL_LIGHTS);
|
||||
if (gMainLightColorAndFlags.w < 0.5 && additionalLightCount == 0) {
|
||||
fragColor = baseColor;
|
||||
|
||||
@@ -30,6 +30,7 @@ layout(set = 1, binding = 0, std140) uniform LightingConstants {
|
||||
|
||||
layout(set = 2, binding = 0, std140) uniform MaterialConstants {
|
||||
vec4 gBaseColorFactor;
|
||||
vec4 gAlphaCutoffParams;
|
||||
};
|
||||
|
||||
layout(set = 3, binding = 0, std140) uniform ShadowReceiverConstants {
|
||||
@@ -139,6 +140,11 @@ vec3 EvaluateAdditionalLight(AdditionalLightData light, vec3 normalWS, vec3 posi
|
||||
|
||||
void main() {
|
||||
vec4 baseColor = texture(sampler2D(uBaseColorTexture, uLinearSampler), vTexCoord) * gBaseColorFactor;
|
||||
#ifdef XC_ALPHA_TEST
|
||||
if (baseColor.a < gAlphaCutoffParams.x) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
int additionalLightCount = min(int(gLightingParams.x + 0.5), XC_MAX_ADDITIONAL_LIGHTS);
|
||||
if (gMainLightColorAndFlags.w < 0.5 && additionalLightCount == 0) {
|
||||
fragColor = baseColor;
|
||||
|
||||
@@ -29,6 +29,7 @@ cbuffer LightingConstants : register(b1) {
|
||||
|
||||
cbuffer MaterialConstants : register(b2) {
|
||||
float4 gBaseColorFactor;
|
||||
float4 gAlphaCutoffParams;
|
||||
};
|
||||
|
||||
cbuffer ShadowReceiverConstants : register(b3) {
|
||||
@@ -139,6 +140,9 @@ float3 EvaluateAdditionalLight(AdditionalLightData light, float3 normalWS, float
|
||||
|
||||
float4 MainPS(PSInput input) : SV_TARGET {
|
||||
float4 baseColor = gBaseColorTexture.Sample(gLinearSampler, input.texcoord) * gBaseColorFactor;
|
||||
#ifdef XC_ALPHA_TEST
|
||||
clip(baseColor.a - gAlphaCutoffParams.x);
|
||||
#endif
|
||||
const int additionalLightCount = min((int)gLightingParams.x, XC_MAX_ADDITIONAL_LIGHTS);
|
||||
if (gMainLightColorAndFlags.a < 0.5f && additionalLightCount == 0) {
|
||||
return baseColor;
|
||||
|
||||
@@ -3,6 +3,7 @@ Shader "Builtin Forward Lit"
|
||||
Properties
|
||||
{
|
||||
_BaseColor ("Base Color", Color) = (1,1,1,1) [Semantic(BaseColor)]
|
||||
_Cutoff ("Alpha Cutoff", Range) = 0.5 [Semantic(AlphaCutoff)]
|
||||
_MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)]
|
||||
}
|
||||
SubShader
|
||||
@@ -26,6 +27,7 @@ Shader "Builtin Forward Lit"
|
||||
#pragma vertex MainVS
|
||||
#pragma fragment MainPS
|
||||
#pragma multi_compile _ XC_MAIN_LIGHT_SHADOWS
|
||||
#pragma shader_feature_local _ XC_ALPHA_TEST
|
||||
#pragma backend D3D12 HLSL "forward-lit.vs.hlsl" "forward-lit.ps.hlsl" vs_5_0 ps_5_0
|
||||
#pragma backend OpenGL GLSL "forward-lit.vert.glsl" "forward-lit.frag.glsl"
|
||||
#pragma backend Vulkan GLSL "forward-lit.vert.vk.glsl" "forward-lit.frag.vk.glsl"
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
// XC_BUILTIN_SHADOW_CASTER_OPENGL_PS
|
||||
#version 430
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(binding = 0) uniform sampler2D uBaseColorTexture;
|
||||
|
||||
layout(std140, binding = 1) uniform MaterialConstants {
|
||||
vec4 gBaseColorFactor;
|
||||
vec4 gAlphaCutoffParams;
|
||||
};
|
||||
|
||||
in vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
fragColor = vec4(0.0);
|
||||
#ifdef XC_ALPHA_TEST
|
||||
vec4 baseColor = texture(uBaseColorTexture, vTexCoord) * gBaseColorFactor;
|
||||
if (baseColor.a < gAlphaCutoffParams.x) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
gl_FragDepth = gl_FragCoord.z;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,22 @@
|
||||
// XC_BUILTIN_SHADOW_CASTER_VULKAN_PS
|
||||
#version 450
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(set = 2, binding = 0) uniform texture2D uBaseColorTexture;
|
||||
layout(set = 3, binding = 0) uniform sampler uLinearSampler;
|
||||
|
||||
layout(set = 1, binding = 0, std140) uniform MaterialConstants {
|
||||
vec4 gBaseColorFactor;
|
||||
vec4 gAlphaCutoffParams;
|
||||
};
|
||||
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
fragColor = vec4(0.0);
|
||||
#ifdef XC_ALPHA_TEST
|
||||
vec4 baseColor = texture(sampler2D(uBaseColorTexture, uLinearSampler), vTexCoord) * gBaseColorFactor;
|
||||
if (baseColor.a < gAlphaCutoffParams.x) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
gl_FragDepth = gl_FragCoord.z;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
// XC_BUILTIN_SHADOW_CASTER_D3D12_PS
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION;
|
||||
Texture2D gBaseColorTexture : register(t0);
|
||||
SamplerState gLinearSampler : register(s0);
|
||||
|
||||
cbuffer MaterialConstants : register(b1) {
|
||||
float4 gBaseColorFactor;
|
||||
float4 gAlphaCutoffParams;
|
||||
};
|
||||
|
||||
float4 MainPS(PSInput input) : SV_TARGET {
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
float MainPS(PSInput input) : SV_Depth {
|
||||
#ifdef XC_ALPHA_TEST
|
||||
float4 baseColor = gBaseColorTexture.Sample(gLinearSampler, input.texcoord) * gBaseColorFactor;
|
||||
clip(baseColor.a - gAlphaCutoffParams.x);
|
||||
#endif
|
||||
return input.position.z;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
Shader "Builtin Shadow Caster"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_BaseColor ("Base Color", Color) = (1,1,1,1) [Semantic(BaseColor)]
|
||||
_Cutoff ("Alpha Cutoff", Range) = 0.5 [Semantic(AlphaCutoff)]
|
||||
_MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)]
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Pass
|
||||
@@ -9,10 +15,14 @@ Shader "Builtin Shadow Caster"
|
||||
Resources
|
||||
{
|
||||
PerObjectConstants (ConstantBuffer, 0, 0) [Semantic(PerObject)]
|
||||
MaterialConstants (ConstantBuffer, 1, 0) [Semantic(Material)]
|
||||
BaseColorTexture (Texture2D, 2, 0) [Semantic(BaseColorTexture)]
|
||||
LinearClampSampler (Sampler, 3, 0) [Semantic(LinearClampSampler)]
|
||||
}
|
||||
HLSLPROGRAM
|
||||
#pragma vertex MainVS
|
||||
#pragma fragment MainPS
|
||||
#pragma shader_feature_local _ XC_ALPHA_TEST
|
||||
#pragma backend D3D12 HLSL "shadow-caster.vs.hlsl" "shadow-caster.ps.hlsl" vs_5_0 ps_5_0
|
||||
#pragma backend OpenGL GLSL "shadow-caster.vert.glsl" "shadow-caster.frag.glsl"
|
||||
#pragma backend Vulkan GLSL "shadow-caster.vert.vk.glsl" "shadow-caster.frag.vk.glsl"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// XC_BUILTIN_SHADOW_CASTER_OPENGL_VS
|
||||
#version 430
|
||||
layout(location = 0) in vec3 aPosition;
|
||||
layout(location = 2) in vec2 aTexCoord;
|
||||
|
||||
layout(std140, binding = 0) uniform PerObjectConstants {
|
||||
mat4 gProjectionMatrix;
|
||||
@@ -8,8 +9,11 @@ layout(std140, binding = 0) uniform PerObjectConstants {
|
||||
mat4 gModelMatrix;
|
||||
};
|
||||
|
||||
out vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0);
|
||||
vec4 positionVS = gViewMatrix * positionWS;
|
||||
gl_Position = gProjectionMatrix * positionVS;
|
||||
vTexCoord = aTexCoord;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// XC_BUILTIN_SHADOW_CASTER_VULKAN_VS
|
||||
#version 450
|
||||
layout(location = 0) in vec3 aPosition;
|
||||
layout(location = 2) in vec2 aTexCoord;
|
||||
|
||||
layout(set = 0, binding = 0, std140) uniform PerObjectConstants {
|
||||
mat4 gProjectionMatrix;
|
||||
@@ -8,8 +9,11 @@ layout(set = 0, binding = 0, std140) uniform PerObjectConstants {
|
||||
mat4 gModelMatrix;
|
||||
};
|
||||
|
||||
layout(location = 0) out vec2 vTexCoord;
|
||||
|
||||
void main() {
|
||||
vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0);
|
||||
vec4 positionVS = gViewMatrix * positionWS;
|
||||
gl_Position = gProjectionMatrix * positionVS;
|
||||
vTexCoord = aTexCoord;
|
||||
}
|
||||
|
||||
@@ -7,16 +7,19 @@ cbuffer PerObjectConstants : register(b0) {
|
||||
|
||||
struct VSInput {
|
||||
float3 position : POSITION;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
PSInput MainVS(VSInput input) {
|
||||
PSInput output;
|
||||
float4 positionWS = mul(gModelMatrix, float4(input.position, 1.0));
|
||||
float4 positionWS = mul(gModelMatrix, float4(input.position, 1.0f));
|
||||
float4 positionVS = mul(gViewMatrix, positionWS);
|
||||
output.position = mul(gProjectionMatrix, positionVS);
|
||||
output.texcoord = input.texcoord;
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Rendering {
|
||||
|
||||
struct BuiltinForwardMaterialData {
|
||||
Math::Vector4 baseColorFactor = Math::Vector4::One();
|
||||
float alphaCutoff = 0.5f;
|
||||
};
|
||||
|
||||
enum class BuiltinSkyboxTextureMode : Core::uint8 {
|
||||
@@ -141,9 +142,39 @@ inline const Resources::Texture* ResolveBuiltinBaseColorTexture(const Resources:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline float ResolveBuiltinAlphaCutoff(const Resources::Material* material) {
|
||||
if (material == nullptr) {
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "AlphaCutoff")) {
|
||||
if (material->HasProperty(property->name) &&
|
||||
(property->type == Resources::ShaderPropertyType::Float ||
|
||||
property->type == Resources::ShaderPropertyType::Range)) {
|
||||
return material->GetFloat(property->name);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* kCutoffPropertyNames[] = {
|
||||
"_Cutoff",
|
||||
"cutoff",
|
||||
"_AlphaCutoff",
|
||||
"alphaCutoff"
|
||||
};
|
||||
|
||||
for (const char* propertyName : kCutoffPropertyNames) {
|
||||
if (material->HasProperty(Containers::String(propertyName))) {
|
||||
return material->GetFloat(Containers::String(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
inline BuiltinForwardMaterialData BuildBuiltinForwardMaterialData(const Resources::Material* material) {
|
||||
BuiltinForwardMaterialData data = {};
|
||||
data.baseColorFactor = ResolveBuiltinBaseColorFactor(material);
|
||||
data.alphaCutoff = ResolveBuiltinAlphaCutoff(material);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <XCEngine/Core/Asset/ResourceHandle.h>
|
||||
#include <XCEngine/Core/Math/Matrix4.h>
|
||||
#include <XCEngine/Rendering/Builtin/BuiltinPassTypes.h>
|
||||
#include <XCEngine/Rendering/Materials/RenderMaterialResolve.h>
|
||||
#include <XCEngine/Rendering/RenderPass.h>
|
||||
#include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h>
|
||||
#include <XCEngine/Rendering/Caches/RenderResourceCache.h>
|
||||
@@ -10,14 +11,19 @@
|
||||
#include <XCEngine/RHI/RHIDescriptorSet.h>
|
||||
#include <XCEngine/RHI/RHIPipelineLayout.h>
|
||||
#include <XCEngine/RHI/RHIPipelineState.h>
|
||||
#include <XCEngine/RHI/RHIResourceView.h>
|
||||
#include <XCEngine/RHI/RHISampler.h>
|
||||
#include <XCEngine/RHI/RHITexture.h>
|
||||
#include <XCEngine/Resources/Shader/Shader.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
class Material;
|
||||
class Shader;
|
||||
class Texture;
|
||||
} // namespace Resources
|
||||
|
||||
namespace Rendering {
|
||||
@@ -54,6 +60,11 @@ private:
|
||||
RHI::RHIDescriptorSet* set = nullptr;
|
||||
};
|
||||
|
||||
struct FallbackPerMaterialConstants {
|
||||
Math::Vector4 baseColorFactor = Math::Vector4::One();
|
||||
Math::Vector4 alphaCutoffParams = Math::Vector4(0.5f, 0.0f, 0.0f, 0.0f);
|
||||
};
|
||||
|
||||
struct PassLayoutKey {
|
||||
const Resources::Shader* shader = nullptr;
|
||||
Containers::String passName;
|
||||
@@ -73,29 +84,46 @@ private:
|
||||
|
||||
struct PassResourceLayout {
|
||||
RHI::RHIPipelineLayout* pipelineLayout = nullptr;
|
||||
PassResourceBindingLocation perObject = {};
|
||||
BuiltinPassSetLayoutMetadata perObjectSetLayout = {};
|
||||
Core::uint32 firstDescriptorSet = 0;
|
||||
Core::uint32 descriptorSetCount = 0;
|
||||
std::vector<BuiltinPassSetLayoutMetadata> setLayouts;
|
||||
std::vector<OwnedDescriptorSet> staticDescriptorSets;
|
||||
PassResourceBindingLocation perObject = {};
|
||||
PassResourceBindingLocation material = {};
|
||||
PassResourceBindingLocation baseColorTexture = {};
|
||||
PassResourceBindingLocation linearClampSampler = {};
|
||||
};
|
||||
|
||||
struct PerObjectSetKey {
|
||||
struct DynamicDescriptorSetKey {
|
||||
PassLayoutKey passLayout = {};
|
||||
Core::uint32 setIndex = 0;
|
||||
Core::uint64 objectId = 0;
|
||||
const Resources::Material* material = nullptr;
|
||||
|
||||
bool operator==(const PerObjectSetKey& other) const {
|
||||
bool operator==(const DynamicDescriptorSetKey& other) const {
|
||||
return passLayout == other.passLayout &&
|
||||
setIndex == other.setIndex &&
|
||||
material == other.material &&
|
||||
objectId == other.objectId;
|
||||
}
|
||||
};
|
||||
|
||||
struct PerObjectSetKeyHash {
|
||||
size_t operator()(const PerObjectSetKey& key) const noexcept {
|
||||
struct DynamicDescriptorSetKeyHash {
|
||||
size_t operator()(const DynamicDescriptorSetKey& key) const noexcept {
|
||||
size_t hash = PassLayoutKeyHash()(key.passLayout);
|
||||
hash ^= std::hash<Core::uint32>{}(key.setIndex) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
hash ^= std::hash<Core::uint64>{}(key.objectId) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
hash ^= reinterpret_cast<size_t>(key.material) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
struct CachedDescriptorSet {
|
||||
OwnedDescriptorSet descriptorSet = {};
|
||||
Core::uint64 materialVersion = 0;
|
||||
RHI::RHIResourceView* baseColorTextureView = nullptr;
|
||||
};
|
||||
|
||||
struct ResolvedShaderPass {
|
||||
const Resources::Shader* shader = nullptr;
|
||||
const Resources::ShaderPass* pass = nullptr;
|
||||
@@ -157,12 +185,23 @@ private:
|
||||
bool CreateOwnedDescriptorSet(
|
||||
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||
OwnedDescriptorSet& descriptorSet);
|
||||
RHI::RHIDescriptorSet* GetOrCreatePerObjectSet(
|
||||
RHI::RHIDescriptorSet* GetOrCreateStaticDescriptorSet(
|
||||
const PassLayoutKey& passLayoutKey,
|
||||
PassResourceLayout& passLayout,
|
||||
Core::uint32 setIndex);
|
||||
CachedDescriptorSet* GetOrCreateDynamicDescriptorSet(
|
||||
const PassLayoutKey& passLayoutKey,
|
||||
const PassResourceLayout& passLayout,
|
||||
Core::uint64 objectId);
|
||||
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||
Core::uint32 setIndex,
|
||||
Core::uint64 objectId,
|
||||
const Resources::Material* material,
|
||||
const MaterialConstantPayloadView& materialConstants,
|
||||
RHI::RHIResourceView* baseColorTextureView);
|
||||
void DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet);
|
||||
void DestroyPassResourceLayout(PassResourceLayout& passLayout);
|
||||
RHI::RHIResourceView* ResolveTextureView(const Resources::Texture* texture);
|
||||
RHI::RHIResourceView* ResolveTextureView(const VisibleRenderItem& visibleItem);
|
||||
bool DrawVisibleItem(
|
||||
const RenderContext& context,
|
||||
const RenderSurface& surface,
|
||||
@@ -178,7 +217,10 @@ private:
|
||||
|
||||
std::unordered_map<PassLayoutKey, PassResourceLayout, PassLayoutKeyHash> m_passResourceLayouts;
|
||||
std::unordered_map<PipelineStateKey, RHI::RHIPipelineState*, PipelineStateKeyHash> m_pipelineStates;
|
||||
std::unordered_map<PerObjectSetKey, OwnedDescriptorSet, PerObjectSetKeyHash> m_perObjectSets;
|
||||
std::unordered_map<DynamicDescriptorSetKey, CachedDescriptorSet, DynamicDescriptorSetKeyHash> m_dynamicDescriptorSets;
|
||||
RHI::RHISampler* m_sampler = nullptr;
|
||||
RHI::RHITexture* m_fallbackTexture2D = nullptr;
|
||||
RHI::RHIResourceView* m_fallbackTexture2DView = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Passes
|
||||
|
||||
@@ -98,6 +98,7 @@ private:
|
||||
|
||||
struct FallbackPerMaterialConstants {
|
||||
Math::Vector4 baseColorFactor = Math::Vector4::One();
|
||||
Math::Vector4 alphaCutoffParams = Math::Vector4(0.5f, 0.0f, 0.0f, 0.0f);
|
||||
};
|
||||
|
||||
struct SkyboxConstants {
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include "Rendering/RenderSurface.h"
|
||||
#include "Resources/Material/Material.h"
|
||||
#include "Resources/Mesh/Mesh.h"
|
||||
#include "Resources/Texture/Texture.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -37,6 +39,40 @@ bool IsSupportedPerObjectOnlyBindingPlan(const BuiltinPassResourceBindingPlan& b
|
||||
!bindingPlan.usesSamplers;
|
||||
}
|
||||
|
||||
bool UsesContiguousDescriptorSets(const BuiltinPassResourceBindingPlan& bindingPlan) {
|
||||
if (bindingPlan.bindings.Empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<bool> usedSets(static_cast<size_t>(bindingPlan.maxSetIndex) + 1u, false);
|
||||
Core::uint32 minSet = UINT32_MAX;
|
||||
Core::uint32 maxSet = 0;
|
||||
for (const BuiltinPassResourceBindingDesc& binding : bindingPlan.bindings) {
|
||||
usedSets[binding.location.set] = true;
|
||||
minSet = std::min(minSet, binding.location.set);
|
||||
maxSet = std::max(maxSet, binding.location.set);
|
||||
}
|
||||
|
||||
for (Core::uint32 setIndex = minSet; setIndex <= maxSet; ++setIndex) {
|
||||
if (!usedSets[setIndex]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsSupportedAlphaTestBindingPlan(const BuiltinPassResourceBindingPlan& bindingPlan) {
|
||||
return bindingPlan.perObject.IsValid() &&
|
||||
bindingPlan.material.IsValid() &&
|
||||
bindingPlan.baseColorTexture.IsValid() &&
|
||||
bindingPlan.linearClampSampler.IsValid() &&
|
||||
!bindingPlan.lighting.IsValid() &&
|
||||
!bindingPlan.shadowReceiver.IsValid() &&
|
||||
!bindingPlan.shadowMapTexture.IsValid() &&
|
||||
!bindingPlan.shadowMapSampler.IsValid();
|
||||
}
|
||||
|
||||
uint32_t ResolveSurfaceColorAttachmentCount(const RenderSurface& surface) {
|
||||
const std::vector<RHI::RHIResourceView*>& colorAttachments = surface.GetColorAttachments();
|
||||
return (!colorAttachments.empty() && colorAttachments[0] != nullptr) ? 1u : 0u;
|
||||
@@ -131,16 +167,66 @@ bool BuiltinDepthStylePassBase::CreateResources(const RenderContext& context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::SamplerDesc samplerDesc = {};
|
||||
samplerDesc.filter = static_cast<uint32_t>(RHI::FilterMode::Linear);
|
||||
samplerDesc.addressU = static_cast<uint32_t>(RHI::TextureAddressMode::Clamp);
|
||||
samplerDesc.addressV = static_cast<uint32_t>(RHI::TextureAddressMode::Clamp);
|
||||
samplerDesc.addressW = static_cast<uint32_t>(RHI::TextureAddressMode::Clamp);
|
||||
samplerDesc.mipLodBias = 0.0f;
|
||||
samplerDesc.maxAnisotropy = 1;
|
||||
samplerDesc.comparisonFunc = static_cast<uint32_t>(RHI::ComparisonFunc::Always);
|
||||
samplerDesc.minLod = 0.0f;
|
||||
samplerDesc.maxLod = 1000.0f;
|
||||
m_sampler = context.device->CreateSampler(samplerDesc);
|
||||
if (m_sampler == nullptr) {
|
||||
DestroyResources();
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char whitePixels2D[4] = {
|
||||
255, 255, 255, 255
|
||||
};
|
||||
RHI::TextureDesc fallback2DDesc = {};
|
||||
fallback2DDesc.width = 1;
|
||||
fallback2DDesc.height = 1;
|
||||
fallback2DDesc.depth = 1;
|
||||
fallback2DDesc.mipLevels = 1;
|
||||
fallback2DDesc.arraySize = 1;
|
||||
fallback2DDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
|
||||
fallback2DDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
|
||||
fallback2DDesc.sampleCount = 1;
|
||||
fallback2DDesc.sampleQuality = 0;
|
||||
fallback2DDesc.flags = 0;
|
||||
m_fallbackTexture2D = context.device->CreateTexture(
|
||||
fallback2DDesc,
|
||||
whitePixels2D,
|
||||
sizeof(whitePixels2D),
|
||||
sizeof(whitePixels2D));
|
||||
if (m_fallbackTexture2D == nullptr) {
|
||||
DestroyResources();
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::ResourceViewDesc fallback2DViewDesc = {};
|
||||
fallback2DViewDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
|
||||
fallback2DViewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
|
||||
fallback2DViewDesc.mipLevel = 0;
|
||||
m_fallbackTexture2DView = context.device->CreateShaderResourceView(m_fallbackTexture2D, fallback2DViewDesc);
|
||||
if (m_fallbackTexture2DView == nullptr) {
|
||||
DestroyResources();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuiltinDepthStylePassBase::DestroyResources() {
|
||||
m_resourceCache.Shutdown();
|
||||
|
||||
for (auto& descriptorSetEntry : m_perObjectSets) {
|
||||
DestroyOwnedDescriptorSet(descriptorSetEntry.second);
|
||||
for (auto& descriptorSetEntry : m_dynamicDescriptorSets) {
|
||||
DestroyOwnedDescriptorSet(descriptorSetEntry.second.descriptorSet);
|
||||
}
|
||||
m_perObjectSets.clear();
|
||||
m_dynamicDescriptorSets.clear();
|
||||
|
||||
for (auto& pipelineEntry : m_pipelineStates) {
|
||||
if (pipelineEntry.second != nullptr) {
|
||||
@@ -155,6 +241,24 @@ void BuiltinDepthStylePassBase::DestroyResources() {
|
||||
}
|
||||
m_passResourceLayouts.clear();
|
||||
|
||||
if (m_fallbackTexture2DView != nullptr) {
|
||||
m_fallbackTexture2DView->Shutdown();
|
||||
delete m_fallbackTexture2DView;
|
||||
m_fallbackTexture2DView = nullptr;
|
||||
}
|
||||
|
||||
if (m_fallbackTexture2D != nullptr) {
|
||||
m_fallbackTexture2D->Shutdown();
|
||||
delete m_fallbackTexture2D;
|
||||
m_fallbackTexture2D = nullptr;
|
||||
}
|
||||
|
||||
if (m_sampler != nullptr) {
|
||||
m_sampler->Shutdown();
|
||||
delete m_sampler;
|
||||
m_sampler = nullptr;
|
||||
}
|
||||
|
||||
m_device = nullptr;
|
||||
m_backendType = RHI::RHIType::D3D12;
|
||||
m_builtinShader.Reset();
|
||||
@@ -235,7 +339,7 @@ BuiltinDepthStylePassBase::ResolvedShaderPass BuiltinDepthStylePassBase::Resolve
|
||||
}
|
||||
|
||||
if (m_builtinShader.IsValid() &&
|
||||
tryResolveFromShader(m_builtinShader.Get(), nullptr)) {
|
||||
tryResolveFromShader(m_builtinShader.Get(), material)) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
@@ -259,9 +363,19 @@ bool BuiltinDepthStylePassBase::TryBuildSupportedBindingPlan(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsSupportedPerObjectOnlyBindingPlan(outPlan)) {
|
||||
if (!UsesContiguousDescriptorSets(outPlan)) {
|
||||
if (outError != nullptr) {
|
||||
*outError = "Builtin depth-style pass currently requires exactly one PerObject constant-buffer binding";
|
||||
*outError = "Builtin depth-style pass requires contiguous descriptor set indices";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsSupportedPerObjectOnlyBindingPlan(outPlan) &&
|
||||
!IsSupportedAlphaTestBindingPlan(outPlan)) {
|
||||
if (outError != nullptr) {
|
||||
*outError =
|
||||
"Builtin depth-style pass requires either PerObject-only bindings or the alpha-test contract "
|
||||
"(PerObject + Material + BaseColorTexture + LinearClampSampler)";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -304,24 +418,26 @@ BuiltinDepthStylePassBase::PassResourceLayout* BuiltinDepthStylePassBase::GetOrC
|
||||
return failLayout(contextualError.CStr());
|
||||
}
|
||||
|
||||
std::vector<BuiltinPassSetLayoutMetadata> setLayouts;
|
||||
Containers::String setLayoutError;
|
||||
if (!TryBuildBuiltinPassSetLayouts(bindingPlan, setLayouts, &setLayoutError)) {
|
||||
if (!TryBuildBuiltinPassSetLayouts(bindingPlan, passLayout.setLayouts, &setLayoutError)) {
|
||||
return failLayout(setLayoutError.CStr());
|
||||
}
|
||||
|
||||
if (bindingPlan.perObject.set >= setLayouts.size()) {
|
||||
if (bindingPlan.perObject.set >= passLayout.setLayouts.size()) {
|
||||
return failLayout("Builtin depth-style pass produced an invalid PerObject descriptor set index");
|
||||
}
|
||||
|
||||
passLayout.perObject = bindingPlan.perObject;
|
||||
passLayout.firstDescriptorSet = bindingPlan.firstDescriptorSet;
|
||||
passLayout.perObjectSetLayout = setLayouts[bindingPlan.perObject.set];
|
||||
RefreshBuiltinPassSetLayoutMetadata(passLayout.perObjectSetLayout);
|
||||
passLayout.descriptorSetCount = bindingPlan.descriptorSetCount;
|
||||
passLayout.staticDescriptorSets.resize(passLayout.setLayouts.size());
|
||||
passLayout.perObject = bindingPlan.perObject;
|
||||
passLayout.material = bindingPlan.material;
|
||||
passLayout.baseColorTexture = bindingPlan.baseColorTexture;
|
||||
passLayout.linearClampSampler = bindingPlan.linearClampSampler;
|
||||
|
||||
std::vector<RHI::DescriptorSetLayoutDesc> nativeSetLayouts(setLayouts.size());
|
||||
for (size_t setIndex = 0; setIndex < setLayouts.size(); ++setIndex) {
|
||||
nativeSetLayouts[setIndex] = setLayouts[setIndex].layout;
|
||||
std::vector<RHI::DescriptorSetLayoutDesc> nativeSetLayouts(passLayout.setLayouts.size());
|
||||
for (size_t setIndex = 0; setIndex < passLayout.setLayouts.size(); ++setIndex) {
|
||||
nativeSetLayouts[setIndex] = passLayout.setLayouts[setIndex].layout;
|
||||
}
|
||||
|
||||
RHI::RHIPipelineLayoutDesc pipelineLayoutDesc = {};
|
||||
@@ -333,7 +449,7 @@ BuiltinDepthStylePassBase::PassResourceLayout* BuiltinDepthStylePassBase::GetOrC
|
||||
}
|
||||
|
||||
const auto result = m_passResourceLayouts.emplace(passLayoutKey, std::move(passLayout));
|
||||
RefreshBuiltinPassSetLayoutMetadata(result.first->second.perObjectSetLayout);
|
||||
RefreshBuiltinPassSetLayouts(result.first->second.setLayouts);
|
||||
return &result.first->second;
|
||||
}
|
||||
|
||||
@@ -412,31 +528,98 @@ bool BuiltinDepthStylePassBase::CreateOwnedDescriptorSet(
|
||||
return true;
|
||||
}
|
||||
|
||||
RHI::RHIDescriptorSet* BuiltinDepthStylePassBase::GetOrCreatePerObjectSet(
|
||||
RHI::RHIDescriptorSet* BuiltinDepthStylePassBase::GetOrCreateStaticDescriptorSet(
|
||||
const PassLayoutKey& passLayoutKey,
|
||||
PassResourceLayout& passLayout,
|
||||
Core::uint32 setIndex) {
|
||||
(void)passLayoutKey;
|
||||
|
||||
if (setIndex >= passLayout.setLayouts.size() ||
|
||||
setIndex >= passLayout.staticDescriptorSets.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const BuiltinPassSetLayoutMetadata& setLayout = passLayout.setLayouts[setIndex];
|
||||
if (setLayout.layout.bindingCount == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OwnedDescriptorSet& descriptorSet = passLayout.staticDescriptorSets[setIndex];
|
||||
if (descriptorSet.set == nullptr) {
|
||||
if (!CreateOwnedDescriptorSet(setLayout, descriptorSet)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (setLayout.usesLinearClampSampler) {
|
||||
if (!passLayout.linearClampSampler.IsValid() ||
|
||||
passLayout.linearClampSampler.set != setIndex ||
|
||||
m_sampler == nullptr) {
|
||||
DestroyOwnedDescriptorSet(descriptorSet);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
descriptorSet.set->UpdateSampler(passLayout.linearClampSampler.binding, m_sampler);
|
||||
}
|
||||
}
|
||||
|
||||
return descriptorSet.set;
|
||||
}
|
||||
|
||||
BuiltinDepthStylePassBase::CachedDescriptorSet* BuiltinDepthStylePassBase::GetOrCreateDynamicDescriptorSet(
|
||||
const PassLayoutKey& passLayoutKey,
|
||||
const PassResourceLayout& passLayout,
|
||||
Core::uint64 objectId) {
|
||||
if (!passLayout.perObject.IsValid() ||
|
||||
passLayout.perObjectSetLayout.layout.bindingCount == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PerObjectSetKey key = {};
|
||||
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||
Core::uint32 setIndex,
|
||||
Core::uint64 objectId,
|
||||
const Resources::Material* material,
|
||||
const MaterialConstantPayloadView& materialConstants,
|
||||
RHI::RHIResourceView* baseColorTextureView) {
|
||||
DynamicDescriptorSetKey key = {};
|
||||
key.passLayout = passLayoutKey;
|
||||
key.setIndex = setIndex;
|
||||
key.objectId = objectId;
|
||||
key.material = material;
|
||||
|
||||
const auto existing = m_perObjectSets.find(key);
|
||||
if (existing != m_perObjectSets.end()) {
|
||||
return existing->second.set;
|
||||
CachedDescriptorSet& cachedDescriptorSet = m_dynamicDescriptorSets[key];
|
||||
if (cachedDescriptorSet.descriptorSet.set == nullptr) {
|
||||
if (!CreateOwnedDescriptorSet(setLayout, cachedDescriptorSet.descriptorSet)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
OwnedDescriptorSet descriptorSet = {};
|
||||
if (!CreateOwnedDescriptorSet(passLayout.perObjectSetLayout, descriptorSet)) {
|
||||
return nullptr;
|
||||
const Core::uint64 materialVersion = material != nullptr ? material->GetChangeVersion() : 0;
|
||||
if (setLayout.usesMaterial) {
|
||||
if (!passLayout.material.IsValid() ||
|
||||
passLayout.material.set != setIndex ||
|
||||
!materialConstants.IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (cachedDescriptorSet.materialVersion != materialVersion) {
|
||||
cachedDescriptorSet.descriptorSet.set->WriteConstant(
|
||||
passLayout.material.binding,
|
||||
materialConstants.data,
|
||||
materialConstants.size);
|
||||
}
|
||||
}
|
||||
|
||||
const auto result = m_perObjectSets.emplace(key, descriptorSet);
|
||||
return result.first->second.set;
|
||||
if (setLayout.usesBaseColorTexture) {
|
||||
if (baseColorTextureView == nullptr ||
|
||||
!passLayout.baseColorTexture.IsValid() ||
|
||||
passLayout.baseColorTexture.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (cachedDescriptorSet.baseColorTextureView != baseColorTextureView) {
|
||||
cachedDescriptorSet.descriptorSet.set->Update(
|
||||
passLayout.baseColorTexture.binding,
|
||||
baseColorTextureView);
|
||||
}
|
||||
}
|
||||
|
||||
cachedDescriptorSet.materialVersion = materialVersion;
|
||||
cachedDescriptorSet.baseColorTextureView = baseColorTextureView;
|
||||
return &cachedDescriptorSet;
|
||||
}
|
||||
|
||||
void BuiltinDepthStylePassBase::DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet) {
|
||||
@@ -454,15 +637,46 @@ void BuiltinDepthStylePassBase::DestroyOwnedDescriptorSet(OwnedDescriptorSet& de
|
||||
}
|
||||
|
||||
void BuiltinDepthStylePassBase::DestroyPassResourceLayout(PassResourceLayout& passLayout) {
|
||||
for (OwnedDescriptorSet& descriptorSet : passLayout.staticDescriptorSets) {
|
||||
DestroyOwnedDescriptorSet(descriptorSet);
|
||||
}
|
||||
passLayout.staticDescriptorSets.clear();
|
||||
|
||||
if (passLayout.pipelineLayout != nullptr) {
|
||||
passLayout.pipelineLayout->Shutdown();
|
||||
delete passLayout.pipelineLayout;
|
||||
passLayout.pipelineLayout = nullptr;
|
||||
}
|
||||
|
||||
passLayout.setLayouts.clear();
|
||||
passLayout.perObject = {};
|
||||
passLayout.perObjectSetLayout = {};
|
||||
passLayout.material = {};
|
||||
passLayout.baseColorTexture = {};
|
||||
passLayout.linearClampSampler = {};
|
||||
passLayout.firstDescriptorSet = 0;
|
||||
passLayout.descriptorSetCount = 0;
|
||||
}
|
||||
|
||||
RHI::RHIResourceView* BuiltinDepthStylePassBase::ResolveTextureView(
|
||||
const Resources::Texture* texture) {
|
||||
if (texture == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const RenderResourceCache::CachedTexture* cachedTexture = m_resourceCache.GetOrCreateTexture(m_device, texture);
|
||||
if (cachedTexture != nullptr && cachedTexture->shaderResourceView != nullptr) {
|
||||
return cachedTexture->shaderResourceView;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RHI::RHIResourceView* BuiltinDepthStylePassBase::ResolveTextureView(
|
||||
const VisibleRenderItem& visibleItem) {
|
||||
const Resources::Material* material = ResolveMaterial(visibleItem);
|
||||
const Resources::Texture* texture = ResolveBuiltinBaseColorTexture(material);
|
||||
RHI::RHIResourceView* textureView = ResolveTextureView(texture);
|
||||
return textureView != nullptr ? textureView : m_fallbackTexture2DView;
|
||||
}
|
||||
|
||||
bool BuiltinDepthStylePassBase::DrawVisibleItem(
|
||||
@@ -531,18 +745,6 @@ bool BuiltinDepthStylePassBase::DrawVisibleItem(
|
||||
commandList->SetIndexBuffer(cachedMesh->indexBufferView, 0);
|
||||
}
|
||||
|
||||
RHI::RHIDescriptorSet* constantSet = GetOrCreatePerObjectSet(
|
||||
passLayoutKey,
|
||||
*passLayout,
|
||||
visibleItem.gameObject->GetID());
|
||||
if (constantSet == nullptr) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
(Containers::String("BuiltinDepthStylePassBase failed to allocate descriptor set for ") +
|
||||
visibleItem.gameObject->GetName().c_str()).CStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
const Math::Matrix4x4 projectionMatrix =
|
||||
m_passType == BuiltinMaterialPass::ShadowCaster
|
||||
? sceneData.cameraData.viewProjection
|
||||
@@ -556,14 +758,122 @@ bool BuiltinDepthStylePassBase::DrawVisibleItem(
|
||||
viewMatrix,
|
||||
visibleItem.localToWorld.Transpose()
|
||||
};
|
||||
constantSet->WriteConstant(passLayout->perObject.binding, &constants, sizeof(constants));
|
||||
|
||||
RHI::RHIDescriptorSet* descriptorSets[] = { constantSet };
|
||||
commandList->SetGraphicsDescriptorSets(
|
||||
passLayout->firstDescriptorSet,
|
||||
1,
|
||||
descriptorSets,
|
||||
passLayout->pipelineLayout);
|
||||
MaterialConstantPayloadView materialConstants = ResolveSchemaMaterialConstantPayload(material);
|
||||
FallbackPerMaterialConstants fallbackMaterialConstants = {};
|
||||
if (!materialConstants.IsValid()) {
|
||||
const BuiltinForwardMaterialData materialData = BuildBuiltinForwardMaterialData(material);
|
||||
fallbackMaterialConstants.baseColorFactor = materialData.baseColorFactor;
|
||||
fallbackMaterialConstants.alphaCutoffParams = Math::Vector4(
|
||||
materialData.alphaCutoff,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f);
|
||||
static const Resources::MaterialConstantFieldDesc kFallbackMaterialConstantFields[] = {
|
||||
{
|
||||
Containers::String("_BaseColor"),
|
||||
Resources::MaterialPropertyType::Float4,
|
||||
0,
|
||||
sizeof(Math::Vector4),
|
||||
sizeof(Math::Vector4)
|
||||
},
|
||||
{
|
||||
Containers::String("_Cutoff"),
|
||||
Resources::MaterialPropertyType::Float,
|
||||
sizeof(Math::Vector4),
|
||||
sizeof(float),
|
||||
sizeof(Math::Vector4)
|
||||
}
|
||||
};
|
||||
materialConstants.data = &fallbackMaterialConstants;
|
||||
materialConstants.size = sizeof(fallbackMaterialConstants);
|
||||
materialConstants.layout = {
|
||||
kFallbackMaterialConstantFields,
|
||||
2,
|
||||
sizeof(fallbackMaterialConstants)
|
||||
};
|
||||
}
|
||||
|
||||
RHI::RHIResourceView* baseColorTextureView = ResolveTextureView(visibleItem);
|
||||
if (passLayout->baseColorTexture.IsValid() && baseColorTextureView == nullptr) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
(Containers::String("BuiltinDepthStylePassBase failed to resolve base color texture for ") +
|
||||
visibleItem.gameObject->GetName().c_str()).CStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passLayout->descriptorSetCount > 0) {
|
||||
std::vector<RHI::RHIDescriptorSet*> descriptorSets(passLayout->descriptorSetCount, nullptr);
|
||||
|
||||
for (Core::uint32 descriptorOffset = 0; descriptorOffset < passLayout->descriptorSetCount; ++descriptorOffset) {
|
||||
const Core::uint32 setIndex = passLayout->firstDescriptorSet + descriptorOffset;
|
||||
if (setIndex >= passLayout->setLayouts.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const BuiltinPassSetLayoutMetadata& setLayout = passLayout->setLayouts[setIndex];
|
||||
if (setLayout.layout.bindingCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::RHIDescriptorSet* descriptorSet = nullptr;
|
||||
if (setLayout.usesPerObject ||
|
||||
setLayout.usesMaterial ||
|
||||
setLayout.usesBaseColorTexture) {
|
||||
const Core::uint64 objectId =
|
||||
setLayout.usesPerObject ? visibleItem.gameObject->GetID() : 0;
|
||||
const Resources::Material* materialKey =
|
||||
(setLayout.usesMaterial || setLayout.usesBaseColorTexture) ? material : nullptr;
|
||||
|
||||
CachedDescriptorSet* cachedDescriptorSet = GetOrCreateDynamicDescriptorSet(
|
||||
passLayoutKey,
|
||||
*passLayout,
|
||||
setLayout,
|
||||
setIndex,
|
||||
objectId,
|
||||
materialKey,
|
||||
materialConstants,
|
||||
baseColorTextureView);
|
||||
if (cachedDescriptorSet == nullptr || cachedDescriptorSet->descriptorSet.set == nullptr) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
(Containers::String("BuiltinDepthStylePassBase failed to allocate dynamic descriptor set for ") +
|
||||
visibleItem.gameObject->GetName().c_str()).CStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
descriptorSet = cachedDescriptorSet->descriptorSet.set;
|
||||
if (setLayout.usesPerObject) {
|
||||
if (!passLayout->perObject.IsValid() || passLayout->perObject.set != setIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
descriptorSet->WriteConstant(
|
||||
passLayout->perObject.binding,
|
||||
&constants,
|
||||
sizeof(constants));
|
||||
}
|
||||
} else {
|
||||
descriptorSet = GetOrCreateStaticDescriptorSet(passLayoutKey, *passLayout, setIndex);
|
||||
if (descriptorSet == nullptr) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
(Containers::String("BuiltinDepthStylePassBase failed to allocate static descriptor set for ") +
|
||||
visibleItem.gameObject->GetName().c_str()).CStr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
descriptorSets[descriptorOffset] = descriptorSet;
|
||||
}
|
||||
|
||||
commandList->SetGraphicsDescriptorSets(
|
||||
passLayout->firstDescriptorSet,
|
||||
passLayout->descriptorSetCount,
|
||||
descriptorSets.data(),
|
||||
passLayout->pipelineLayout);
|
||||
}
|
||||
|
||||
if (visibleItem.hasSection) {
|
||||
const Containers::Array<Resources::MeshSection>& sections = visibleItem.mesh->GetSections();
|
||||
|
||||
@@ -183,7 +183,7 @@ BuiltinForwardPipeline::ResolvedShaderPass BuiltinForwardPipeline::ResolveSurfac
|
||||
if (builtinShaderHandle->IsValid()) {
|
||||
const Resources::Shader* builtinShader = builtinShaderHandle->Get();
|
||||
if (const Resources::ShaderPass* shaderPass =
|
||||
FindCompatibleSurfacePass(*builtinShader, sceneData, nullptr, pass, backend)) {
|
||||
FindCompatibleSurfacePass(*builtinShader, sceneData, material, pass, backend)) {
|
||||
resolved.shader = builtinShader;
|
||||
resolved.pass = shaderPass;
|
||||
resolved.passName = shaderPass->name;
|
||||
@@ -705,18 +705,32 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
if (!materialConstants.IsValid()) {
|
||||
const BuiltinForwardMaterialData materialData = BuildBuiltinForwardMaterialData(material);
|
||||
fallbackMaterialConstants.baseColorFactor = materialData.baseColorFactor;
|
||||
static const Resources::MaterialConstantFieldDesc kFallbackMaterialConstantField = {
|
||||
Containers::String("baseColorFactor"),
|
||||
Resources::MaterialPropertyType::Float4,
|
||||
0,
|
||||
sizeof(FallbackPerMaterialConstants),
|
||||
sizeof(FallbackPerMaterialConstants)
|
||||
fallbackMaterialConstants.alphaCutoffParams = Math::Vector4(
|
||||
materialData.alphaCutoff,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f);
|
||||
static const Resources::MaterialConstantFieldDesc kFallbackMaterialConstantFields[] = {
|
||||
{
|
||||
Containers::String("_BaseColor"),
|
||||
Resources::MaterialPropertyType::Float4,
|
||||
0,
|
||||
sizeof(Math::Vector4),
|
||||
sizeof(Math::Vector4)
|
||||
},
|
||||
{
|
||||
Containers::String("_Cutoff"),
|
||||
Resources::MaterialPropertyType::Float,
|
||||
sizeof(Math::Vector4),
|
||||
sizeof(float),
|
||||
sizeof(Math::Vector4)
|
||||
}
|
||||
};
|
||||
materialConstants.data = &fallbackMaterialConstants;
|
||||
materialConstants.size = sizeof(fallbackMaterialConstants);
|
||||
materialConstants.layout = {
|
||||
&kFallbackMaterialConstantField,
|
||||
1,
|
||||
kFallbackMaterialConstantFields,
|
||||
2,
|
||||
sizeof(fallbackMaterialConstants)
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user