feat: add explicit camera clear modes
This commit is contained in:
@@ -11,6 +11,13 @@ enum class CameraProjectionType {
|
||||
Orthographic
|
||||
};
|
||||
|
||||
enum class CameraClearMode {
|
||||
Auto = 0,
|
||||
ColorAndDepth,
|
||||
DepthOnly,
|
||||
None
|
||||
};
|
||||
|
||||
class CameraComponent : public Component {
|
||||
public:
|
||||
std::string GetName() const override { return "Camera"; }
|
||||
@@ -36,6 +43,9 @@ public:
|
||||
bool IsPrimary() const { return m_primary; }
|
||||
void SetPrimary(bool value) { m_primary = value; }
|
||||
|
||||
CameraClearMode GetClearMode() const { return m_clearMode; }
|
||||
void SetClearMode(CameraClearMode value) { m_clearMode = value; }
|
||||
|
||||
const Math::Color& GetClearColor() const { return m_clearColor; }
|
||||
void SetClearColor(const Math::Color& value) { m_clearColor = value; }
|
||||
|
||||
@@ -50,6 +60,7 @@ private:
|
||||
float m_farClipPlane = 1000.0f;
|
||||
float m_depth = 0.0f;
|
||||
bool m_primary = true;
|
||||
CameraClearMode m_clearMode = CameraClearMode::Auto;
|
||||
Math::Color m_clearColor = Math::Color(0.192f, 0.302f, 0.475f, 1.0f);
|
||||
};
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ void CameraComponent::Serialize(std::ostream& os) const {
|
||||
os << "far=" << m_farClipPlane << ";";
|
||||
os << "depth=" << m_depth << ";";
|
||||
os << "primary=" << (m_primary ? 1 : 0) << ";";
|
||||
os << "clearMode=" << static_cast<int>(m_clearMode) << ";";
|
||||
os << "clearColor=" << m_clearColor.r << "," << m_clearColor.g << "," << m_clearColor.b << "," << m_clearColor.a << ";";
|
||||
}
|
||||
|
||||
@@ -65,6 +66,8 @@ void CameraComponent::Deserialize(std::istream& is) {
|
||||
m_depth = std::stof(value);
|
||||
} else if (key == "primary") {
|
||||
m_primary = (std::stoi(value) != 0);
|
||||
} else if (key == "clearMode") {
|
||||
m_clearMode = static_cast<CameraClearMode>(std::stoi(value));
|
||||
} else if (key == "clearColor") {
|
||||
std::replace(value.begin(), value.end(), ',', ' ');
|
||||
std::istringstream ss(value);
|
||||
|
||||
@@ -26,6 +26,20 @@ bool IsUsableCamera(const Components::CameraComponent* camera) {
|
||||
camera->GetGameObject()->IsActiveInHierarchy();
|
||||
}
|
||||
|
||||
RenderClearFlags ResolveClearFlags(const Components::CameraComponent& camera, size_t cameraIndex) {
|
||||
switch (camera.GetClearMode()) {
|
||||
case Components::CameraClearMode::ColorAndDepth:
|
||||
return RenderClearFlags::All;
|
||||
case Components::CameraClearMode::DepthOnly:
|
||||
return RenderClearFlags::Depth;
|
||||
case Components::CameraClearMode::None:
|
||||
return RenderClearFlags::None;
|
||||
case Components::CameraClearMode::Auto:
|
||||
default:
|
||||
return cameraIndex == 0 ? RenderClearFlags::All : RenderClearFlags::Depth;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SceneRenderer::SceneRenderer() = default;
|
||||
@@ -88,7 +102,7 @@ std::vector<CameraRenderRequest> SceneRenderer::BuildRenderRequests(
|
||||
request.context = context;
|
||||
request.surface = surface;
|
||||
request.cameraDepth = camera->GetDepth();
|
||||
request.clearFlags = cameraIndex == 0 ? RenderClearFlags::All : RenderClearFlags::Depth;
|
||||
request.clearFlags = ResolveClearFlags(*camera, cameraIndex);
|
||||
requests.push_back(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
#include <XCEngine/Components/LightComponent.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace XCEngine::Components;
|
||||
|
||||
namespace {
|
||||
@@ -16,6 +18,7 @@ TEST(CameraComponent_Test, DefaultValues) {
|
||||
EXPECT_FLOAT_EQ(camera.GetNearClipPlane(), 0.1f);
|
||||
EXPECT_FLOAT_EQ(camera.GetFarClipPlane(), 1000.0f);
|
||||
EXPECT_TRUE(camera.IsPrimary());
|
||||
EXPECT_EQ(camera.GetClearMode(), CameraClearMode::Auto);
|
||||
}
|
||||
|
||||
TEST(CameraComponent_Test, SetterClamping) {
|
||||
@@ -32,6 +35,19 @@ TEST(CameraComponent_Test, SetterClamping) {
|
||||
EXPECT_GT(camera.GetFarClipPlane(), camera.GetNearClipPlane());
|
||||
}
|
||||
|
||||
TEST(CameraComponent_Test, SerializeRoundTripPreservesClearMode) {
|
||||
CameraComponent source;
|
||||
source.SetClearMode(CameraClearMode::DepthOnly);
|
||||
|
||||
std::stringstream stream;
|
||||
source.Serialize(stream);
|
||||
|
||||
CameraComponent target;
|
||||
target.Deserialize(stream);
|
||||
|
||||
EXPECT_EQ(target.GetClearMode(), CameraClearMode::DepthOnly);
|
||||
}
|
||||
|
||||
TEST(LightComponent_Test, DefaultValues) {
|
||||
LightComponent light;
|
||||
|
||||
|
||||
@@ -287,6 +287,7 @@ TEST(SceneRenderer_Test, BuildsSortedRequestsForAllUsableCamerasAndHonorsOverrid
|
||||
auto* highCamera = highCameraObject->AddComponent<CameraComponent>();
|
||||
highCamera->SetPrimary(true);
|
||||
highCamera->SetDepth(5.0f);
|
||||
highCamera->SetClearMode(CameraClearMode::None);
|
||||
|
||||
SceneRenderer renderer;
|
||||
const RenderContext context = CreateValidContext();
|
||||
@@ -302,7 +303,7 @@ TEST(SceneRenderer_Test, BuildsSortedRequestsForAllUsableCamerasAndHonorsOverrid
|
||||
EXPECT_EQ(defaultRequests[0].surface.GetHeight(), 180u);
|
||||
EXPECT_EQ(defaultRequests[1].camera, highCamera);
|
||||
EXPECT_EQ(defaultRequests[1].cameraDepth, 5.0f);
|
||||
EXPECT_EQ(defaultRequests[1].clearFlags, RenderClearFlags::Depth);
|
||||
EXPECT_EQ(defaultRequests[1].clearFlags, RenderClearFlags::None);
|
||||
|
||||
const std::vector<CameraRenderRequest> overrideRequests =
|
||||
renderer.BuildRenderRequests(scene, lowCamera, context, surface);
|
||||
@@ -311,6 +312,24 @@ TEST(SceneRenderer_Test, BuildsSortedRequestsForAllUsableCamerasAndHonorsOverrid
|
||||
EXPECT_EQ(overrideRequests[0].clearFlags, RenderClearFlags::All);
|
||||
}
|
||||
|
||||
TEST(SceneRenderer_Test, HonorsExplicitOverrideCameraClearMode) {
|
||||
Scene scene("SceneRendererOverrideClearModeScene");
|
||||
|
||||
GameObject* cameraObject = scene.CreateGameObject("Camera");
|
||||
auto* camera = cameraObject->AddComponent<CameraComponent>();
|
||||
camera->SetPrimary(true);
|
||||
camera->SetDepth(2.0f);
|
||||
camera->SetClearMode(CameraClearMode::DepthOnly);
|
||||
|
||||
SceneRenderer renderer;
|
||||
const std::vector<CameraRenderRequest> requests =
|
||||
renderer.BuildRenderRequests(scene, camera, CreateValidContext(), RenderSurface(640, 360));
|
||||
|
||||
ASSERT_EQ(requests.size(), 1u);
|
||||
EXPECT_EQ(requests[0].camera, camera);
|
||||
EXPECT_EQ(requests[0].clearFlags, RenderClearFlags::Depth);
|
||||
}
|
||||
|
||||
TEST(SceneRenderer_Test, ForwardsPipelineLifetimeAndRenderCallsToCameraRenderer) {
|
||||
Scene scene("SceneRendererScene");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user