Support camera-config color-scale pass stacks

This commit is contained in:
2026-04-06 14:37:54 +08:00
parent f0d3f251b4
commit 3a64c325bf
6 changed files with 154 additions and 30 deletions

View File

@@ -9,6 +9,7 @@
#include <XCEngine/Resources/Material/Material.h>
#include <string>
#include <vector>
namespace XCEngine {
namespace Components {
@@ -90,11 +91,16 @@ public:
const Math::Color& GetSkyboxBottomColor() const { return m_skyboxBottomColor; }
void SetSkyboxBottomColor(const Math::Color& value) { m_skyboxBottomColor = value; }
bool IsColorScalePostProcessEnabled() const { return m_colorScalePostProcessEnabled; }
void SetColorScalePostProcessEnabled(bool value) { m_colorScalePostProcessEnabled = value; }
bool IsColorScalePostProcessEnabled() const;
void SetColorScalePostProcessEnabled(bool value);
const Math::Vector4& GetColorScalePostProcessScale() const { return m_colorScalePostProcessScale; }
void SetColorScalePostProcessScale(const Math::Vector4& value) { m_colorScalePostProcessScale = value; }
const Math::Vector4& GetColorScalePostProcessScale() const;
void SetColorScalePostProcessScale(const Math::Vector4& value);
const std::vector<Math::Vector4>& GetColorScalePostProcessPasses() const { return m_colorScalePostProcessPasses; }
void SetColorScalePostProcessPasses(const std::vector<Math::Vector4>& values);
void AddColorScalePostProcessPass(const Math::Vector4& value);
void ClearColorScalePostProcessPasses() { m_colorScalePostProcessPasses.clear(); }
void Serialize(std::ostream& os) const override;
void Deserialize(std::istream& is) override;
@@ -119,8 +125,8 @@ private:
Math::Color m_skyboxTopColor = Math::Color(0.18f, 0.36f, 0.74f, 1.0f);
Math::Color m_skyboxHorizonColor = Math::Color(0.78f, 0.84f, 0.92f, 1.0f);
Math::Color m_skyboxBottomColor = Math::Color(0.92f, 0.93f, 0.95f, 1.0f);
bool m_colorScalePostProcessEnabled = false;
Math::Vector4 m_colorScalePostProcessScale = Math::Vector4::One();
Math::Vector4 m_colorScalePostProcessDefaultScale = Math::Vector4::One();
std::vector<Math::Vector4> m_colorScalePostProcessPasses;
};
} // namespace Components

View File

