From 455567fef1258e99d14614f5ac3d0dc1e16014dd Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Wed, 29 Apr 2026 13:02:23 -0500 Subject: [PATCH] implement new 1.2 spec aspect parameter behavior --- devices/rtx/device/camera/Camera.cpp | 38 +++++++++++++------ devices/rtx/device/camera/Camera.h | 19 +++++++--- devices/rtx/device/camera/Orthographic.cpp | 29 ++++++++------ devices/rtx/device/camera/Orthographic.h | 4 ++ devices/rtx/device/camera/Perspective.cpp | 36 ++++++++++-------- devices/rtx/device/camera/Perspective.h | 8 ++++ devices/rtx/device/frame/Frame.cu | 3 +- devices/rtx/device/gpu/cameraCreateRay.h | 16 ++++---- devices/rtx/device/gpu/gpu_objects.h | 4 +- .../pipeline/passes/AnariSceneRenderPass.cpp | 34 ++++++++++++----- .../pipeline/passes/AnariSceneRenderPass.h | 3 ++ tsd/src/tsd/ui/imgui/windows/BaseViewport.cpp | 13 +++++++ tsd/src/tsd/ui/imgui/windows/BaseViewport.h | 2 + tsd/src/tsd/ui/imgui/windows/Viewport.cpp | 8 ++++ tsd/src/tsd/ui/imgui/windows/Viewport.h | 1 + 15 files changed, 153 insertions(+), 65 deletions(-) diff --git a/devices/rtx/device/camera/Camera.cpp b/devices/rtx/device/camera/Camera.cpp index 57becdad1..6cb2d6fe2 100644 --- a/devices/rtx/device/camera/Camera.cpp +++ b/devices/rtx/device/camera/Camera.cpp @@ -45,9 +45,24 @@ Camera::Camera(DeviceGlobalState *s) : Object(ANARI_CAMERA, s) s->commitBuffer.addObjectToCommit(this); } -void Camera::finalize() +void Camera::commitParameters() { - upload(); + m_region = vec4(0.f, 0.f, 1.f, 1.f); + getParam("imageRegion", ANARI_FLOAT32_BOX2, &m_region); + m_pos = getParam("position", vec3(0.f)); + m_dir = normalize(getParam("direction", vec3(0.f, 0.f, 1.f))); + m_up = normalize(getParam("up", vec3(0.f, 1.f, 0.f))); + + m_aspect.reset(); + float aspect = 1.f; + if (getParam("aspect", ANARI_FLOAT32, &aspect)) + m_aspect = aspect; +} + +void Camera::populateFrameData(CameraGPUData &fd, uvec2 /*frameSize*/) const +{ + populateBaseFrameData(fd); + fd.type = CameraType::UNKNOWN; } Camera *Camera::createInstance(std::string_view subtype, DeviceGlobalState *d) @@ -60,19 +75,20 @@ Camera *Camera::createInstance(std::string_view subtype, DeviceGlobalState *d) return new UnknownCamera(subtype, d); } -void *Camera::deviceData() const +void Camera::populateBaseFrameData(CameraGPUData &fd) const { - return DeviceObject::deviceData(); + fd.region = m_region; + fd.pos = m_pos; + fd.dir = m_dir; + fd.up = m_up; } -void Camera::readBaseParameters(CameraGPUData &hd) +float Camera::effectiveAspect(uvec2 frameSize) const { - vec4 region = vec4(0.f, 0.f, 1.f, 1.f); - getParam("imageRegion", ANARI_FLOAT32_BOX2, ®ion); - hd.region = region; - hd.pos = getParam("position", vec3(0.f)); - hd.dir = normalize(getParam("direction", vec3(0.f, 0.f, 1.f))); - hd.up = normalize(getParam("up", vec3(0.f, 1.f, 0.f))); + if (m_aspect) + return *m_aspect; + + return frameSize.y == 0 ? 1.f : float(frameSize.x) / float(frameSize.y); } } // namespace visrtx diff --git a/devices/rtx/device/camera/Camera.h b/devices/rtx/device/camera/Camera.h index 3cd1184f6..6157c4c33 100644 --- a/devices/rtx/device/camera/Camera.h +++ b/devices/rtx/device/camera/Camera.h @@ -33,23 +33,30 @@ #include "Object.h" #include "gpu/gpu_objects.h" -#include "utility/DeviceObject.h" +// std +#include namespace visrtx { -struct Camera : public Object, public DeviceObject +struct Camera : public Object { Camera(DeviceGlobalState *d); ~Camera() override = default; - void finalize() override; + void commitParameters() override; + virtual void populateFrameData(CameraGPUData &fd, uvec2 frameSize) const; static Camera *createInstance(std::string_view subtype, DeviceGlobalState *d); - void *deviceData() const override; - protected: - void readBaseParameters(CameraGPUData &hd); + void populateBaseFrameData(CameraGPUData &fd) const; + float effectiveAspect(uvec2 frameSize) const; + + vec4 m_region{0.f, 0.f, 1.f, 1.f}; + vec3 m_pos{0.f}; + vec3 m_dir{0.f, 0.f, 1.f}; + vec3 m_up{0.f, 1.f, 0.f}; + std::optional m_aspect; }; } // namespace visrtx diff --git a/devices/rtx/device/camera/Orthographic.cpp b/devices/rtx/device/camera/Orthographic.cpp index b5bdf1e2d..1215cc74a 100644 --- a/devices/rtx/device/camera/Orthographic.cpp +++ b/devices/rtx/device/camera/Orthographic.cpp @@ -37,18 +37,23 @@ Orthographic::Orthographic(DeviceGlobalState *s) : Camera(s) {} void Orthographic::commitParameters() { - const float aspect = getParam("aspect", 1.f); - const float height = getParam("height", 1.f); - - vec2 imgPlaneSize(height * aspect, height); - - auto &hd = data(); - readBaseParameters(hd); - hd.type = CameraType::ORTHOGRAPHIC; - auto &o = hd.orthographic; - o.pos_du = normalize(cross(hd.dir, hd.up)) * imgPlaneSize.x; - o.pos_dv = normalize(cross(o.pos_du, hd.dir)) * imgPlaneSize.y; - o.pos_00 = hd.pos - 0.5f * o.pos_du - 0.5f * o.pos_dv; + Camera::commitParameters(); + + m_height = getParam("height", 1.f); +} + +void Orthographic::populateFrameData(CameraGPUData &fd, uvec2 frameSize) const +{ + populateBaseFrameData(fd); + fd.type = CameraType::ORTHOGRAPHIC; + + const float aspect = effectiveAspect(frameSize); + vec2 imgPlaneSize(m_height * aspect, m_height); + + auto &o = fd.orthographic; + o.pos_du = normalize(cross(fd.dir, fd.up)) * imgPlaneSize.x; + o.pos_dv = normalize(cross(o.pos_du, fd.dir)) * imgPlaneSize.y; + o.pos_00 = fd.pos - 0.5f * o.pos_du - 0.5f * o.pos_dv; } } // namespace visrtx diff --git a/devices/rtx/device/camera/Orthographic.h b/devices/rtx/device/camera/Orthographic.h index f5360d4d8..94512e512 100644 --- a/devices/rtx/device/camera/Orthographic.h +++ b/devices/rtx/device/camera/Orthographic.h @@ -39,6 +39,10 @@ struct Orthographic : public Camera { Orthographic(DeviceGlobalState *d); void commitParameters() override; + void populateFrameData(CameraGPUData &fd, uvec2 frameSize) const override; + + private: + float m_height{1.f}; }; } // namespace visrtx diff --git a/devices/rtx/device/camera/Perspective.cpp b/devices/rtx/device/camera/Perspective.cpp index 020901acb..3c29abf05 100644 --- a/devices/rtx/device/camera/Perspective.cpp +++ b/devices/rtx/device/camera/Perspective.cpp @@ -39,31 +39,37 @@ Perspective::Perspective(DeviceGlobalState *s) : Camera(s) {} void Perspective::commitParameters() { - auto &hd = data(); - readBaseParameters(hd); - hd.type = CameraType::PERSPECTIVE; + Camera::commitParameters(); - const float fovy = getParam("fovy", glm::radians(60.f)); - const float aspect = getParam("aspect", 1.f); + m_fovy = getParam("fovy", glm::radians(60.f)); + m_focusDistance = getParam("focusDistance", 1.f); + m_apertureRadius = getParam("apertureRadius", 0.f); +} + +void Perspective::populateFrameData(CameraGPUData &fd, uvec2 frameSize) const +{ + populateBaseFrameData(fd); + fd.type = CameraType::PERSPECTIVE; + + const float aspect = effectiveAspect(frameSize); vec2 imgPlaneSize; - imgPlaneSize.y = 2.f * tanf(0.5f * fovy); + imgPlaneSize.y = 2.f * tanf(0.5f * m_fovy); imgPlaneSize.x = imgPlaneSize.y * aspect; - vec3 dir_du = normalize(cross(hd.dir, hd.up)) * imgPlaneSize.x; - vec3 dir_dv = normalize(cross(dir_du, hd.dir)) * imgPlaneSize.y; - vec3 dir_00 = hd.dir - .5f * dir_du - .5f * dir_dv; + vec3 dir_du = normalize(cross(fd.dir, fd.up)) * imgPlaneSize.x; + vec3 dir_dv = normalize(cross(dir_du, fd.dir)) * imgPlaneSize.y; + vec3 dir_00 = fd.dir - .5f * dir_du - .5f * dir_dv; - const float focusDistance = getParam("focusDistance", 1.f); const float apertureRadius = - getParam("apertureRadius", 0.f) / (imgPlaneSize.x * focusDistance); + m_apertureRadius / (imgPlaneSize.x * m_focusDistance); if (apertureRadius > 0.f) { - dir_du *= focusDistance; - dir_dv *= focusDistance; - dir_00 *= focusDistance; + dir_du *= m_focusDistance; + dir_dv *= m_focusDistance; + dir_00 *= m_focusDistance; } - auto &p = hd.perspective; + auto &p = fd.perspective; p.dir_du = dir_du; p.dir_dv = dir_dv; p.dir_00 = dir_00; diff --git a/devices/rtx/device/camera/Perspective.h b/devices/rtx/device/camera/Perspective.h index 460f7dd8a..f468a9d25 100644 --- a/devices/rtx/device/camera/Perspective.h +++ b/devices/rtx/device/camera/Perspective.h @@ -32,6 +32,8 @@ #pragma once #include "camera/Camera.h" +// glm +#include namespace visrtx { @@ -39,6 +41,12 @@ struct Perspective : public Camera { Perspective(DeviceGlobalState *d); void commitParameters() override; + void populateFrameData(CameraGPUData &fd, uvec2 frameSize) const override; + + private: + float m_fovy{glm::radians(60.f)}; + float m_focusDistance{1.f}; + float m_apertureRadius{0.f}; }; } // namespace visrtx diff --git a/devices/rtx/device/frame/Frame.cu b/devices/rtx/device/frame/Frame.cu index 71a2ba9ae..0b6e20a57 100644 --- a/devices/rtx/device/frame/Frame.cu +++ b/devices/rtx/device/frame/Frame.cu @@ -519,8 +519,7 @@ void Frame::renderFrame() cudaEventRecord(m_eventStart, state.stream); m_renderer->populateFrameData(hd); - - hd.camera = (CameraGPUData *)m_camera->deviceData(); + m_camera->populateFrameData(hd.camera, hd.fb.size); hd.world = m_world->gpuData(); hd.registry.samplers = state.registry.samplers.devicePtr(); diff --git a/devices/rtx/device/gpu/cameraCreateRay.h b/devices/rtx/device/gpu/cameraCreateRay.h index 8ea6b6141..d4aed1c99 100644 --- a/devices/rtx/device/gpu/cameraCreateRay.h +++ b/devices/rtx/device/gpu/cameraCreateRay.h @@ -35,17 +35,17 @@ namespace visrtx { -VISRTX_DEVICE Ray cameraCreateRay(const CameraGPUData *c, vec2 screen, vec2 r) +VISRTX_DEVICE Ray cameraCreateRay(const CameraGPUData &c, vec2 screen, vec2 r) { Ray ray; - screen.x = glm::mix(c->region[0], c->region[2], screen.x); - screen.y = glm::mix(c->region[1], c->region[3], screen.y); + screen.x = glm::mix(c.region[0], c.region[2], screen.x); + screen.y = glm::mix(c.region[1], c.region[3], screen.y); - switch (c->type) { + switch (c.type) { case CameraType::PERSPECTIVE: { - const auto &p = c->perspective; - ray.org = c->pos; + const auto &p = c.perspective; + ray.org = c.pos; ray.dir = p.dir_00 + screen.x * p.dir_du + screen.y * p.dir_dv; if (p.scaledAperture > 0.f) { @@ -59,8 +59,8 @@ VISRTX_DEVICE Ray cameraCreateRay(const CameraGPUData *c, vec2 screen, vec2 r) break; } case CameraType::ORTHOGRAPHIC: { - const auto &o = c->orthographic; - ray.dir = c->dir; + const auto &o = c.orthographic; + ray.dir = c.dir; ray.org = o.pos_00 + screen.x * o.pos_du + screen.y * o.pos_dv; break; } diff --git a/devices/rtx/device/gpu/gpu_objects.h b/devices/rtx/device/gpu/gpu_objects.h index f1197856a..90db9aeca 100644 --- a/devices/rtx/device/gpu/gpu_objects.h +++ b/devices/rtx/device/gpu/gpu_objects.h @@ -105,7 +105,7 @@ struct OrthographicCameraGPUData struct CameraGPUData { - CameraType type{CameraType::UNKNOWN}; + CameraType type; vec4 region; vec3 pos; vec3 dir; @@ -774,7 +774,7 @@ struct FrameGPUData FramebufferGPUData fb; RendererGPUData renderer; WorldGPUData world; - CameraGPUData *camera; + CameraGPUData camera; // Objects // diff --git a/tsd/src/tsd/rendering/pipeline/passes/AnariSceneRenderPass.cpp b/tsd/src/tsd/rendering/pipeline/passes/AnariSceneRenderPass.cpp index 643fe5f78..2ce15720b 100644 --- a/tsd/src/tsd/rendering/pipeline/passes/AnariSceneRenderPass.cpp +++ b/tsd/src/tsd/rendering/pipeline/passes/AnariSceneRenderPass.cpp @@ -80,11 +80,7 @@ void AnariSceneRenderPass::setCamera(anari::Camera c) anari::commitParameters(m_device, m_frame); anari::release(m_device, m_camera); m_camera = c; - if (m_camera) { - auto size = getDimensions(); - anari::setParameter(m_device, m_camera, "aspect", size.x / float(size.y)); - anari::commitParameters(m_device, m_camera); - } + updateCameraAspect(); } void AnariSceneRenderPass::setRenderer(anari::Renderer r) @@ -217,6 +213,15 @@ void AnariSceneRenderPass::setEnableNormals(bool on) anari::commitParameters(m_device, m_frame); } +void AnariSceneRenderPass::setUseImplicitAspectRatio(bool on) +{ + if (on == m_useImplicitAspectRatio) + return; + + m_useImplicitAspectRatio = on; + updateCameraAspect(); +} + void AnariSceneRenderPass::startFirstFrame(bool waitForCompletion) { if (!m_firstFrame) @@ -240,6 +245,20 @@ anari::Frame AnariSceneRenderPass::getFrame() const return m_frame; } +void AnariSceneRenderPass::updateCameraAspect() +{ + auto size = getDimensions(); + if (!m_camera || size.y == 0) + return; + + if (m_useImplicitAspectRatio) + anari::unsetParameter(m_device, m_camera, "aspect"); + else + anari::setParameter(m_device, m_camera, "aspect", size.x / float(size.y)); + + anari::commitParameters(m_device, m_camera); +} + void AnariSceneRenderPass::updateSize() { cleanup(); @@ -247,10 +266,7 @@ void AnariSceneRenderPass::updateSize() anari::setParameter(m_device, m_frame, "size", size); anari::commitParameters(m_device, m_frame); - if (m_camera) { - anari::setParameter(m_device, m_camera, "aspect", size.x / float(size.y)); - anari::commitParameters(m_device, m_camera); - } + updateCameraAspect(); const size_t totalSize = size_t(size.x) * size_t(size.y); m_buffers.color = detail::allocate(totalSize); diff --git a/tsd/src/tsd/rendering/pipeline/passes/AnariSceneRenderPass.h b/tsd/src/tsd/rendering/pipeline/passes/AnariSceneRenderPass.h index 714a1cac9..bb0eb4381 100644 --- a/tsd/src/tsd/rendering/pipeline/passes/AnariSceneRenderPass.h +++ b/tsd/src/tsd/rendering/pipeline/passes/AnariSceneRenderPass.h @@ -33,6 +33,7 @@ struct AnariSceneRenderPass : public ImagePass void setEnableInstanceId(bool on); void setEnableAlbedo(bool on); void setEnableNormals(bool on); + void setUseImplicitAspectRatio(bool on); void startFirstFrame(bool waitForCompletion = false); @@ -43,6 +44,7 @@ struct AnariSceneRenderPass : public ImagePass private: void updateSize() override; + void updateCameraAspect(); void render(ImageBuffers &b, int stageId) override; void copyFrameData(); void composite(ImageBuffers &b, int stageId); @@ -58,6 +60,7 @@ struct AnariSceneRenderPass : public ImagePass bool m_enableAlbedo{false}; bool m_enableNormals{false}; bool m_runAsync{true}; + bool m_useImplicitAspectRatio{false}; anari::DataType m_format{ANARI_UFIXED8_RGBA_SRGB}; diff --git a/tsd/src/tsd/ui/imgui/windows/BaseViewport.cpp b/tsd/src/tsd/ui/imgui/windows/BaseViewport.cpp index 5dba8bb8f..0199792d8 100644 --- a/tsd/src/tsd/ui/imgui/windows/BaseViewport.cpp +++ b/tsd/src/tsd/ui/imgui/windows/BaseViewport.cpp @@ -39,6 +39,7 @@ void BaseViewport::saveSettings(tsd::core::DataNode &root) root["viewport.scale"] = m_viewport.resolutionScale; root["viewport.showTimeSlider"] = m_showAnimationSlider; root["viewport.showOrientationWidget"] = m_showOrientationWidget; + root["camera.useImplicitAspectRatio"] = m_camera.useImplicitAspectRatio; // Gizmo settings // @@ -55,6 +56,9 @@ void BaseViewport::loadSettings(tsd::core::DataNode &root) root["viewport.showTimeSlider"].getValue(ANARI_BOOL, &m_showAnimationSlider); root["viewport.showOrientationWidget"].getValue( ANARI_BOOL, &m_showOrientationWidget); + root["camera.useImplicitAspectRatio"].getValue( + ANARI_BOOL, &m_camera.useImplicitAspectRatio); + camera_setUseImplicitAspectRatio(m_camera.useImplicitAspectRatio); // Gizmo settings // @@ -141,6 +145,11 @@ void BaseViewport::camera_setCurrent(tsd::scene::CameraAppRef c) m_camera.current = c; } +void BaseViewport::camera_setUseImplicitAspectRatio(bool on) +{ + m_camera.useImplicitAspectRatio = on; +} + bool BaseViewport::gizmo_canShow() const { if (!m_gizmo.active || !viewport_isActive()) @@ -596,6 +605,10 @@ void BaseViewport::ui_menubar_Camera() ImGui::EndMenu(); } + ImGui::Separator(); + if (ImGui::Checkbox("Use Implicit Aspect Ratio", + &m_camera.useImplicitAspectRatio)) + camera_setUseImplicitAspectRatio(m_camera.useImplicitAspectRatio); ImGui::Separator(); tsd::ui::buildUI_object(*m_camera.current, scene, true); ImGui::Unindent(INDENT_AMOUNT); diff --git a/tsd/src/tsd/ui/imgui/windows/BaseViewport.h b/tsd/src/tsd/ui/imgui/windows/BaseViewport.h index de4ac0e22..2989db2fa 100644 --- a/tsd/src/tsd/ui/imgui/windows/BaseViewport.h +++ b/tsd/src/tsd/ui/imgui/windows/BaseViewport.h @@ -50,6 +50,7 @@ struct BaseViewport : public Window void camera_update(bool force = false); void camera_setCurrent(tsd::scene::CameraAppRef c); + virtual void camera_setUseImplicitAspectRatio(bool on); virtual void camera_resetView(bool resetAzEl = true) = 0; virtual void camera_centerView() = 0; @@ -73,6 +74,7 @@ struct BaseViewport : public Window tsd::rendering::Manipulator localArcball; tsd::rendering::Manipulator *arcball{nullptr}; tsd::rendering::UpdateToken arcballToken{0}; + bool useImplicitAspectRatio{false}; } m_camera; struct ViewportState diff --git a/tsd/src/tsd/ui/imgui/windows/Viewport.cpp b/tsd/src/tsd/ui/imgui/windows/Viewport.cpp index 0928a83cd..3d0d844ed 100644 --- a/tsd/src/tsd/ui/imgui/windows/Viewport.cpp +++ b/tsd/src/tsd/ui/imgui/windows/Viewport.cpp @@ -335,6 +335,7 @@ void Viewport::imagePipeline_populate(tsd::rendering::ImagePipeline &p) m_timeToLoadDevice); m_anariPass = p.emplace_back(m_device); + m_anariPass->setUseImplicitAspectRatio(m_camera.useImplicitAspectRatio); m_saveToFilePass = p.emplace_back(); m_saveToFilePass->setEnabled(false); @@ -578,6 +579,13 @@ void Viewport::setSelectionVisibilityFilterEnabled(bool enabled) } } +void Viewport::camera_setUseImplicitAspectRatio(bool on) +{ + BaseViewport::camera_setUseImplicitAspectRatio(on); + if (m_anariPass) + m_anariPass->setUseImplicitAspectRatio(on); +} + void Viewport::updateFrame() { if (m_prevRenderer == m_renderers.current && m_prevCamera == m_camera.current) diff --git a/tsd/src/tsd/ui/imgui/windows/Viewport.h b/tsd/src/tsd/ui/imgui/windows/Viewport.h index 49e35c56d..2f9ea833c 100644 --- a/tsd/src/tsd/ui/imgui/windows/Viewport.h +++ b/tsd/src/tsd/ui/imgui/windows/Viewport.h @@ -56,6 +56,7 @@ struct Viewport : public BaseViewport void imagePipeline_populate(tsd::rendering::ImagePipeline &p) override; + void camera_setUseImplicitAspectRatio(bool on) override; void camera_resetView(bool resetAzEl = true) override; void camera_centerView() override;