feat: add basic forward lighting coverage

This commit is contained in:
2026-04-01 00:41:56 +08:00
parent ac2b7c1fa2
commit 3373119eee
10 changed files with 31741 additions and 7 deletions

View File

@@ -59,16 +59,21 @@ cbuffer PerObjectConstants : register(b1) {
float4x4 gProjectionMatrix;
float4x4 gViewMatrix;
float4x4 gModelMatrix;
float4x4 gNormalMatrix;
float4 gMainLightDirectionAndIntensity;
float4 gMainLightColorAndFlags;
};
struct VSInput {
float3 position : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
};
struct PSInput {
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
float3 normalWS : TEXCOORD0;
float2 texcoord : TEXCOORD1;
};
PSInput MainVS(VSInput input) {
@@ -76,31 +81,48 @@ PSInput MainVS(VSInput input) {
float4 positionWS = mul(gModelMatrix, float4(input.position, 1.0f));
float4 positionVS = mul(gViewMatrix, positionWS);
output.position = mul(gProjectionMatrix, positionVS);
output.normalWS = mul((float3x3)gNormalMatrix, input.normal);
output.texcoord = input.texcoord;
return output;
}
float4 MainPS(PSInput input) : SV_TARGET {
return gBaseColorTexture.Sample(gLinearSampler, input.texcoord);
float4 baseColor = gBaseColorTexture.Sample(gLinearSampler, input.texcoord);
if (gMainLightColorAndFlags.a < 0.5f) {
return baseColor;
}
float3 normalWS = normalize(input.normalWS);
float3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz);
float diffuse = saturate(dot(normalWS, directionToLightWS));
float3 lighting = float3(0.28f, 0.28f, 0.28f) +
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w);
return float4(baseColor.rgb * lighting, baseColor.a);
}
)";
const char kBuiltinForwardVertexShader[] = R"(#version 430
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec2 aTexCoord;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aTexCoord;
layout(std140, binding = 1) uniform PerObjectConstants {
mat4 gProjectionMatrix;
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
out vec3 vNormalWS;
out vec2 vTexCoord;
void main() {
vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0);
vec4 positionVS = gViewMatrix * positionWS;
gl_Position = gProjectionMatrix * positionVS;
vNormalWS = mat3(gNormalMatrix) * aNormal;
vTexCoord = aTexCoord;
}
)";
@@ -108,12 +130,33 @@ void main() {
const char kBuiltinForwardFragmentShader[] = R"(#version 430
layout(binding = 1) uniform sampler2D uBaseColorTexture;
layout(std140, binding = 1) uniform PerObjectConstants {
mat4 gProjectionMatrix;
mat4 gViewMatrix;
mat4 gModelMatrix;
mat4 gNormalMatrix;
vec4 gMainLightDirectionAndIntensity;
vec4 gMainLightColorAndFlags;
};
in vec3 vNormalWS;
in vec2 vTexCoord;
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = texture(uBaseColorTexture, vTexCoord);
vec4 baseColor = texture(uBaseColorTexture, vTexCoord);
if (gMainLightColorAndFlags.w < 0.5) {
fragColor = baseColor;
return;
}
vec3 normalWS = normalize(vNormalWS);
vec3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz);
float diffuse = max(dot(normalWS, directionToLightWS), 0.0);
vec3 lighting = vec3(0.28) +
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w);
fragColor = vec4(baseColor.rgb * lighting, baseColor.a);
}
)";
@@ -204,6 +247,14 @@ RHI::InputLayoutDesc BuiltinForwardPipeline::BuildInputLayout() {
position.alignedByteOffset = 0;
inputLayout.elements.push_back(position);
RHI::InputElementDesc normal = {};
normal.semanticName = "NORMAL";
normal.semanticIndex = 0;
normal.format = static_cast<uint32_t>(RHI::Format::R32G32B32_Float);
normal.inputSlot = 0;
normal.alignedByteOffset = static_cast<uint32_t>(offsetof(Resources::StaticMeshVertex, normal));
inputLayout.elements.push_back(normal);
RHI::InputElementDesc texcoord = {};
texcoord.semanticName = "TEXCOORD";
texcoord.semanticIndex = 0;
@@ -689,7 +740,22 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
const PerObjectConstants constants = {
sceneData.cameraData.projection,
sceneData.cameraData.view,
visibleItem.localToWorld.Transpose()
visibleItem.localToWorld.Transpose(),
visibleItem.localToWorld.Inverse(),
sceneData.lighting.HasMainDirectionalLight()
? Math::Vector4(
sceneData.lighting.mainDirectionalLight.direction.x,
sceneData.lighting.mainDirectionalLight.direction.y,
sceneData.lighting.mainDirectionalLight.direction.z,
sceneData.lighting.mainDirectionalLight.intensity)
: Math::Vector4::Zero(),
sceneData.lighting.HasMainDirectionalLight()
? Math::Vector4(
sceneData.lighting.mainDirectionalLight.color.r,
sceneData.lighting.mainDirectionalLight.color.g,
sceneData.lighting.mainDirectionalLight.color.b,
1.0f)
: Math::Vector4::Zero()
};
RHI::RHIResourceView* textureView = ResolveTextureView(visibleItem);

View File

@@ -2,6 +2,7 @@
#include "Components/CameraComponent.h"
#include "Components/GameObject.h"
#include "Components/LightComponent.h"
#include "Components/MeshFilterComponent.h"
#include "Components/MeshRendererComponent.h"
#include "Components/TransformComponent.h"
@@ -22,6 +23,13 @@ bool IsUsableCamera(const Components::CameraComponent* camera) {
camera->GetGameObject()->IsActiveInHierarchy();
}
bool IsUsableLight(const Components::LightComponent* light) {
return light != nullptr &&
light->IsEnabled() &&
light->GetGameObject() != nullptr &&
light->GetGameObject()->IsActiveInHierarchy();
}
bool CompareVisibleItems(const VisibleRenderItem& lhs, const VisibleRenderItem& rhs) {
if (lhs.renderQueue != rhs.renderQueue) {
return lhs.renderQueue < rhs.renderQueue;
@@ -66,6 +74,7 @@ RenderSceneData RenderSceneExtractor::Extract(
sceneData.visibleItems.begin(),
sceneData.visibleItems.end(),
CompareVisibleItems);
ExtractLighting(scene, sceneData.lighting);
return sceneData;
}
@@ -93,6 +102,7 @@ RenderSceneData RenderSceneExtractor::ExtractForCamera(
sceneData.visibleItems.begin(),
sceneData.visibleItems.end(),
CompareVisibleItems);
ExtractLighting(scene, sceneData.lighting);
return sceneData;
}
@@ -171,6 +181,46 @@ RenderCameraData RenderSceneExtractor::BuildCameraData(
return cameraData;
}
void RenderSceneExtractor::ExtractLighting(
const Components::Scene& scene,
RenderLightingData& lightingData) const {
const std::vector<Components::LightComponent*> lights =
scene.FindObjectsOfType<Components::LightComponent>();
Components::LightComponent* mainDirectionalLight = nullptr;
for (Components::LightComponent* light : lights) {
if (!IsUsableLight(light) ||
light->GetLightType() != Components::LightType::Directional) {
continue;
}
if (mainDirectionalLight == nullptr ||
light->GetIntensity() > mainDirectionalLight->GetIntensity()) {
mainDirectionalLight = light;
}
}
if (mainDirectionalLight == nullptr) {
lightingData = {};
return;
}
RenderDirectionalLightData lightData;
lightData.enabled = true;
lightData.intensity = mainDirectionalLight->GetIntensity();
lightData.color = mainDirectionalLight->GetColor();
Math::Vector3 direction = mainDirectionalLight->transform().GetForward() * -1.0f;
if (direction.SqrMagnitude() <= Math::EPSILON) {
direction = Math::Vector3::Back();
} else {
direction = direction.Normalized();
}
lightData.direction = direction;
lightingData.mainDirectionalLight = lightData;
}
void RenderSceneExtractor::ExtractVisibleItems(
Components::GameObject* gameObject,
const Math::Vector3& cameraPosition,