feat: add camera viewport rect render areas
This commit is contained in:
@@ -25,6 +25,16 @@ void CameraComponent::SetFarClipPlane(float value) {
|
||||
m_farClipPlane = std::max(m_nearClipPlane + 0.001f, value);
|
||||
}
|
||||
|
||||
void CameraComponent::SetViewportRect(const Math::Rect& value) {
|
||||
const float x = std::clamp(value.x, 0.0f, 1.0f);
|
||||
const float y = std::clamp(value.y, 0.0f, 1.0f);
|
||||
const float width = std::clamp(value.width, 0.0f, 1.0f);
|
||||
const float height = std::clamp(value.height, 0.0f, 1.0f);
|
||||
const float right = std::min(1.0f, x + width);
|
||||
const float bottom = std::min(1.0f, y + height);
|
||||
m_viewportRect = Math::Rect(x, y, right - x, bottom - y);
|
||||
}
|
||||
|
||||
void CameraComponent::Serialize(std::ostream& os) const {
|
||||
os << "projection=" << static_cast<int>(m_projectionType) << ";";
|
||||
os << "fov=" << m_fieldOfView << ";";
|
||||
@@ -35,6 +45,7 @@ void CameraComponent::Serialize(std::ostream& os) const {
|
||||
os << "primary=" << (m_primary ? 1 : 0) << ";";
|
||||
os << "clearMode=" << static_cast<int>(m_clearMode) << ";";
|
||||
os << "cullingMask=" << m_cullingMask << ";";
|
||||
os << "viewportRect=" << m_viewportRect.x << "," << m_viewportRect.y << "," << m_viewportRect.width << "," << m_viewportRect.height << ";";
|
||||
os << "clearColor=" << m_clearColor.r << "," << m_clearColor.g << "," << m_clearColor.b << "," << m_clearColor.a << ";";
|
||||
}
|
||||
|
||||
@@ -71,6 +82,12 @@ void CameraComponent::Deserialize(std::istream& is) {
|
||||
m_clearMode = static_cast<CameraClearMode>(std::stoi(value));
|
||||
} else if (key == "cullingMask") {
|
||||
m_cullingMask = static_cast<uint32_t>(std::stoul(value));
|
||||
} else if (key == "viewportRect") {
|
||||
std::replace(value.begin(), value.end(), ',', ' ');
|
||||
std::istringstream ss(value);
|
||||
Math::Rect viewportRect;
|
||||
ss >> viewportRect.x >> viewportRect.y >> viewportRect.width >> viewportRect.height;
|
||||
SetViewportRect(viewportRect);
|
||||
} else if (key == "clearColor") {
|
||||
std::replace(value.begin(), value.end(), ',', ' ');
|
||||
std::istringstream ss(value);
|
||||
|
||||
@@ -101,11 +101,16 @@ bool CameraRenderer::Render(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (request.surface.GetRenderAreaWidth() == 0 ||
|
||||
request.surface.GetRenderAreaHeight() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderSceneData sceneData = m_sceneExtractor.ExtractForCamera(
|
||||
*request.scene,
|
||||
*request.camera,
|
||||
request.surface.GetWidth(),
|
||||
request.surface.GetHeight());
|
||||
request.surface.GetRenderAreaWidth(),
|
||||
request.surface.GetRenderAreaHeight());
|
||||
if (!sceneData.HasCamera()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -324,19 +324,24 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p
|
||||
renderTargets.data(),
|
||||
surface.GetDepthAttachment());
|
||||
|
||||
const Math::RectInt renderArea = surface.GetRenderArea();
|
||||
if (renderArea.width <= 0 || renderArea.height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const RHI::Viewport viewport = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
static_cast<float>(surface.GetWidth()),
|
||||
static_cast<float>(surface.GetHeight()),
|
||||
static_cast<float>(renderArea.x),
|
||||
static_cast<float>(renderArea.y),
|
||||
static_cast<float>(renderArea.width),
|
||||
static_cast<float>(renderArea.height),
|
||||
0.0f,
|
||||
1.0f
|
||||
};
|
||||
const RHI::Rect scissorRect = {
|
||||
0,
|
||||
0,
|
||||
static_cast<int32_t>(surface.GetWidth()),
|
||||
static_cast<int32_t>(surface.GetHeight())
|
||||
renderArea.x,
|
||||
renderArea.y,
|
||||
renderArea.x + renderArea.width,
|
||||
renderArea.y + renderArea.height
|
||||
};
|
||||
commandList->SetViewport(viewport);
|
||||
commandList->SetScissorRect(scissorRect);
|
||||
|
||||
@@ -1,8 +1,39 @@
|
||||
#include "Rendering/RenderSurface.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
|
||||
namespace {
|
||||
|
||||
Math::RectInt ClampRenderArea(
|
||||
const Math::RectInt& renderArea,
|
||||
uint32_t surfaceWidth,
|
||||
uint32_t surfaceHeight) {
|
||||
const int32_t maxWidth = static_cast<int32_t>(surfaceWidth);
|
||||
const int32_t maxHeight = static_cast<int32_t>(surfaceHeight);
|
||||
|
||||
const int32_t left = std::clamp(renderArea.x, 0, maxWidth);
|
||||
const int32_t top = std::clamp(renderArea.y, 0, maxHeight);
|
||||
const int64_t unclampedRight = static_cast<int64_t>(renderArea.x) +
|
||||
static_cast<int64_t>(std::max(renderArea.width, 0));
|
||||
const int64_t unclampedBottom = static_cast<int64_t>(renderArea.y) +
|
||||
static_cast<int64_t>(std::max(renderArea.height, 0));
|
||||
const int32_t right = std::clamp(
|
||||
static_cast<int32_t>(std::min<int64_t>(unclampedRight, maxWidth)),
|
||||
left,
|
||||
maxWidth);
|
||||
const int32_t bottom = std::clamp(
|
||||
static_cast<int32_t>(std::min<int64_t>(unclampedBottom, maxHeight)),
|
||||
top,
|
||||
maxHeight);
|
||||
return Math::RectInt(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RenderSurface::RenderSurface(uint32_t width, uint32_t height)
|
||||
: m_width(width)
|
||||
, m_height(height) {
|
||||
@@ -11,6 +42,9 @@ RenderSurface::RenderSurface(uint32_t width, uint32_t height)
|
||||
void RenderSurface::SetSize(uint32_t width, uint32_t height) {
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
if (m_hasCustomRenderArea) {
|
||||
m_renderArea = ClampRenderArea(m_renderArea, m_width, m_height);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderSurface::SetColorAttachment(RHI::RHIResourceView* colorAttachment) {
|
||||
@@ -24,6 +58,32 @@ void RenderSurface::SetColorAttachments(const std::vector<RHI::RHIResourceView*>
|
||||
m_colorAttachments = colorAttachments;
|
||||
}
|
||||
|
||||
void RenderSurface::SetRenderArea(const Math::RectInt& renderArea) {
|
||||
m_renderArea = ClampRenderArea(renderArea, m_width, m_height);
|
||||
m_hasCustomRenderArea = true;
|
||||
}
|
||||
|
||||
void RenderSurface::ResetRenderArea() {
|
||||
m_hasCustomRenderArea = false;
|
||||
m_renderArea = {};
|
||||
}
|
||||
|
||||
Math::RectInt RenderSurface::GetRenderArea() const {
|
||||
if (!m_hasCustomRenderArea) {
|
||||
return Math::RectInt(0, 0, static_cast<int32_t>(m_width), static_cast<int32_t>(m_height));
|
||||
}
|
||||
|
||||
return ClampRenderArea(m_renderArea, m_width, m_height);
|
||||
}
|
||||
|
||||
uint32_t RenderSurface::GetRenderAreaWidth() const {
|
||||
return static_cast<uint32_t>(std::max(GetRenderArea().width, 0));
|
||||
}
|
||||
|
||||
uint32_t RenderSurface::GetRenderAreaHeight() const {
|
||||
return static_cast<uint32_t>(std::max(GetRenderArea().height, 0));
|
||||
}
|
||||
|
||||
void RenderSurface::SetClearColorOverride(const Math::Color& clearColor) {
|
||||
m_hasClearColorOverride = true;
|
||||
m_clearColorOverride = clearColor;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Scene/Scene.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
@@ -40,6 +41,20 @@ RenderClearFlags ResolveClearFlags(const Components::CameraComponent& camera, si
|
||||
}
|
||||
}
|
||||
|
||||
Math::RectInt ResolveCameraRenderArea(
|
||||
const Components::CameraComponent& camera,
|
||||
const RenderSurface& surface) {
|
||||
const Math::Rect viewportRect = camera.GetViewportRect();
|
||||
const float surfaceWidth = static_cast<float>(surface.GetWidth());
|
||||
const float surfaceHeight = static_cast<float>(surface.GetHeight());
|
||||
|
||||
const int32_t left = static_cast<int32_t>(std::floor(viewportRect.x * surfaceWidth));
|
||||
const int32_t top = static_cast<int32_t>(std::floor(viewportRect.y * surfaceHeight));
|
||||
const int32_t right = static_cast<int32_t>(std::ceil((viewportRect.x + viewportRect.width) * surfaceWidth));
|
||||
const int32_t bottom = static_cast<int32_t>(std::ceil((viewportRect.y + viewportRect.height) * surfaceHeight));
|
||||
return Math::RectInt(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SceneRenderer::SceneRenderer() = default;
|
||||
@@ -101,9 +116,13 @@ std::vector<CameraRenderRequest> SceneRenderer::BuildRenderRequests(
|
||||
request.camera = camera;
|
||||
request.context = context;
|
||||
request.surface = surface;
|
||||
request.surface.SetRenderArea(ResolveCameraRenderArea(*camera, surface));
|
||||
request.cameraDepth = camera->GetDepth();
|
||||
request.clearFlags = ResolveClearFlags(*camera, cameraIndex);
|
||||
requests.push_back(request);
|
||||
if (request.surface.GetRenderAreaWidth() > 0 &&
|
||||
request.surface.GetRenderAreaHeight() > 0) {
|
||||
requests.push_back(request);
|
||||
}
|
||||
}
|
||||
|
||||
return requests;
|
||||
|
||||
Reference in New Issue
Block a user