Formalize camera post-process descriptors

This commit is contained in:
2026-04-06 14:56:43 +08:00
parent 3a64c325bf
commit b6132aec4d
9 changed files with 400 additions and 41 deletions

View File

@@ -4,6 +4,7 @@
#include "Resources/Material/Material.h"
#include <algorithm>
#include <cctype>
#include <sstream>
namespace XCEngine {
@@ -56,49 +57,118 @@ bool TryParseVector4(const std::string& value, Math::Vector4& outValue) {
return !stream.fail();
}
Rendering::CameraPostProcessStack BuildColorScalePostProcessStack(
const std::vector<Math::Vector4>& values) {
Rendering::CameraPostProcessStack passes;
passes.reserve(values.size());
for (const Math::Vector4& value : values) {
passes.push_back(Rendering::CameraPostProcessPassDesc::MakeColorScale(value));
}
return passes;
}
size_t FindFirstColorScalePassIndex(const Rendering::CameraPostProcessStack& passes) {
for (size_t index = 0; index < passes.size(); ++index) {
if (passes[index].type == Rendering::CameraPostProcessPassType::ColorScale) {
return index;
}
}
return passes.size();
}
} // namespace
void CameraComponent::SetPostProcessPasses(const Rendering::CameraPostProcessStack& values) {
m_postProcessPasses = values;
for (const Rendering::CameraPostProcessPassDesc& pass : m_postProcessPasses) {
if (pass.type == Rendering::CameraPostProcessPassType::ColorScale) {
m_colorScalePostProcessDefaultScale = pass.colorScale.scale;
break;
}
}
}
void CameraComponent::AddPostProcessPass(const Rendering::CameraPostProcessPassDesc& value) {
if (!value.IsValid()) {
return;
}
if (value.type == Rendering::CameraPostProcessPassType::ColorScale &&
FindFirstColorScalePassIndex(m_postProcessPasses) == m_postProcessPasses.size()) {
m_colorScalePostProcessDefaultScale = value.colorScale.scale;
}
m_postProcessPasses.push_back(value);
}
bool CameraComponent::IsColorScalePostProcessEnabled() const {
return !m_colorScalePostProcessPasses.empty();
return FindFirstColorScalePassIndex(m_postProcessPasses) != m_postProcessPasses.size();
}
void CameraComponent::SetColorScalePostProcessEnabled(bool value) {
if (value) {
if (m_colorScalePostProcessPasses.empty()) {
m_colorScalePostProcessPasses.push_back(m_colorScalePostProcessDefaultScale);
if (!IsColorScalePostProcessEnabled()) {
m_postProcessPasses.push_back(
Rendering::CameraPostProcessPassDesc::MakeColorScale(
m_colorScalePostProcessDefaultScale));
}
return;
}
m_colorScalePostProcessPasses.clear();
ClearColorScalePostProcessPasses();
}
const Math::Vector4& CameraComponent::GetColorScalePostProcessScale() const {
return m_colorScalePostProcessPasses.empty()
const size_t firstColorScalePassIndex = FindFirstColorScalePassIndex(m_postProcessPasses);
return firstColorScalePassIndex == m_postProcessPasses.size()
? m_colorScalePostProcessDefaultScale
: m_colorScalePostProcessPasses.front();
: m_postProcessPasses[firstColorScalePassIndex].colorScale.scale;
}
void CameraComponent::SetColorScalePostProcessScale(const Math::Vector4& value) {
m_colorScalePostProcessDefaultScale = value;
if (!m_colorScalePostProcessPasses.empty()) {
m_colorScalePostProcessPasses.front() = value;
const size_t firstColorScalePassIndex = FindFirstColorScalePassIndex(m_postProcessPasses);
if (firstColorScalePassIndex != m_postProcessPasses.size()) {
m_postProcessPasses[firstColorScalePassIndex].colorScale.scale = value;
}
}
std::vector<Math::Vector4> CameraComponent::GetColorScalePostProcessPasses() const {
std::vector<Math::Vector4> values;
values.reserve(m_postProcessPasses.size());
for (const Rendering::CameraPostProcessPassDesc& pass : m_postProcessPasses) {
if (pass.type == Rendering::CameraPostProcessPassType::ColorScale) {
values.push_back(pass.colorScale.scale);
}
}
return values;
}
void CameraComponent::SetColorScalePostProcessPasses(const std::vector<Math::Vector4>& values) {
m_colorScalePostProcessPasses = values;
if (!m_colorScalePostProcessPasses.empty()) {
m_colorScalePostProcessDefaultScale = m_colorScalePostProcessPasses.front();
SetPostProcessPasses(BuildColorScalePostProcessStack(values));
if (!values.empty()) {
m_colorScalePostProcessDefaultScale = values.front();
}
}
void CameraComponent::AddColorScalePostProcessPass(const Math::Vector4& value) {
if (m_colorScalePostProcessPasses.empty()) {
if (!IsColorScalePostProcessEnabled()) {
m_colorScalePostProcessDefaultScale = value;
}
m_colorScalePostProcessPasses.push_back(value);
m_postProcessPasses.push_back(Rendering::CameraPostProcessPassDesc::MakeColorScale(value));
}
void CameraComponent::ClearColorScalePostProcessPasses() {
m_postProcessPasses.erase(
std::remove_if(
m_postProcessPasses.begin(),
m_postProcessPasses.end(),
[](const Rendering::CameraPostProcessPassDesc& pass) {
return pass.type == Rendering::CameraPostProcessPassType::ColorScale;
}),
m_postProcessPasses.end());
}
void CameraComponent::SetFieldOfView(float value) {
@@ -206,12 +276,18 @@ void CameraComponent::Serialize(std::ostream& os) const {
os << "skyboxTopColor=" << m_skyboxTopColor.r << "," << m_skyboxTopColor.g << "," << m_skyboxTopColor.b << "," << m_skyboxTopColor.a << ";";
os << "skyboxHorizonColor=" << m_skyboxHorizonColor.r << "," << m_skyboxHorizonColor.g << "," << m_skyboxHorizonColor.b << "," << m_skyboxHorizonColor.a << ";";
os << "skyboxBottomColor=" << m_skyboxBottomColor.r << "," << m_skyboxBottomColor.g << "," << m_skyboxBottomColor.b << "," << m_skyboxBottomColor.a << ";";
os << "colorScalePostProcessEnabled=" << (IsColorScalePostProcessEnabled() ? 1 : 0) << ";";
os << "colorScalePostProcessScale=" << EncodeVector4(GetColorScalePostProcessScale()) << ";";
os << "colorScalePostProcessPassCount=" << m_colorScalePostProcessPasses.size() << ";";
for (size_t index = 0; index < m_colorScalePostProcessPasses.size(); ++index) {
os << "colorScalePostProcessPass" << index << "="
<< EncodeVector4(m_colorScalePostProcessPasses[index]) << ";";
os << "postProcessPassCount=" << m_postProcessPasses.size() << ";";
for (size_t index = 0; index < m_postProcessPasses.size(); ++index) {
const Rendering::CameraPostProcessPassDesc& pass = m_postProcessPasses[index];
os << "postProcessPass" << index << "Type=" << static_cast<int>(pass.type) << ";";
switch (pass.type) {
case Rendering::CameraPostProcessPassType::ColorScale:
os << "postProcessPass" << index << "ColorScale="
<< EncodeVector4(pass.colorScale.scale) << ";";
break;
default:
break;
}
}
}
@@ -220,11 +296,13 @@ void CameraComponent::Deserialize(std::istream& is) {
m_skyboxMaterialPath.clear();
m_skyboxMaterialRef.Reset();
m_colorScalePostProcessDefaultScale = Math::Vector4::One();
m_colorScalePostProcessPasses.clear();
m_postProcessPasses.clear();
std::string token;
std::string pendingSkyboxMaterialPath;
Resources::AssetRef pendingSkyboxMaterialRef;
size_t postProcessPassCount = 0;
Rendering::CameraPostProcessStack deserializedPostProcessPasses;
bool legacyColorScaleEnabled = false;
size_t colorScalePassCount = 0;
std::vector<Math::Vector4> deserializedColorScalePasses;
@@ -289,6 +367,33 @@ void CameraComponent::Deserialize(std::istream& is) {
std::replace(value.begin(), value.end(), ',', ' ');
std::istringstream ss(value);
ss >> m_skyboxBottomColor.r >> m_skyboxBottomColor.g >> m_skyboxBottomColor.b >> m_skyboxBottomColor.a;
} else if (key == "postProcessPassCount") {
postProcessPassCount = static_cast<size_t>(std::stoul(value));
deserializedPostProcessPasses.clear();
deserializedPostProcessPasses.resize(postProcessPassCount);
} else if (key.rfind("postProcessPass", 0) == 0) {
const size_t prefixLength = std::string("postProcessPass").size();
size_t propertyPos = prefixLength;
while (propertyPos < key.size() &&
std::isdigit(static_cast<unsigned char>(key[propertyPos])) != 0) {
++propertyPos;
}
if (propertyPos > prefixLength) {
const size_t index = static_cast<size_t>(
std::stoul(key.substr(prefixLength, propertyPos - prefixLength)));
if (index >= deserializedPostProcessPasses.size()) {
deserializedPostProcessPasses.resize(index + 1);
}
Rendering::CameraPostProcessPassDesc& pass = deserializedPostProcessPasses[index];
const std::string property = key.substr(propertyPos);
if (property == "Type") {
pass.type = static_cast<Rendering::CameraPostProcessPassType>(std::stoi(value));
} else if (property == "ColorScale") {
TryParseVector4(value, pass.colorScale.scale);
}
}
} else if (key == "colorScalePostProcessEnabled") {
legacyColorScaleEnabled = (std::stoi(value) != 0);
} else if (key == "colorScalePostProcessScale") {
@@ -331,7 +436,9 @@ void CameraComponent::Deserialize(std::istream& is) {
m_skyboxMaterialRef = pendingSkyboxMaterialRef;
}
if (!deserializedColorScalePasses.empty()) {
if (!deserializedPostProcessPasses.empty()) {
SetPostProcessPasses(deserializedPostProcessPasses);
} else if (!deserializedColorScalePasses.empty()) {
SetColorScalePostProcessPasses(deserializedColorScalePasses);
} else if (legacyColorScaleEnabled) {
SetColorScalePostProcessEnabled(true);

View File

@@ -2,7 +2,7 @@
#include "Components/CameraComponent.h"
#include "Rendering/Caches/FullscreenPassSurfaceCache.h"
#include "Rendering/Passes/BuiltinColorScalePostProcessPass.h"
#include "Rendering/Planning/CameraPostProcessPassFactory.h"
#include "Rendering/Planning/SceneRenderRequestUtils.h"
namespace XCEngine {
@@ -104,8 +104,8 @@ void SceneRenderer::AttachCameraPostProcessRequests(
continue;
}
const std::vector<Math::Vector4>& colorScalePasses = request.camera->GetColorScalePostProcessPasses();
if (colorScalePasses.empty()) {
const CameraPostProcessStack& postProcessPasses = request.camera->GetPostProcessPasses();
if (postProcessPasses.empty()) {
continue;
}
@@ -131,12 +131,11 @@ void SceneRenderer::AttachCameraPostProcessRequests(
continue;
}
std::unique_ptr<RenderPassSequence> postProcessSequence = std::make_unique<RenderPassSequence>();
for (const Math::Vector4& colorScale : colorScalePasses) {
postProcessSequence->AddPass(
std::make_unique<Passes::BuiltinColorScalePostProcessPass>(colorScale));
std::unique_ptr<RenderPassSequence> postProcessSequence =
BuildCameraPostProcessPassSequence(postProcessPasses);
if (postProcessSequence == nullptr || postProcessSequence->GetPassCount() == 0u) {
continue;
}
RenderSurface sourceSurface = sourceEntry->surface;
sourceSurface.SetDepthAttachment(request.surface.GetDepthAttachment());
sourceSurface.SetColorStateBefore(RHI::ResourceStates::Common);