@@ -42,8 +42,65 @@ bool TryDecodeAssetRef(const std::string& value, Resources::AssetRef& outRef) {
return outRef.IsValid();
}
std::string EncodeVector4(const Math::Vector4& value) {
std::ostringstream stream;
stream << value.x << "," << value.y << "," << value.z << "," << value.w;
return stream.str();
}
bool TryParseVector4(const std::string& value, Math::Vector4& outValue) {
std::string normalized = value;
std::replace(normalized.begin(), normalized.end(), ',', ' ');
std::istringstream stream(normalized);
stream >> outValue.x >> outValue.y >> outValue.z >> outValue.w;
return !stream.fail();
}
} // namespace
bool CameraComponent::IsColorScalePostProcessEnabled() const {
return !m_colorScalePostProcessPasses.empty();
}
void CameraComponent::SetColorScalePostProcessEnabled(bool value) {
if (value) {
if (m_colorScalePostProcessPasses.empty()) {
m_colorScalePostProcessPasses.push_back(m_colorScalePostProcessDefaultScale);
}
return;
}
m_colorScalePostProcessPasses.clear();
}
const Math::Vector4& CameraComponent::GetColorScalePostProcessScale() const {
return m_colorScalePostProcessPasses.empty()
? m_colorScalePostProcessDefaultScale
: m_colorScalePostProcessPasses.front();
}
void CameraComponent::SetColorScalePostProcessScale(const Math::Vector4& value) {
m_colorScalePostProcessDefaultScale = value;
if (!m_colorScalePostProcessPasses.empty()) {
m_colorScalePostProcessPasses.front() = value;
}
}
void CameraComponent::SetColorScalePostProcessPasses(const std::vector<Math::Vector4>& values) {
m_colorScalePostProcessPasses = values;
if (!m_colorScalePostProcessPasses.empty()) {
m_colorScalePostProcessDefaultScale = m_colorScalePostProcessPasses.front();
}
}
void CameraComponent::AddColorScalePostProcessPass(const Math::Vector4& value) {
if (m_colorScalePostProcessPasses.empty()) {
m_colorScalePostProcessDefaultScale = value;
}
m_colorScalePostProcessPasses.push_back(value);
}
void CameraComponent::SetFieldOfView(float value) {
m_fieldOfView = std::clamp(value, 1.0f, 179.0f);
}
@@ -149,22 +206,28 @@ 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=" << (m_colorScalePostProcessEnabled ? 1 : 0) << ";";
os << "colorScalePostProcessScale="
<< m_colorScalePostProcessScale.x << ","
<< m_colorScalePostProcessScale.y << ","
<< m_colorScalePostProcessScale.z << ","
<< m_colorScalePostProcessScale.w << ";";
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]) << ";";
}
}
void CameraComponent::Deserialize(std::istream& is) {
m_skyboxMaterial.Reset();
m_skyboxMaterialPath.clear();
m_skyboxMaterialRef.Reset();
m_colorScalePostProcessDefaultScale = Math::Vector4::One();
m_colorScalePostProcessPasses.clear();
std::string token;
std::string pendingSkyboxMaterialPath;
Resources::AssetRef pendingSkyboxMaterialRef;
bool legacyColorScaleEnabled = false;
size_t colorScalePassCount = 0;
std::vector<Math::Vector4> deserializedColorScalePasses;
while (std::getline(is, token, ';')) {
if (token.empty()) {
continue;
@@ -227,14 +290,22 @@ void CameraComponent::Deserialize(std::istream& is) {
std::istringstream ss(value);
ss >> m_skyboxBottomColor.r >> m_skyboxBottomColor.g >> m_skyboxBottomColor.b >> m_skyboxBottomColor.a;
} else if (key == "colorScalePostProcessEnabled") {
m_colorScalePostProcessEnabled = (std::stoi(value) != 0);
legacyColorScaleEnabled = (std::stoi(value) != 0);
} else if (key == "colorScalePostProcessScale") {
std::replace(value.begin(), value.end(), ',', ' ');
std::istringstream ss(value);
ss >> m_colorScalePostProcessScale.x
>> m_colorScalePostProcessScale.y
>> m_colorScalePostProcessScale.z
>> m_colorScalePostProcessScale.w;
TryParseVector4(value, m_colorScalePostProcessDefaultScale);
} else if (key == "colorScalePostProcessPassCount") {
colorScalePassCount = static_cast<size_t>(std::stoul(value));
deserializedColorScalePasses.clear();
deserializedColorScalePasses.resize(colorScalePassCount, Math::Vector4::One());
} else if (key.rfind("colorScalePostProcessPass", 0) == 0) {
const std::string indexString = key.substr(std::string("colorScalePostProcessPass").size());
if (!indexString.empty()) {
const size_t index = static_cast<size_t>(std::stoul(indexString));
if (index >= deserializedColorScalePasses.size()) {
deserializedColorScalePasses.resize(index + 1, Math::Vector4::One());
}
TryParseVector4(value, deserializedColorScalePasses[index]);
}
}
}
@@ -259,6 +330,12 @@ void CameraComponent::Deserialize(std::istream& is) {
if (m_skyboxMaterial.Get() == nullptr && pendingSkyboxMaterialRef.IsValid()) {
m_skyboxMaterialRef = pendingSkyboxMaterialRef;
}
if (!deserializedColorScalePasses.empty()) {
SetColorScalePostProcessPasses(deserializedColorScalePasses);
} else if (legacyColorScaleEnabled) {
SetColorScalePostProcessEnabled(true);
}
}
} // namespace Components

View File

@@ -99,12 +99,16 @@ void SceneRenderer::AttachCameraPostProcessRequests(
for (size_t index = 0; index < requests.size(); ++index) {
CameraRenderRequest& request = requests[index];
if (request.camera == nullptr ||
!request.camera->IsColorScalePostProcessEnabled() ||
request.context.device == nullptr ||
!HasValidColorTarget(request.surface)) {
continue;
}
const std::vector<Math::Vector4>& colorScalePasses = request.camera->GetColorScalePostProcessPasses();
if (colorScalePasses.empty()) {
continue;
}
const std::vector<RHI::RHIResourceView*>& colorAttachments = request.surface.GetColorAttachments();
const RHI::Format colorFormat = colorAttachments[0]->GetFormat();
if (colorFormat == RHI::Format::Unknown) {
@@ -128,8 +132,10 @@ void SceneRenderer::AttachCameraPostProcessRequests(
}
std::unique_ptr<RenderPassSequence> postProcessSequence = std::make_unique<RenderPassSequence>();
postProcessSequence->AddPass(std::make_unique<Passes::BuiltinColorScalePostProcessPass>(
request.camera->GetColorScalePostProcessScale()));
for (const Math::Vector4& colorScale : colorScalePasses) {
postProcessSequence->AddPass(
std::make_unique<Passes::BuiltinColorScalePostProcessPass>(colorScale));
}
RenderSurface sourceSurface = sourceEntry->surface;
sourceSurface.SetDepthAttachment(request.surface.GetDepthAttachment());