Formalize forward lighting contract

This commit is contained in:
2026-04-05 15:44:37 +08:00
parent f6da4d0eb6
commit 2c96f0d164
18 changed files with 152 additions and 90 deletions

View File

@@ -8,15 +8,18 @@ layout(std140, binding = 0) uniform PerObjectConstants {
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
};
layout(std140, binding = 1) uniform LightingConstants {
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
layout(std140, binding = 1) uniform MaterialConstants {
layout(std140, binding = 2) uniform MaterialConstants {
vec4 gBaseColorFactor;
};
layout(std140, binding = 2) uniform ShadowReceiverConstants {
layout(std140, binding = 3) uniform ShadowReceiverConstants {
mat4 gWorldToShadowMatrix;
vec4 gShadowBiasAndTexelSize;
vec4 gShadowOptions;

View File

@@ -1,24 +1,27 @@
// XC_BUILTIN_FORWARD_LIT_VULKAN_PS
#version 450
layout(set = 2, binding = 0) uniform texture2D uBaseColorTexture;
layout(set = 3, binding = 0) uniform sampler uLinearSampler;
layout(set = 5, binding = 0) uniform texture2D uShadowMapTexture;
layout(set = 6, binding = 0) uniform sampler uShadowMapSampler;
layout(set = 4, binding = 0) uniform texture2D uBaseColorTexture;
layout(set = 5, binding = 0) uniform sampler uLinearSampler;
layout(set = 6, binding = 0) uniform texture2D uShadowMapTexture;
layout(set = 7, binding = 0) uniform sampler uShadowMapSampler;
layout(set = 0, binding = 0, std140) uniform PerObjectConstants {
mat4 gProjectionMatrix;
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
};
layout(set = 1, binding = 0, std140) uniform LightingConstants {
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
layout(set = 1, binding = 0, std140) uniform MaterialConstants {
layout(set = 2, binding = 0, std140) uniform MaterialConstants {
vec4 gBaseColorFactor;
};
layout(set = 4, binding = 0, std140) uniform ShadowReceiverConstants {
layout(set = 3, binding = 0, std140) uniform ShadowReceiverConstants {
mat4 gWorldToShadowMatrix;
vec4 gShadowBiasAndTexelSize;
vec4 gShadowOptions;

View File

@@ -9,15 +9,18 @@ cbuffer PerObjectConstants : register(b0) {
float4x4 gViewMatrix;
float4x4 gModelMatrix;
float4x4 gNormalMatrix;
};
cbuffer LightingConstants : register(b1) {
float4 gMainLightDirectionAndIntensity;
float4 gMainLightColorAndFlags;
};
cbuffer MaterialConstants : register(b1) {
cbuffer MaterialConstants : register(b2) {
float4 gBaseColorFactor;
};
cbuffer ShadowReceiverConstants : register(b2) {
cbuffer ShadowReceiverConstants : register(b3) {
float4x4 gWorldToShadowMatrix;
float4 gShadowBiasAndTexelSize;
float4 gShadowOptions;

View File

@@ -14,12 +14,13 @@ Shader "Builtin Forward Lit"
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)]
ShadowReceiverConstants (ConstantBuffer, 4, 0) [Semantic(ShadowReceiver)]
ShadowMapTexture (Texture2D, 5, 0) [Semantic(ShadowMapTexture)]
ShadowMapSampler (Sampler, 6, 0) [Semantic(ShadowMapSampler)]
LightingConstants (ConstantBuffer, 1, 0) [Semantic(Lighting)]
MaterialConstants (ConstantBuffer, 2, 0) [Semantic(Material)]
ShadowReceiverConstants (ConstantBuffer, 3, 0) [Semantic(ShadowReceiver)]
BaseColorTexture (Texture2D, 4, 0) [Semantic(BaseColorTexture)]
LinearClampSampler (Sampler, 5, 0) [Semantic(LinearClampSampler)]
ShadowMapTexture (Texture2D, 6, 0) [Semantic(ShadowMapTexture)]
ShadowMapSampler (Sampler, 7, 0) [Semantic(ShadowMapSampler)]
}
HLSLPROGRAM
#pragma vertex MainVS

View File

@@ -9,8 +9,6 @@ layout(std140, binding = 0) uniform PerObjectConstants {
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
out vec3 vNormalWS;

View File

@@ -9,8 +9,6 @@ layout(set = 0, binding = 0, std140) uniform PerObjectConstants {
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
layout(location = 0) out vec3 vNormalWS;

View File

@@ -4,8 +4,6 @@ cbuffer PerObjectConstants : register(b0) {
float4x4 gViewMatrix;
float4x4 gModelMatrix;
float4x4 gNormalMatrix;
float4 gMainLightDirectionAndIntensity;
float4 gMainLightColorAndFlags;
};
struct VSInput {

View File

@@ -7,8 +7,6 @@ layout(std140, binding = 0) uniform PerObjectConstants {
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
layout(std140, binding = 1) uniform MaterialConstants {

View File

@@ -8,8 +8,6 @@ layout(set = 0, binding = 0, std140) uniform PerObjectConstants {
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
layout(set = 1, binding = 0, std140) uniform MaterialConstants {

View File

@@ -7,8 +7,6 @@ cbuffer PerObjectConstants : register(b0) {
float4x4 gViewMatrix;
float4x4 gModelMatrix;
float4x4 gNormalMatrix;
float4 gMainLightDirectionAndIntensity;
float4 gMainLightColorAndFlags;
};
cbuffer MaterialConstants : register(b1) {

View File

@@ -9,8 +9,6 @@ layout(std140, binding = 0) uniform PerObjectConstants {
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
out vec2 vTexCoord;

View File

@@ -9,8 +9,6 @@ layout(set = 0, binding = 0, std140) uniform PerObjectConstants {
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
layout(location = 0) out vec2 vTexCoord;

View File

@@ -4,8 +4,6 @@ cbuffer PerObjectConstants : register(b0) {
float4x4 gViewMatrix;
float4x4 gModelMatrix;
float4x4 gNormalMatrix;
float4 gMainLightDirectionAndIntensity;
float4 gMainLightColorAndFlags;
};
struct VSInput {

View File

@@ -64,6 +64,9 @@ private:
Math::Matrix4x4 view = Math::Matrix4x4::Identity();
Math::Matrix4x4 model = Math::Matrix4x4::Identity();
Math::Matrix4x4 normalMatrix = Math::Matrix4x4::Identity();
};
struct LightingConstants {
Math::Vector4 mainLightDirectionAndIntensity = Math::Vector4::Zero();
Math::Vector4 mainLightColorAndFlags = Math::Vector4::Zero();
};
@@ -103,6 +106,7 @@ private:
std::vector<OwnedDescriptorSet> staticDescriptorSets;
PassResourceBindingLocation perObject = {};
PassResourceBindingLocation material = {};
PassResourceBindingLocation lighting = {};
PassResourceBindingLocation shadowReceiver = {};
PassResourceBindingLocation baseColorTexture = {};
PassResourceBindingLocation linearClampSampler = {};
@@ -200,6 +204,7 @@ private:
Core::uint64 objectId,
const Resources::Material* material,
const MaterialConstantPayloadView& materialConstants,
const LightingConstants& lightingConstants,
const ShadowReceiverConstants& shadowReceiverConstants,
RHI::RHIResourceView* baseColorTextureView,
RHI::RHIResourceView* shadowMapTextureView);

View File

@@ -37,6 +37,7 @@ enum class BuiltinPassResourceSemantic : Core::uint8 {
Unknown = 0,
PerObject,
Material,
Lighting,
ShadowReceiver,
BaseColorTexture,
ShadowMapTexture,
@@ -60,6 +61,7 @@ struct BuiltinPassResourceBindingPlan {
bool usesSamplers = false;
PassResourceBindingLocation perObject = {};
PassResourceBindingLocation material = {};
PassResourceBindingLocation lighting = {};
PassResourceBindingLocation shadowReceiver = {};
PassResourceBindingLocation baseColorTexture = {};
PassResourceBindingLocation linearClampSampler = {};
@@ -84,6 +86,7 @@ struct BuiltinPassSetLayoutMetadata {
bool shaderVisible = false;
bool usesPerObject = false;
bool usesMaterial = false;
bool usesLighting = false;
bool usesShadowReceiver = false;
bool usesTexture = false;
bool usesBaseColorTexture = false;
@@ -209,6 +212,11 @@ inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic(
return BuiltinPassResourceSemantic::Material;
}
if (semantic == Containers::String("lighting") ||
semantic == Containers::String("lightingconstants")) {
return BuiltinPassResourceSemantic::Lighting;
}
if (semantic == Containers::String("shadowreceiver") ||
semantic == Containers::String("shadowreceiverconstants")) {
return BuiltinPassResourceSemantic::ShadowReceiver;
@@ -242,6 +250,7 @@ inline bool IsBuiltinPassResourceTypeCompatible(
switch (semantic) {
case BuiltinPassResourceSemantic::PerObject:
case BuiltinPassResourceSemantic::Material:
case BuiltinPassResourceSemantic::Lighting:
case BuiltinPassResourceSemantic::ShadowReceiver:
return type == Resources::ShaderResourceType::ConstantBuffer;
case BuiltinPassResourceSemantic::BaseColorTexture:
@@ -295,6 +304,9 @@ inline bool TryBuildBuiltinPassResourceBindingPlan(
case BuiltinPassResourceSemantic::Material:
location = &outPlan.material;
break;
case BuiltinPassResourceSemantic::Lighting:
location = &outPlan.lighting;
break;
case BuiltinPassResourceSemantic::ShadowReceiver:
location = &outPlan.shadowReceiver;
break;
@@ -488,6 +500,9 @@ inline bool TryBuildBuiltinPassSetLayouts(
case BuiltinPassResourceSemantic::Material:
setLayout.usesMaterial = true;
break;
case BuiltinPassResourceSemantic::Lighting:
setLayout.usesLighting = true;
break;
case BuiltinPassResourceSemantic::ShadowReceiver:
setLayout.usesShadowReceiver = true;
break;

View File

@@ -561,6 +561,7 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
passLayout.perObject = bindingPlan.perObject;
passLayout.material = bindingPlan.material;
passLayout.lighting = bindingPlan.lighting;
passLayout.shadowReceiver = bindingPlan.shadowReceiver;
passLayout.baseColorTexture = bindingPlan.baseColorTexture;
passLayout.linearClampSampler = bindingPlan.linearClampSampler;
@@ -570,6 +571,10 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
if (!passLayout.perObject.IsValid()) {
return failLayout("BuiltinForwardPipeline requires a PerObject resource binding");
}
if (ShaderPassMatchesBuiltinPass(*resolvedShaderPass.pass, BuiltinMaterialPass::ForwardLit) &&
!passLayout.lighting.IsValid()) {
return failLayout("BuiltinForwardPipeline forward-lit pass requires a Lighting resource binding");
}
std::vector<RHI::DescriptorSetLayoutDesc> nativeSetLayouts(passLayout.setLayouts.size());
for (size_t i = 0; i < passLayout.setLayouts.size(); ++i) {
@@ -718,6 +723,7 @@ BuiltinForwardPipeline::CachedDescriptorSet* BuiltinForwardPipeline::GetOrCreate
Core::uint64 objectId,
const Resources::Material* material,
const MaterialConstantPayloadView& materialConstants,
const LightingConstants& lightingConstants,
const ShadowReceiverConstants& shadowReceiverConstants,
RHI::RHIResourceView* baseColorTextureView,
RHI::RHIResourceView* shadowMapTextureView) {
@@ -750,6 +756,16 @@ BuiltinForwardPipeline::CachedDescriptorSet* BuiltinForwardPipeline::GetOrCreate
}
}
if (setLayout.usesLighting) {
if (!passLayout.lighting.IsValid() || passLayout.lighting.set != setIndex) {
return nullptr;
}
cachedDescriptorSet.descriptorSet.set->WriteConstant(
passLayout.lighting.binding,
&lightingConstants,
sizeof(lightingConstants));
}
if (setLayout.usesShadowReceiver) {
if (!passLayout.shadowReceiver.IsValid() || passLayout.shadowReceiver.set != setIndex) {
return nullptr;
@@ -824,6 +840,7 @@ void BuiltinForwardPipeline::DestroyPassResourceLayout(PassResourceLayout& passL
passLayout.descriptorSetCount = 0;
passLayout.perObject = {};
passLayout.material = {};
passLayout.lighting = {};
passLayout.shadowReceiver = {};
passLayout.baseColorTexture = {};
passLayout.linearClampSampler = {};
@@ -872,7 +889,9 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
sceneData.cameraData.projection,
sceneData.cameraData.view,
visibleItem.localToWorld.Transpose(),
visibleItem.localToWorld.Inverse(),
visibleItem.localToWorld.Inverse()
};
const LightingConstants lightingConstants = {
sceneData.lighting.HasMainDirectionalLight()
? Math::Vector4(
sceneData.lighting.mainDirectionalLight.direction.x,
@@ -961,6 +980,7 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
RHI::RHIDescriptorSet* descriptorSet = nullptr;
if (setLayout.usesPerObject ||
setLayout.usesLighting ||
setLayout.usesMaterial ||
setLayout.usesShadowReceiver ||
setLayout.usesTexture) {
@@ -979,6 +999,7 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
objectId,
materialKey,
materialConstants,
lightingConstants,
shadowReceiverConstants,
baseColorTextureView,
shadowMapTextureView);