Skip to content

Commit

Permalink
[Render/RenderSystem] The XR view buffers are copied to the window
Browse files Browse the repository at this point in the history
- This is done through a simple dedicated passthrough render pass, taking the rendered buffers as input and the default framebuffer as output
  - Blitting to the default framebuffer isn't possible due to possibly different buffer dimensions and formats
  • Loading branch information
Razakhel committed Nov 13, 2024
1 parent 5db2cb4 commit 0ee6928
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 8 deletions.
4 changes: 3 additions & 1 deletion examples/xrDemo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ int main() {
Raz::Application app;
Raz::World& world = app.addWorld();

auto& render = world.addSystem<Raz::RenderSystem>(1280, 720, "RaZ");
// Dimensions of [2468, 2584] (definition of each view of the Meta Quest 2) divided by 3
auto& render = world.addSystem<Raz::RenderSystem>(823, 861, "RaZ", Raz::WindowSetting::NON_RESIZABLE);

Raz::Window& window = render.getWindow();

window.addKeyCallback(Raz::Keyboard::ESCAPE, [&app] (float) noexcept { app.quit(); });
Expand Down
1 change: 1 addition & 0 deletions include/RaZ/Render/RenderSystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class RenderSystem final : public System {
#if defined(RAZ_USE_XR)
void renderXrFrame();
#endif
void copyToWindow(const Texture2D& colorBuffer, const Texture2D& depthBuffer, unsigned int windowWidth, unsigned int windowHeight) const;

unsigned int m_sceneWidth {};
unsigned int m_sceneHeight {};
Expand Down
74 changes: 67 additions & 7 deletions src/RaZ/Render/RenderSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ void RenderSystem::updateLight(const Entity& entity, unsigned int lightIndex) co

#if defined(RAZ_USE_XR)
void RenderSystem::renderXrFrame() {
ZoneScopedN("RenderSystem::renderXrFrame");
TracyGpuZone("RenderSystem::renderXrFrame")

m_xrSystem->renderFrame([this] (const Vec3f& position, const Quaternionf& rotation, const ViewFov& viewFov) {
Mat4f invViewMat = rotation.computeMatrix();
invViewMat.getElement(3, 0) = position.x();
Expand All @@ -312,17 +315,17 @@ void RenderSystem::renderXrFrame() {
constexpr float nearZ = 0.1f;
constexpr float farZ = 1000.f;
constexpr float invDepthDiff = 1.f / (farZ - nearZ);
const Mat4f projMatrix(2.f * invAngleWidth, 0.f, angleWidthDiff * invAngleWidth, 0.f,
0.f, 2.f * invAngleHeight, angleHeightDiff * invAngleHeight, 0.f,
0.f, 0.f, -(farZ + nearZ) * invDepthDiff, -(farZ * (nearZ + nearZ)) * invDepthDiff,
0.f, 0.f, -1.f, 0.f);
const Mat4f projMat(2.f * invAngleWidth, 0.f, angleWidthDiff * invAngleWidth, 0.f,
0.f, 2.f * invAngleHeight, angleHeightDiff * invAngleHeight, 0.f,
0.f, 0.f, -(farZ + nearZ) * invDepthDiff, -(farZ * (nearZ + nearZ)) * invDepthDiff,
0.f, 0.f, -1.f, 0.f);

m_cameraUbo.bind();
sendViewMatrix(viewMat);
sendInverseViewMatrix(invViewMat);
sendProjectionMatrix(projMatrix);
sendInverseProjectionMatrix(projMatrix.inverse());
sendViewProjectionMatrix(projMatrix * viewMat);
sendProjectionMatrix(projMat);
sendInverseProjectionMatrix(projMat.inverse());
sendViewProjectionMatrix(projMat * viewMat);
sendCameraPosition(position);

m_renderGraph.execute(*this);
Expand All @@ -331,7 +334,64 @@ void RenderSystem::renderXrFrame() {
const Framebuffer& geomFramebuffer = m_renderGraph.m_geometryPass.getFramebuffer();
return std::make_pair(std::cref(geomFramebuffer.getColorBuffer(0)), std::cref(geomFramebuffer.getDepthBuffer()));
});

#if !defined(RAZ_NO_WINDOW)
// TODO: the copied color buffer must be the one from the render pass executed last
const Framebuffer& geomFramebuffer = m_renderGraph.m_geometryPass.getFramebuffer();
copyToWindow(geomFramebuffer.getColorBuffer(0), geomFramebuffer.getDepthBuffer(), m_window->getWidth(), m_window->getHeight());
#endif
}
#endif

void RenderSystem::copyToWindow(const Texture2D& colorBuffer, const Texture2D& depthBuffer, unsigned int windowWidth, unsigned int windowHeight) const {
assert("Error: The given color buffer must have a valid & non-depth colorspace to be copied to the window."
&& colorBuffer.getColorspace() != TextureColorspace::DEPTH && colorBuffer.getColorspace() != TextureColorspace::INVALID);
assert("Error: The given depth buffer must have a depth colorspace to be copied to the window."
&& depthBuffer.getColorspace() == TextureColorspace::DEPTH);

ZoneScopedN("RenderSystem::copyToWindow");
TracyGpuZone("RenderSystem::copyToWindow")

static RenderPass windowCopyPass = [] () {
RenderPass copyPass(FragmentShader::loadFromSource(R"(
in vec2 fragTexcoords;
uniform sampler2D uniFinalColorBuffer;
uniform sampler2D uniFinalDepthBuffer;
uniform vec2 uniSizeFactor;
layout(location = 0) out vec4 fragColor;
void main() {
vec2 scaledUv = fragTexcoords * uniSizeFactor;
fragColor = texture(uniFinalColorBuffer, scaledUv).rgba;
gl_FragDepth = texture(uniFinalDepthBuffer, scaledUv).r;
}
)"), "Window copy pass");

RenderShaderProgram& copyProgram = copyPass.getProgram();
copyProgram.setAttribute(0, "uniFinalColorBuffer");
copyProgram.setAttribute(1, "uniFinalDepthBuffer");

return copyPass;
}();

RenderShaderProgram& windowCopyProgram = windowCopyPass.getProgram();

const Vec2f sizeFactor(static_cast<float>(m_sceneWidth) / static_cast<float>(windowWidth),
static_cast<float>(m_sceneHeight) / static_cast<float>(windowHeight));
windowCopyProgram.setAttribute(sizeFactor, "uniSizeFactor");
windowCopyProgram.sendAttributes();

windowCopyProgram.use();
Renderer::activateTexture(0);
colorBuffer.bind();
Renderer::activateTexture(1);
depthBuffer.bind();

Renderer::bindFramebuffer(0);
Renderer::clear(MaskType::COLOR | MaskType::DEPTH | MaskType::STENCIL);
windowCopyPass.execute();
}

} // namespace Raz

0 comments on commit 0ee6928

Please sign in to comment.