From 7ce37e0b32d0c77dd79e212da6423786a448f0f7 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Sun, 20 Oct 2024 17:59:29 +0200 Subject: [PATCH 01/83] add CCubeProjection.hpp, ILinearProjection.hpp & IProjection.hpp headers (temporary to common/include/camera directory) --- common/include/camera/CCubeProjection.hpp | 31 +++++++++++++++++++++ common/include/camera/ILinearProjection.hpp | 28 +++++++++++++++++++ common/include/camera/IProjection.hpp | 24 ++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 common/include/camera/CCubeProjection.hpp create mode 100644 common/include/camera/ILinearProjection.hpp create mode 100644 common/include/camera/IProjection.hpp diff --git a/common/include/camera/CCubeProjection.hpp b/common/include/camera/CCubeProjection.hpp new file mode 100644 index 000000000..ef3d25d71 --- /dev/null +++ b/common/include/camera/CCubeProjection.hpp @@ -0,0 +1,31 @@ +#ifndef _NBL_CCUBE_PROJECTION_HPP_ +#define _NBL_CCUBE_PROJECTION_HPP_ + +#include "ILinearProjection.hpp" + +namespace nbl::hlsl +{ + +struct CCubeProjectionBase +{ + using base_t = ILinearProjection>; +}; + +//! Class providing linear cube projections with projection matrix per face of a cube, each projection matrix represents a single view-port +class CCubeProjection : public CCubeProjectionBase::base_t +{ +public: + using base_t = typename CCubeProjectionBase::base_t; + using range_t = typename base_t::range_t; + + CCubeProjection(range_t&& matrices = {}) : base_t(std::move(matrices)) {} + + range_t& getCubeFaceProjectionMatrices() + { + return base_t::getViewportMatrices(); + } +}; + +} // nbl::hlsl namespace + +#endif // _NBL_CCUBE_PROJECTION_HPP_ \ No newline at end of file diff --git a/common/include/camera/ILinearProjection.hpp b/common/include/camera/ILinearProjection.hpp new file mode 100644 index 000000000..ba39018a5 --- /dev/null +++ b/common/include/camera/ILinearProjection.hpp @@ -0,0 +1,28 @@ +#ifndef _NBL_ILINEAR_PROJECTION_HPP_ +#define _NBL_ILINEAR_PROJECTION_HPP_ + +#include "IProjection.hpp" + +namespace nbl::hlsl +{ + +//! Interface class for linear projections range storage - a projection matrix represents single view-port +template +class ILinearProjection : protected IProjection +{ +public: + using base_t = typename IProjection; + using range_t = typename base_t::range_t; + + ILinearProjection(range_t&& matrices) : base_t(matrices) {} + +protected: + inline range_t& getViewportMatrices() + { + return base_t::m_projMatrices; + } +}; + +} // nbl::hlsl namespace + +#endif // _NBL_ILINEAR_PROJECTION_HPP_ \ No newline at end of file diff --git a/common/include/camera/IProjection.hpp b/common/include/camera/IProjection.hpp new file mode 100644 index 000000000..164c48b9f --- /dev/null +++ b/common/include/camera/IProjection.hpp @@ -0,0 +1,24 @@ +#ifndef _NBL_IPROJECTION_HPP_ +#define _NBL_IPROJECTION_HPP_ + +#include + +namespace nbl::hlsl +{ +//! Interface class for projection matrices range storage +template> +requires nbl::is_any_of_v, float64_t4x4, float32_t4x4> +class IProjection +{ +public: + using value_t = std::ranges::iterator_t; + using range_t = Range; + +protected: + IProjection(const range_t& matrices) : m_projMatrices(matrices) {} + range_t m_projMatrices; +}; + +} // nbl::hlsl namespace + +#endif // _NBL_IPROJECTION_HPP_ \ No newline at end of file From e2392293550ef5865646617a2cfbf3638bd805e2 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Sun, 20 Oct 2024 19:18:14 +0200 Subject: [PATCH 02/83] add range_value_t to IProjection --- common/include/camera/IProjection.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/include/camera/IProjection.hpp b/common/include/camera/IProjection.hpp index 164c48b9f..d0486c013 100644 --- a/common/include/camera/IProjection.hpp +++ b/common/include/camera/IProjection.hpp @@ -11,8 +11,8 @@ requires nbl::is_any_of_v, float64_t4x4, float class IProjection { public: - using value_t = std::ranges::iterator_t; using range_t = Range; + using range_value_t = std::ranges::range_value_t; protected: IProjection(const range_t& matrices) : m_projMatrices(matrices) {} From 5e039226d73450c2063df5cb5757d71483cce613 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Mon, 21 Oct 2024 14:39:53 +0200 Subject: [PATCH 03/83] create IProjectionRange, pair with IProjection, use concepts for specific range type & projection matrix type constraints, update ILinearProjection and CCubeProjection - now I can pair IProjection with a gimbal --- common/include/camera/CCubeProjection.hpp | 12 +++--- common/include/camera/ILinearProjection.hpp | 11 +++--- common/include/camera/IProjection.hpp | 43 +++++++++++++++++---- 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/common/include/camera/CCubeProjection.hpp b/common/include/camera/CCubeProjection.hpp index ef3d25d71..2e2a91218 100644 --- a/common/include/camera/CCubeProjection.hpp +++ b/common/include/camera/CCubeProjection.hpp @@ -8,7 +8,9 @@ namespace nbl::hlsl struct CCubeProjectionBase { - using base_t = ILinearProjection>; + using projection_t = typename IProjection; + using projection_range_t = std::array; + using base_t = ILinearProjection; }; //! Class providing linear cube projections with projection matrix per face of a cube, each projection matrix represents a single view-port @@ -16,13 +18,13 @@ class CCubeProjection : public CCubeProjectionBase::base_t { public: using base_t = typename CCubeProjectionBase::base_t; - using range_t = typename base_t::range_t; + using projection_range_t = typename base_t::range_t; - CCubeProjection(range_t&& matrices = {}) : base_t(std::move(matrices)) {} + CCubeProjection(projection_range_t&& projections = {}) : base_t(std::move(projections)) {} - range_t& getCubeFaceProjectionMatrices() + projection_range_t& getCubeFaceProjections() { - return base_t::getViewportMatrices(); + return base_t::getViewportProjections(); } }; diff --git a/common/include/camera/ILinearProjection.hpp b/common/include/camera/ILinearProjection.hpp index ba39018a5..3539b153f 100644 --- a/common/include/camera/ILinearProjection.hpp +++ b/common/include/camera/ILinearProjection.hpp @@ -8,18 +8,19 @@ namespace nbl::hlsl //! Interface class for linear projections range storage - a projection matrix represents single view-port template -class ILinearProjection : protected IProjection +class ILinearProjection : protected IProjectionRange { public: - using base_t = typename IProjection; + using base_t = typename IProjectionRange; using range_t = typename base_t::range_t; + using projection_t = typename base_t::projection_t; - ILinearProjection(range_t&& matrices) : base_t(matrices) {} + ILinearProjection(range_t&& projections) : base_t(projections) {} protected: - inline range_t& getViewportMatrices() + inline range_t& getViewportProjections() { - return base_t::m_projMatrices; + return base_t::m_projectionRange; } }; diff --git a/common/include/camera/IProjection.hpp b/common/include/camera/IProjection.hpp index d0486c013..fbd6f43e0 100644 --- a/common/include/camera/IProjection.hpp +++ b/common/include/camera/IProjection.hpp @@ -5,20 +5,49 @@ namespace nbl::hlsl { -//! Interface class for projection matrices range storage -template> -requires nbl::is_any_of_v, float64_t4x4, float32_t4x4> + +template +concept ProjectionMatrix = is_any_of_v; + +//! Interface class for projection +template class IProjection { +public: + using value_t = T; + + IProjection(const value_t& matrix = {}) : m_projectionMatrix(matrix) {} + value_t& getProjectionMatrix() { return m_projectionMatrix; } + +protected: + value_t m_projectionMatrix; +}; + +template +concept ProjectionRange = requires +{ + typename std::ranges::range_value_t; + std::is_base_of_v::value_t>, std::ranges::range_value_t>; +}; + +//! Interface class for a range of IProjection projections +template, 1u>> +class IProjectionRange +{ public: using range_t = Range; - using range_value_t = std::ranges::range_value_t; + using projection_t = std::ranges::range_value_t; + + //! Constructor for the range of projections + IProjectionRange(const range_t& projections) : m_projectionRange(projections) {} + + //! Get the stored range of projections + const range_t& getProjections() const { return m_projectionRange; } protected: - IProjection(const range_t& matrices) : m_projMatrices(matrices) {} - range_t m_projMatrices; + range_t m_projectionRange; }; -} // nbl::hlsl namespace +} // namespace nbl::hlsl #endif // _NBL_IPROJECTION_HPP_ \ No newline at end of file From 6196c611add87683dc2f53b81813976d5b82812d Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Mon, 21 Oct 2024 18:39:36 +0200 Subject: [PATCH 04/83] save draft of CVirtualCameraEvent.hpp & ICameraControl.hpp, update sources, save main.cpp tests, add TODO comments --- 61_UI/main.cpp | 24 ++++ common/include/camera/CCubeProjection.hpp | 19 +-- common/include/camera/CVirtualCameraEvent.hpp | 63 ++++++++++ common/include/camera/ICameraControl.hpp | 117 ++++++++++++++++++ common/include/camera/ILinearProjection.hpp | 2 +- common/include/camera/IProjection.hpp | 14 +-- 6 files changed, 223 insertions(+), 16 deletions(-) create mode 100644 common/include/camera/CVirtualCameraEvent.hpp create mode 100644 common/include/camera/ICameraControl.hpp diff --git a/61_UI/main.cpp b/61_UI/main.cpp index ef03d88d6..37e50805c 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -4,6 +4,10 @@ #include "common.hpp" +#include "camera/CCubeProjection.hpp" +#include "camera/ICameraControl.hpp" +#include "glm/glm/ext/matrix_clip_space.hpp" // TODO: TESTING + /* Renders scene texture to an offline framebuffer which color attachment @@ -489,6 +493,26 @@ class UISampleApp final : public examples::SimpleWindowedApplication oracle.reportBeginFrameRecord(); camera.mapKeysToArrows(); + /* + TESTS, TODO: remove all once finished work & integrate with the example properly + */ + + using cube_projection_t = CCubeProjection; + using constraints_t = CCubeProjection<>::constraints_t; + using camera_control_t = ICameraController; + using gimbal_t = camera_control_t::CGimbal; + + cube_projection_t cubeProjection; // can init all at construction, but will init only first for tests + auto& projections = cubeProjection.getCubeFaceProjections(); + auto firstFaceProjection = projections.front(); + firstFaceProjection = make_smart_refctd_ptr(glm::perspectiveLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar)); + + const float32_t3 position(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance), + target(0.f, 0.f, 0.f), up(0.f, 1.f, 0.f); + + auto gimbal = make_smart_refctd_ptr(smart_refctd_ptr(firstFaceProjection), position, target, up); + auto controller = make_smart_refctd_ptr(smart_refctd_ptr(gimbal)); + return true; } diff --git a/common/include/camera/CCubeProjection.hpp b/common/include/camera/CCubeProjection.hpp index 2e2a91218..e09d01dce 100644 --- a/common/include/camera/CCubeProjection.hpp +++ b/common/include/camera/CCubeProjection.hpp @@ -6,23 +6,26 @@ namespace nbl::hlsl { -struct CCubeProjectionBase +template +struct CCubeProjectionConstraints { - using projection_t = typename IProjection; - using projection_range_t = std::array; + using matrix_t = typename T; + using projection_t = typename IProjection; + using projection_range_t = std::array, 6u>; using base_t = ILinearProjection; }; //! Class providing linear cube projections with projection matrix per face of a cube, each projection matrix represents a single view-port -class CCubeProjection : public CCubeProjectionBase::base_t +template +class CCubeProjection : public CCubeProjectionConstraints::base_t { public: - using base_t = typename CCubeProjectionBase::base_t; - using projection_range_t = typename base_t::range_t; + using constraints_t = CCubeProjectionConstraints; + using base_t = typename constraints_t::base_t; - CCubeProjection(projection_range_t&& projections = {}) : base_t(std::move(projections)) {} + CCubeProjection(constraints_t::projection_range_t&& projections = {}) : base_t(std::move(projections)) {} - projection_range_t& getCubeFaceProjections() + constraints_t::projection_range_t& getCubeFaceProjections() { return base_t::getViewportProjections(); } diff --git a/common/include/camera/CVirtualCameraEvent.hpp b/common/include/camera/CVirtualCameraEvent.hpp new file mode 100644 index 000000000..b91712321 --- /dev/null +++ b/common/include/camera/CVirtualCameraEvent.hpp @@ -0,0 +1,63 @@ +#ifndef _NBL_VIRTUAL_CAMERA_EVENT_HPP_ +#define _NBL_VIRTUAL_CAMERA_EVENT_HPP_ + +#include "nbl/builtin/hlsl/cpp_compat/matrix.hlsl" + +// TODO: DIFFERENT NAMESPACE +namespace nbl::hlsl +{ + +//! Virtual camera event representing a manipulation +enum class VirtualEventType +{ + //! Moves the camera forward or backward + MoveForward, + + //! Zooms in or out + Zoom, + + //! Moves the camera left/right and up/down + Strafe, + + //! Rotates the camera horizontally + Pan, + + //! Rotates the camera vertically + Tilt, + + //! Rolls the camera around the Z axis + Roll, + + //! Resets the camera to a default position and orientation + Reset +}; + +//! We encode all manipulation type values into a vec4 & assume they are written in NDC coordinate system with respect to camera +using manipulation_value_t = float64_t4x4; + +class CVirtualCameraEvent +{ +public: + CVirtualCameraEvent(VirtualEventType type, const manipulation_value_t value) + : type(type), value(value) {} + + // Returns the type of virtual event + VirtualEventType getType() const + { + return type; + } + + // Returns the associated value for manipulation + manipulation_value_t getValue() const + { + return value; + } + +private: + VirtualEventType type; + manipulation_value_t value; +}; + +} + +#endif // _NBL_VIRTUAL_CAMERA_EVENT_HPP_ \ No newline at end of file diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp new file mode 100644 index 000000000..c62871644 --- /dev/null +++ b/common/include/camera/ICameraControl.hpp @@ -0,0 +1,117 @@ +#ifndef _NBL_I_CAMERA_CONTROLLER_HPP_ +#define _NBL_I_CAMERA_CONTROLLER_HPP_ + +#include "IProjection.hpp" +#include "CVirtualCameraEvent.hpp" +#include "glm/glm/ext/matrix_transform.hpp" // TODO: TEMPORARY!!! whatever used will be moved to cpp + +// TODO: DIFFERENT NAMESPACE +namespace nbl::hlsl +{ + +template +class ICameraController : virtual public core::IReferenceCounted +{ +public: + using projection_t = typename IProjection; + + class CGimbal : virtual public core::IReferenceCounted + { + public: + CGimbal(const core::smart_refctd_ptr&& projection, const float32_t3& position, const float32_t3& lookat, const float32_t3& upVec = float32_t3(0.0f, 1.0f, 0.0f), const float32_t3& backupUpVec = float32_t3(0.5f, 1.0f, 0.0f)) + : m_projection(std::move(projection)), m_position(position), m_target(lookat), m_upVec(upVec), m_backupUpVec(backupUpVec), m_initialPosition(position), m_initialTarget(lookat), m_viewMatrix({}), m_isLeftHanded(nbl::hlsl::determinant(m_projection->getProjectionMatrix()) < 0.f) + { + //! I make an assumption that we take ownership of projection (just to make less calculations on gimbal update iterations [but maybe I shouldnt, think of it!]) + recomputeViewMatrix(); + } + + // TODO: ctor with core::path to json config file to load defaults + + const projection_t* getProjection() { return m_projection.get(); } + + // TODO: gimbal methods (to handle VirtualEventType requests) + + private: + inline void recomputeViewMatrix() + { + auto localTarget = glm::normalize(m_target - m_position); + + // If up vector and vector to the target are the same, adjust the up vector + auto up = glm::normalize(m_upVec); + auto cross = glm::cross(localTarget, up); + bool upVectorNeedsChange = glm::dot(cross, cross) == 0; + + if (upVectorNeedsChange) + up = glm::normalize(m_backupUpVec); + + if (m_isLeftHanded) + m_viewMatrix = glm::lookAtLH(m_position, m_target, up); + else + m_viewMatrix = glm::lookAtRH(m_position, m_target, up); + } + + const core::smart_refctd_ptr m_projection; + float32_t3 m_position, m_target, m_upVec, m_backupUpVec; + const float32_t3 m_initialPosition, m_initialTarget; + + float64_t4x4 m_viewMatrix; + const bool m_isLeftHanded; + }; + + ICameraController(core::smart_refctd_ptr&& gimbal) + : m_gimbal(std::move(gimbal)) {} + + void processVirtualEvent(const CVirtualCameraEvent& virtualEvent) + { + // we will treat all manipulation event values as NDC, also for non manipulation events + // we will define how to handle it, all values are encoded onto vec4 (manipulation_value_t) + manipulation_value_t value = virtualEvent.getValue(); + + // TODO: this will use gimbal to handle a virtual event registered by a class (wip) which maps physical keys to virtual events + + case VirtualEventType::MoveForward: + { + // TODO + } break; + + case VirtualEventType::Strafe: + { + // TODO + } break; + + case VirtualEventType::Zoom: + { + // TODO + } break; + + case VirtualEventType::Pan: + { + // TODO + } break; + + case VirtualEventType::Tilt: + { + // TODO + } break; + + case VirtualEventType::Roll: + { + // TODO + } break; + + case VirtualEventType::Reset: + { + // TODO + } break; + + default: + break; + } + +private: + core::smart_refctd_ptr m_gimbal; +}; + +} // nbl::hlsl namespace + +#endif // _NBL_I_CAMERA_CONTROLLER_HPP_ \ No newline at end of file diff --git a/common/include/camera/ILinearProjection.hpp b/common/include/camera/ILinearProjection.hpp index 3539b153f..30a4db358 100644 --- a/common/include/camera/ILinearProjection.hpp +++ b/common/include/camera/ILinearProjection.hpp @@ -15,7 +15,7 @@ class ILinearProjection : protected IProjectionRange using range_t = typename base_t::range_t; using projection_t = typename base_t::projection_t; - ILinearProjection(range_t&& projections) : base_t(projections) {} + ILinearProjection(range_t&& projections) : base_t(std::move(projections)) {} protected: inline range_t& getViewportProjections() diff --git a/common/include/camera/IProjection.hpp b/common/include/camera/IProjection.hpp index fbd6f43e0..f3edfccc4 100644 --- a/common/include/camera/IProjection.hpp +++ b/common/include/camera/IProjection.hpp @@ -1,7 +1,7 @@ #ifndef _NBL_IPROJECTION_HPP_ #define _NBL_IPROJECTION_HPP_ -#include +#include "nbl/builtin/hlsl/cpp_compat/matrix.hlsl" namespace nbl::hlsl { @@ -10,8 +10,8 @@ template concept ProjectionMatrix = is_any_of_v; //! Interface class for projection -template -class IProjection +template +class IProjection : virtual public core::IReferenceCounted { public: using value_t = T; @@ -24,14 +24,14 @@ class IProjection }; template -concept ProjectionRange = requires +concept ProjectionRange = requires { typename std::ranges::range_value_t; - std::is_base_of_v::value_t>, std::ranges::range_value_t>; + // TODO: smart_refctd_ptr check for range_value_t + its type check to grant IProjection }; //! Interface class for a range of IProjection projections -template, 1u>> +template>, 1u>> class IProjectionRange { public: @@ -39,7 +39,7 @@ class IProjectionRange using projection_t = std::ranges::range_value_t; //! Constructor for the range of projections - IProjectionRange(const range_t& projections) : m_projectionRange(projections) {} + IProjectionRange(range_t&& projections) : m_projectionRange(std::move(projections)) {} //! Get the stored range of projections const range_t& getProjections() const { return m_projectionRange; } From fedb9c138fdd41f5713b9b75fc4eeac19dd5d203 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Mon, 21 Oct 2024 13:13:24 -0700 Subject: [PATCH 05/83] Saving work --- 09_GeometryCreator/main.cpp | 20 +++---- common/include/CCamera.hpp | 104 ++++++++++++++++++------------------ 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/09_GeometryCreator/main.cpp b/09_GeometryCreator/main.cpp index 1c7fc0e21..e87ee066b 100644 --- a/09_GeometryCreator/main.cpp +++ b/09_GeometryCreator/main.cpp @@ -2,6 +2,8 @@ // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h +#include +#include #include "common.hpp" class CSwapchainFramebuffersAndDepth final : public nbl::video::CDefaultSwapchainFramebuffers @@ -235,9 +237,9 @@ class GeometryCreatorApp final : public examples::SimpleWindowedApplication // camera { - core::vectorSIMDf cameraPosition(-5.81655884, 2.58630896, -4.23974705); - core::vectorSIMDf cameraTarget(-0.349590302, -0.213266611, 0.317821503); - matrix4SIMD projectionMatrix = matrix4SIMD::buildProjectionMatrixPerspectiveFovLH(core::radians(60.0f), float(WIN_W) / WIN_H, 0.1, 10000); + hlsl::float32_t3 cameraPosition(-5.81655884, 2.58630896, -4.23974705); + hlsl::float32_t3 cameraTarget(-0.349590302, -0.213266611, 0.317821503); + float32_t4x4 projectionMatrix = hlsl::buildProjectionMatrixPerspectiveFovLH(core::radians(60.0f), float(WIN_W) / WIN_H, 0.1, 10000); camera = Camera(cameraPosition, cameraTarget, projectionMatrix, 1.069f, 0.4f); } @@ -303,12 +305,12 @@ class GeometryCreatorApp final : public examples::SimpleWindowedApplication const auto viewMatrix = camera.getViewMatrix(); const auto viewProjectionMatrix = camera.getConcatenatedMatrix(); - core::matrix3x4SIMD modelMatrix; - modelMatrix.setTranslation(nbl::core::vectorSIMDf(0, 0, 0, 0)); - modelMatrix.setRotation(quaternion(0, 0, 0)); + hlsl::float32_t3x4 modelMatrix; + hlsl::setTranslation(modelMatrix, hlsl::float32_t3(0)); + hlsl::setRotation(modelMatrix, quaternion(0, 0, 0)); - core::matrix3x4SIMD modelViewMatrix = core::concatenateBFollowedByA(viewMatrix, modelMatrix); - core::matrix4SIMD modelViewProjectionMatrix = core::concatenateBFollowedByA(viewProjectionMatrix, modelMatrix); + hlsl::float32_t3x4 modelViewMatrix = hlsl::concatenateBFollowedByA(viewMatrix, modelMatrix); + hlsl::float32_t4x4 modelViewProjectionMatrix = hlsl::concatenateBFollowedByA(viewProjectionMatrix, hlsl::getMatrix3x4As4x4(modelMatrix)); core::matrix3x4SIMD normalMatrix; modelViewMatrix.getSub3x3InverseTranspose(normalMatrix); @@ -468,7 +470,7 @@ class GeometryCreatorApp final : public examples::SimpleWindowedApplication InputSystem::ChannelReader mouse; InputSystem::ChannelReader keyboard; - Camera camera = Camera(core::vectorSIMDf(0, 0, 0), core::vectorSIMDf(0, 0, 0), core::matrix4SIMD()); + Camera camera = Camera(hlsl::float32_t3(0, 0, 0), hlsl::float32_t3(0, 0, 0), hlsl::float32_t4x4(1)); video::CDumbPresentationOracle oracle; ResourcesBundle resources; diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 1b0fe9c0f..b7d61c7e2 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -6,6 +6,7 @@ #define _CAMERA_IMPL_ #include +#include #include #include #include @@ -15,7 +16,7 @@ class Camera { public: Camera() = default; - Camera(const nbl::core::vectorSIMDf& position, const nbl::core::vectorSIMDf& lookat, const nbl::core::matrix4SIMD& projection, float moveSpeed = 1.0f, float rotateSpeed = 1.0f, const nbl::core::vectorSIMDf& upVec = nbl::core::vectorSIMDf(0.0f, 1.0f, 0.0f), const nbl::core::vectorSIMDf& backupUpVec = nbl::core::vectorSIMDf(0.5f, 1.0f, 0.0f)) + Camera(const nbl::hlsl::float32_t3& position, const nbl::hlsl::float32_t3& lookat, const nbl::hlsl::float32_t4x4& projection, float moveSpeed = 1.0f, float rotateSpeed = 1.0f, const nbl::hlsl::float32_t3& upVec = nbl::hlsl::float32_t3(0.0f, 1.0f, 0.0f), const nbl::hlsl::float32_t3& backupUpVec = nbl::hlsl::float32_t3(0.5f, 1.0f, 0.0f)) : position(position) , initialPosition(position) , target(lookat) @@ -61,44 +62,44 @@ class Camera inline void mapKeysCustom(std::array& map) { keysMap = map; } - inline const nbl::core::matrix4SIMD& getProjectionMatrix() const { return projMatrix; } - inline const nbl::core::matrix3x4SIMD& getViewMatrix() const { return viewMatrix; } - inline const nbl::core::matrix4SIMD& getConcatenatedMatrix() const { return concatMatrix; } + inline const nbl::hlsl::float32_t4x4& getProjectionMatrix() const { return projMatrix; } + inline const nbl::hlsl::float32_t3x4& getViewMatrix() const { return viewMatrix; } + inline const nbl::hlsl::float32_t4x4& getConcatenatedMatrix() const { return concatMatrix; } - inline void setProjectionMatrix(const nbl::core::matrix4SIMD& projection) + inline void setProjectionMatrix(const nbl::hlsl::float32_t4x4& projection) { projMatrix = projection; + leftHanded = nbl::hlsl::determinant(projection) < 0.f; - const auto hlslMatMap = *reinterpret_cast(&projMatrix); // TEMPORARY TILL THE CAMERA CLASS IS REFACTORED TO WORK WITH HLSL MATRICIES! - { - leftHanded = nbl::hlsl::determinant(hlslMatMap) < 0.f; - } - concatMatrix = nbl::core::matrix4SIMD::concatenateBFollowedByAPrecisely(projMatrix, nbl::core::matrix4SIMD(viewMatrix)); + float64_t4x4 projMatPrecise = float64_t4x4(projMatrix); + float64_t4x4 viewMatPrecise = nbl::hlsl::getMatrix3x4As4x4(viewMatrix); + + concatMatrix = nbl::hlsl::concatenateBFollowedByAPrecisely(projMatrix, nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); } - inline void setPosition(const nbl::core::vectorSIMDf& pos) + inline void setPosition(const nbl::hlsl::float32_t3& pos) { - position.set(pos); + position = pos; recomputeViewMatrix(); } - inline const nbl::core::vectorSIMDf& getPosition() const { return position; } + inline const nbl::hlsl::float32_t3& getPosition() const { return position; } - inline void setTarget(const nbl::core::vectorSIMDf& pos) + inline void setTarget(const nbl::hlsl::float32_t3& pos) { - target.set(pos); + target = pos; recomputeViewMatrix(); } - inline const nbl::core::vectorSIMDf& getTarget() const { return target; } + inline const nbl::hlsl::float32_t3& getTarget() const { return target; } - inline void setUpVector(const nbl::core::vectorSIMDf& up) { upVector = up; } + inline void setUpVector(const nbl::hlsl::float32_t3& up) { upVector = up; } - inline void setBackupUpVector(const nbl::core::vectorSIMDf& up) { backupUpVector = up; } + inline void setBackupUpVector(const nbl::hlsl::float32_t3& up) { backupUpVector = up; } - inline const nbl::core::vectorSIMDf& getUpVector() const { return upVector; } + inline const nbl::hlsl::float32_t3& getUpVector() const { return upVector; } - inline const nbl::core::vectorSIMDf& getBackupUpVector() const { return backupUpVector; } + inline const nbl::hlsl::float32_t3& getBackupUpVector() const { return backupUpVector; } inline const float getMoveSpeed() const { return moveSpeed; } @@ -110,22 +111,22 @@ class Camera inline void recomputeViewMatrix() { - nbl::core::vectorSIMDf pos = position; - nbl::core::vectorSIMDf localTarget = nbl::core::normalize(target - pos); + nbl::hlsl::float32_t3 pos = position; + nbl::hlsl::float32_t3 localTarget = nbl::core::normalize(target - pos); // if upvector and vector to the target are the same, we have a // problem. so solve this problem: - nbl::core::vectorSIMDf up = nbl::core::normalize(upVector); - nbl::core::vectorSIMDf cross = nbl::core::cross(localTarget, up); + nbl::hlsl::float32_t3 up = nbl::core::normalize(upVector); + nbl::hlsl::float32_t3 cross = nbl::core::cross(localTarget, up); bool upVectorNeedsChange = nbl::core::lengthsquared(cross)[0] == 0; if (upVectorNeedsChange) up = nbl::core::normalize(backupUpVector); if (leftHanded) - viewMatrix = nbl::core::matrix3x4SIMD::buildCameraLookAtMatrixLH(pos, target, up); + viewMatrix = nbl::hlsl::buildCameraLookAtMatrixLH(pos, target, up); else - viewMatrix = nbl::core::matrix3x4SIMD::buildCameraLookAtMatrixRH(pos, target, up); - concatMatrix = nbl::core::matrix4SIMD::concatenateBFollowedByAPrecisely(projMatrix, nbl::core::matrix4SIMD(viewMatrix)); + viewMatrix = nbl::hlsl::buildCameraLookAtMatrixRH(pos, target, up); + concatMatrix = nbl::hlsl::concatenateBFollowedByAPrecisely(projMatrix, nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); } inline bool getLeftHanded() const { return leftHanded; } @@ -146,14 +147,14 @@ class Camera if(ev.type == nbl::ui::SMouseEvent::EET_MOVEMENT && mouseDown) { - nbl::core::vectorSIMDf pos = getPosition(); - nbl::core::vectorSIMDf localTarget = getTarget() - pos; + nbl::hlsl::float32_t3 pos = getPosition(); + nbl::hlsl::float32_t3 localTarget = getTarget() - pos; // Get Relative Rotation for localTarget in Radians float relativeRotationX, relativeRotationY; - relativeRotationY = atan2(localTarget.X, localTarget.Z); - const double z1 = nbl::core::sqrt(localTarget.X*localTarget.X + localTarget.Z*localTarget.Z); - relativeRotationX = atan2(z1, localTarget.Y) - nbl::core::PI()/2; + relativeRotationY = atan2(localTarget.z, localTarget.z); + const double z1 = nbl::core::sqrt(localTarget.x*localTarget.x + localTarget.z*localTarget.z); + relativeRotationX = atan2(z1, localTarget.y) - nbl::core::PI()/2; constexpr float RotateSpeedScale = 0.003f; relativeRotationX -= ev.movementEvent.relativeMovementY * rotateSpeed * RotateSpeedScale * -1.0f; @@ -172,12 +173,12 @@ class Camera if (relativeRotationX > MaxVerticalAngle && relativeRotationX < 2 * nbl::core::PI()-MaxVerticalAngle) relativeRotationX = MaxVerticalAngle; - localTarget.set(0,0, nbl::core::max(1.f, nbl::core::length(pos)[0]), 1.f); + localTarget = nbl::hlsl::float32_t3(0,0, nbl::core::max(1.f, nbl::core::length(pos)[0])); + + nbl::hlsl::float32_t3x4 mat; + nbl::hlsl::setRotation(mat, nbl::core::quaternion(relativeRotationX, relativeRotationY, 0)); + localTarget = mul(mat, nbl::hlsl::float32_t4(localTarget, 1.0f)); // TODO: w = 1.0f for sure? - nbl::core::matrix3x4SIMD mat; - mat.setRotation(nbl::core::quaternion(relativeRotationX, relativeRotationY, 0)); - mat.transformVect(localTarget); - setTarget(localTarget + pos); } } @@ -249,33 +250,34 @@ class Camera void endInputProcessing(std::chrono::microseconds _nextPresentationTimeStamp) { - nbl::core::vectorSIMDf pos = getPosition(); - nbl::core::vectorSIMDf localTarget = getTarget() - pos; + nbl::hlsl::float32_t3 pos = getPosition(); + nbl::hlsl::float32_t3 localTarget = getTarget() - pos; if (!firstUpdate) { - nbl::core::vectorSIMDf movedir = localTarget; - movedir.makeSafe3D(); + nbl::hlsl::float32_t3 movedir = localTarget; + // TODO: + //movedir.makeSafe3D(); movedir = nbl::core::normalize(movedir); constexpr float MoveSpeedScale = 0.02f; - pos += movedir * perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_FORWARD] * moveSpeed * MoveSpeedScale; - pos -= movedir * perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_BACKWARD] * moveSpeed * MoveSpeedScale; + pos += movedir * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_FORWARD] * moveSpeed * MoveSpeedScale); + pos -= movedir * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_BACKWARD] * moveSpeed * MoveSpeedScale); // strafing // if upvector and vector to the target are the same, we have a // problem. so solve this problem: - nbl::core::vectorSIMDf up = nbl::core::normalize(upVector); - nbl::core::vectorSIMDf cross = nbl::core::cross(localTarget, up); + nbl::hlsl::float32_t3 up = nbl::core::normalize(upVector); + nbl::hlsl::float32_t3 cross = nbl::core::cross(localTarget, up); bool upVectorNeedsChange = nbl::core::lengthsquared(cross)[0] == 0; if (upVectorNeedsChange) { up = nbl::core::normalize(backupUpVector); } - nbl::core::vectorSIMDf strafevect = localTarget; + nbl::hlsl::float32_t3 strafevect = localTarget; if (leftHanded) strafevect = nbl::core::cross(strafevect, up); else @@ -283,8 +285,8 @@ class Camera strafevect = nbl::core::normalize(strafevect); - pos += strafevect * perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_LEFT] * moveSpeed * MoveSpeedScale; - pos -= strafevect * perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_RIGHT] * moveSpeed * MoveSpeedScale; + pos += strafevect * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_LEFT] * moveSpeed * MoveSpeedScale); + pos -= strafevect * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_RIGHT] * moveSpeed * MoveSpeedScale); } else firstUpdate = false; @@ -308,9 +310,9 @@ class Camera } private: - nbl::core::vectorSIMDf initialPosition, initialTarget, position, target, upVector, backupUpVector; // TODO: make first 2 const + add default copy constructor - nbl::core::matrix3x4SIMD viewMatrix; - nbl::core::matrix4SIMD concatMatrix, projMatrix; + nbl::hlsl::float32_t3 initialPosition, initialTarget, position, target, upVector, backupUpVector; // TODO: make first 2 const + add default copy constructor + nbl::hlsl::float32_t3x4 viewMatrix; + nbl::hlsl::float32_t4x4 concatMatrix, projMatrix; float moveSpeed, rotateSpeed; bool leftHanded, firstUpdate = true, mouseDown = false; From 80be87d54b6015e0dc1843592824258a7792d87a Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Wed, 23 Oct 2024 11:53:07 +0200 Subject: [PATCH 06/83] update ICameraControl & CVirtualCameraEvent, add processVirtualEvent --- common/include/camera/CVirtualCameraEvent.hpp | 78 +++++---- common/include/camera/ICameraControl.hpp | 161 +++++++++++++----- 2 files changed, 165 insertions(+), 74 deletions(-) diff --git a/common/include/camera/CVirtualCameraEvent.hpp b/common/include/camera/CVirtualCameraEvent.hpp index b91712321..efc336695 100644 --- a/common/include/camera/CVirtualCameraEvent.hpp +++ b/common/include/camera/CVirtualCameraEvent.hpp @@ -10,52 +10,72 @@ namespace nbl::hlsl //! Virtual camera event representing a manipulation enum class VirtualEventType { - //! Moves the camera forward or backward - MoveForward, - - //! Zooms in or out - Zoom, - - //! Moves the camera left/right and up/down + //! Move the camera in the direction of strafe vector Strafe, - //! Rotates the camera horizontally - Pan, - - //! Rotates the camera vertically - Tilt, + //! Update orientation of camera by rotating around X, Y, Z axes + Rotate, - //! Rolls the camera around the Z axis - Roll, - - //! Resets the camera to a default position and orientation - Reset + //! Signals boolean state, for example "reset" + State }; -//! We encode all manipulation type values into a vec4 & assume they are written in NDC coordinate system with respect to camera -using manipulation_value_t = float64_t4x4; - class CVirtualCameraEvent { public: - CVirtualCameraEvent(VirtualEventType type, const manipulation_value_t value) - : type(type), value(value) {} + using manipulation_encode_t = float32_t4; + + struct StrafeManipulation + { + float32_t3 direction = {}; + float distance = {}; + }; + + struct RotateManipulation + { + float pitch = {}, roll = {}, yaw = {}; + }; + + struct StateManipulation + { + uint32_t reset : 1; + uint32_t reserved : 31; + + StateManipulation() { memset(this, 0, sizeof(StateManipulation)); } + ~StateManipulation() {} + }; + + union ManipulationValue + { + StrafeManipulation strafe; + RotateManipulation rotation; + StateManipulation state; + + ManipulationValue() { memset(this, 0, sizeof(ManipulationValue)); } + ~ManipulationValue() {} + }; + + CVirtualCameraEvent(VirtualEventType type, const ManipulationValue manipulation) + : m_type(type), m_manipulation(manipulation) + { + static_assert(sizeof(manipulation_encode_t) == sizeof(ManipulationValue)); + } - // Returns the type of virtual event + // Returns the type of manipulation value VirtualEventType getType() const { - return type; + return m_type; } - // Returns the associated value for manipulation - manipulation_value_t getValue() const + // Returns manipulation value + ManipulationValue getManipulation() const { - return value; + return m_manipulation; } private: - VirtualEventType type; - manipulation_value_t value; + VirtualEventType m_type; + ManipulationValue m_manipulation; }; } diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index c62871644..b6be74801 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -4,6 +4,7 @@ #include "IProjection.hpp" #include "CVirtualCameraEvent.hpp" #include "glm/glm/ext/matrix_transform.hpp" // TODO: TEMPORARY!!! whatever used will be moved to cpp +#include "glm/glm/gtc/quaternion.hpp" // TODO: DIFFERENT NAMESPACE namespace nbl::hlsl @@ -19,30 +20,98 @@ class ICameraController : virtual public core::IReferenceCounted { public: CGimbal(const core::smart_refctd_ptr&& projection, const float32_t3& position, const float32_t3& lookat, const float32_t3& upVec = float32_t3(0.0f, 1.0f, 0.0f), const float32_t3& backupUpVec = float32_t3(0.5f, 1.0f, 0.0f)) - : m_projection(std::move(projection)), m_position(position), m_target(lookat), m_upVec(upVec), m_backupUpVec(backupUpVec), m_initialPosition(position), m_initialTarget(lookat), m_viewMatrix({}), m_isLeftHanded(nbl::hlsl::determinant(m_projection->getProjectionMatrix()) < 0.f) + : m_projection(projection), m_position(position), m_target(lookat), m_upVec(upVec), m_backupUpVec(backupUpVec), m_initialPosition(position), m_initialTarget(lookat), m_orientation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)), m_viewMatrix({}), m_isLeftHanded(isLeftHanded(m_projection->getProjectionMatrix())) { - //! I make an assumption that we take ownership of projection (just to make less calculations on gimbal update iterations [but maybe I shouldnt, think of it!]) recomputeViewMatrix(); } + //! Start a gimbal manipulation session + inline void begin() + { + needsToRecomputeViewMatrix = false; + } + + //! End the gimbal manipulation session, recompute matrices and check projection + inline void end() + { + m_isLeftHanded = isLeftHanded(m_projection->getProjectionMatrix()); + + // Recompute the view matrix + if(needsToRecomputeViewMatrix) + recomputeViewMatrix(); + + needsToRecomputeViewMatrix = false; + } + + inline float32_t3 getLocalTarget() const + { + return m_target - m_position; + } + + inline float32_t3 getForwardDirection() const + { + return glm::normalize(getLocalTarget()); + } + + //! Reset the gimbal to its initial position, target, and orientation + inline void reset() + { + m_position = m_initialPosition; + m_target = m_initialTarget; + m_orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); + + recomputeViewMatrix(); // Recompute the view matrix after resetting + } + + //! Move the camera in the direction of strafe (mostly left/right, up/down) + void strafe(const glm::vec3& direction, float distance) + { + if (distance != 0.0f) + { + const auto strafeVector = glm::normalize(direction) * distance; + m_position += strafeVector; + m_target += strafeVector; + + needsToRecomputeViewMatrix = true; + } + } + + //! Update orientation of camera by rotating around all XYZ axes - delta rotations in radians + void rotate(float dPitchRadians, float dYawDeltaRadians, float dRollDeltaRadians) + { + // Rotate around X (pitch) + glm::quat qPitch = glm::angleAxis(dPitchRadians, glm::vec3(1.0f, 0.0f, 0.0f)); + + // Rotate around Y (yaw) + glm::quat qYaw = glm::angleAxis(dYawDeltaRadians, glm::vec3(0.0f, 1.0f, 0.0f)); + + // Rotate around Z (roll) // TODO: handness!! + glm::quat qRoll = glm::angleAxis(dRollDeltaRadians, glm::vec3(0.0f, 0.0f, 1.0f)); + + // Combine the new rotations with the current orientation + m_orientation = glm::normalize(qYaw * qPitch * qRoll * m_orientation); + + // Now we have rotation transformation as 3x3 matrix + auto rotate = glm::mat3_cast(m_orientation); + + // We do not change magnitude of the vector + auto localTargetRotated = rotate * getLocalTarget(); + + // And we can simply update target vector + m_target = m_position + localTargetRotated; + + // TODO: std::any + nice checks for deltas (radians - periodic!) + needsToRecomputeViewMatrix = true; + } + // TODO: ctor with core::path to json config file to load defaults const projection_t* getProjection() { return m_projection.get(); } - // TODO: gimbal methods (to handle VirtualEventType requests) - private: inline void recomputeViewMatrix() { - auto localTarget = glm::normalize(m_target - m_position); - - // If up vector and vector to the target are the same, adjust the up vector - auto up = glm::normalize(m_upVec); - auto cross = glm::cross(localTarget, up); - bool upVectorNeedsChange = glm::dot(cross, cross) == 0; - - if (upVectorNeedsChange) - up = glm::normalize(m_backupUpVec); + auto up = getPatchedUpVector(); if (m_isLeftHanded) m_viewMatrix = glm::lookAtLH(m_position, m_target, up); @@ -50,12 +119,37 @@ class ICameraController : virtual public core::IReferenceCounted m_viewMatrix = glm::lookAtRH(m_position, m_target, up); } + inline float32_t3 getPatchedUpVector() + { + // if up vector and vector to the target are the same we patch the up vector + auto up = glm::normalize(m_upVec); + + const auto localTarget = getForwardDirection(); + const auto cross = glm::cross(localTarget, up); + + // we compute squared length but for checking if the len is 0 it doesnt matter + const bool upVectorZeroLength = glm::dot(cross, cross) == 0.f; + + if (upVectorZeroLength) + up = glm::normalize(m_backupUpVec); + + return up; + } + + inline bool isLeftHanded(const auto& projectionMatrix) + { + return nbl::hlsl::determinant(projectionMatrix) < 0.f; + } + const core::smart_refctd_ptr m_projection; float32_t3 m_position, m_target, m_upVec, m_backupUpVec; const float32_t3 m_initialPosition, m_initialTarget; + glm::quat m_orientation; float64_t4x4 m_viewMatrix; - const bool m_isLeftHanded; + bool m_isLeftHanded; + + bool needsToRecomputeViewMatrix = false; }; ICameraController(core::smart_refctd_ptr&& gimbal) @@ -63,45 +157,22 @@ class ICameraController : virtual public core::IReferenceCounted void processVirtualEvent(const CVirtualCameraEvent& virtualEvent) { - // we will treat all manipulation event values as NDC, also for non manipulation events - // we will define how to handle it, all values are encoded onto vec4 (manipulation_value_t) - manipulation_value_t value = virtualEvent.getValue(); - - // TODO: this will use gimbal to handle a virtual event registered by a class (wip) which maps physical keys to virtual events + const auto manipulation = virtualEvent.getManipulation(); - case VirtualEventType::MoveForward: - { - // TODO - } break; - case VirtualEventType::Strafe: { - // TODO - } break; - - case VirtualEventType::Zoom: - { - // TODO + m_gimbal->strafe(manipulation.strafe.direction, manipulation.strafe.distance); } break; - - case VirtualEventType::Pan: - { - // TODO - } break; - - case VirtualEventType::Tilt: - { - // TODO - } break; - - case VirtualEventType::Roll: + + case VirtualEventType::Rotate: { - // TODO + m_gimbal->rotate(manipulation.rotation.pitch, manipulation.rotation.yaw, manipulation.rotation.roll); } break; - case VirtualEventType::Reset: + case VirtualEventType::State: { - // TODO + if (manipulation.state.reset) + m_gimbal->reset(); } break; default: From 3af8c076396891e658defa953d0ad03341d570bb Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Wed, 23 Oct 2024 18:18:17 +0200 Subject: [PATCH 07/83] put CVirtualCameraEvent logic into ICameraController, update the class with abstract manipulate method - expect virtual event & a gimbal. Update CGimbal with new manipulation & set methods, start replacing CCamera content with new gimbal & controller --- common/include/CCamera.hpp | 67 +---- common/include/camera/CVirtualCameraEvent.hpp | 71 ----- common/include/camera/ICameraControl.hpp | 283 ++++++++++++++---- 3 files changed, 241 insertions(+), 180 deletions(-) diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 1b0fe9c0f..54c6477a3 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -11,70 +11,21 @@ #include #include -class Camera +#include "camera/ICameraControl.hpp" + +// FPS Camera, we will have more types soon + +template +class Camera : public ICameraController { public: - Camera() = default; - Camera(const nbl::core::vectorSIMDf& position, const nbl::core::vectorSIMDf& lookat, const nbl::core::matrix4SIMD& projection, float moveSpeed = 1.0f, float rotateSpeed = 1.0f, const nbl::core::vectorSIMDf& upVec = nbl::core::vectorSIMDf(0.0f, 1.0f, 0.0f), const nbl::core::vectorSIMDf& backupUpVec = nbl::core::vectorSIMDf(0.5f, 1.0f, 0.0f)) - : position(position) - , initialPosition(position) - , target(lookat) - , initialTarget(lookat) - , firstUpdate(true) - , moveSpeed(moveSpeed) - , rotateSpeed(rotateSpeed) - , upVector(upVec) - , backupUpVector(backupUpVec) - { - initDefaultKeysMap(); - allKeysUp(); - setProjectionMatrix(projection); - recomputeViewMatrix(); - } + using matrix_t = T; + Camera() = default; ~Camera() = default; - enum E_CAMERA_MOVE_KEYS : uint8_t - { - ECMK_MOVE_FORWARD = 0, - ECMK_MOVE_BACKWARD, - ECMK_MOVE_LEFT, - ECMK_MOVE_RIGHT, - ECMK_COUNT, - }; - - inline void mapKeysToWASD() - { - keysMap[ECMK_MOVE_FORWARD] = nbl::ui::EKC_W; - keysMap[ECMK_MOVE_BACKWARD] = nbl::ui::EKC_S; - keysMap[ECMK_MOVE_LEFT] = nbl::ui::EKC_A; - keysMap[ECMK_MOVE_RIGHT] = nbl::ui::EKC_D; - } - - inline void mapKeysToArrows() - { - keysMap[ECMK_MOVE_FORWARD] = nbl::ui::EKC_UP_ARROW; - keysMap[ECMK_MOVE_BACKWARD] = nbl::ui::EKC_DOWN_ARROW; - keysMap[ECMK_MOVE_LEFT] = nbl::ui::EKC_LEFT_ARROW; - keysMap[ECMK_MOVE_RIGHT] = nbl::ui::EKC_RIGHT_ARROW; - } - - inline void mapKeysCustom(std::array& map) { keysMap = map; } - - inline const nbl::core::matrix4SIMD& getProjectionMatrix() const { return projMatrix; } - inline const nbl::core::matrix3x4SIMD& getViewMatrix() const { return viewMatrix; } - inline const nbl::core::matrix4SIMD& getConcatenatedMatrix() const { return concatMatrix; } - - inline void setProjectionMatrix(const nbl::core::matrix4SIMD& projection) - { - projMatrix = projection; - const auto hlslMatMap = *reinterpret_cast(&projMatrix); // TEMPORARY TILL THE CAMERA CLASS IS REFACTORED TO WORK WITH HLSL MATRICIES! - { - leftHanded = nbl::hlsl::determinant(hlslMatMap) < 0.f; - } - concatMatrix = nbl::core::matrix4SIMD::concatenateBFollowedByAPrecisely(projMatrix, nbl::core::matrix4SIMD(viewMatrix)); - } + inline void setPosition(const nbl::core::vectorSIMDf& pos) { diff --git a/common/include/camera/CVirtualCameraEvent.hpp b/common/include/camera/CVirtualCameraEvent.hpp index efc336695..309c91662 100644 --- a/common/include/camera/CVirtualCameraEvent.hpp +++ b/common/include/camera/CVirtualCameraEvent.hpp @@ -7,77 +7,6 @@ namespace nbl::hlsl { -//! Virtual camera event representing a manipulation -enum class VirtualEventType -{ - //! Move the camera in the direction of strafe vector - Strafe, - - //! Update orientation of camera by rotating around X, Y, Z axes - Rotate, - - //! Signals boolean state, for example "reset" - State -}; - -class CVirtualCameraEvent -{ -public: - using manipulation_encode_t = float32_t4; - - struct StrafeManipulation - { - float32_t3 direction = {}; - float distance = {}; - }; - - struct RotateManipulation - { - float pitch = {}, roll = {}, yaw = {}; - }; - - struct StateManipulation - { - uint32_t reset : 1; - uint32_t reserved : 31; - - StateManipulation() { memset(this, 0, sizeof(StateManipulation)); } - ~StateManipulation() {} - }; - - union ManipulationValue - { - StrafeManipulation strafe; - RotateManipulation rotation; - StateManipulation state; - - ManipulationValue() { memset(this, 0, sizeof(ManipulationValue)); } - ~ManipulationValue() {} - }; - - CVirtualCameraEvent(VirtualEventType type, const ManipulationValue manipulation) - : m_type(type), m_manipulation(manipulation) - { - static_assert(sizeof(manipulation_encode_t) == sizeof(ManipulationValue)); - } - - // Returns the type of manipulation value - VirtualEventType getType() const - { - return m_type; - } - - // Returns manipulation value - ManipulationValue getManipulation() const - { - return m_manipulation; - } - -private: - VirtualEventType m_type; - ManipulationValue m_manipulation; -}; - } #endif // _NBL_VIRTUAL_CAMERA_EVENT_HPP_ \ No newline at end of file diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index b6be74801..0618f90de 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -16,55 +16,227 @@ class ICameraController : virtual public core::IReferenceCounted public: using projection_t = typename IProjection; + enum VirtualEventType : uint8_t + { + // Strafe forward + MoveForward = 0, + + // Strafe backward + MoveBackward, + + // Strafe left + MoveLeft, + + // Strafe right + MoveRight, + + // Strafe up + MoveUp, + + // Strafe down + MoveDown, + + // Tilt the camera upward (pitch) + TiltUp, + + // Tilt the camera downward (pitch) + TiltDown, + + // Rotate the camera left around the vertical axis (yaw) + PanLeft, + + // Rotate the camera right around the vertical axis (yaw) + PanRight, + + // Roll the camera counterclockwise around the forward axis (roll) + RollLeft, + + // Roll the camera clockwise around the forward axis (roll) + RollRight, + + // Reset the camera to the default state + Reset, + + EventsCount + }; + class CGimbal : virtual public core::IReferenceCounted { public: + //! Virtual event representing a manipulation + enum VirtualEventType + { + //! Move the camera in the direction of strafe vector + Strafe, + + //! Update orientation of camera by rotating around X, Y, Z axes + Rotate, + + //! Signals boolean state, for example "reset" + State + }; + + class CVirtualEvent + { + public: + using manipulation_encode_t = float32_t4; + + struct StrafeManipulation + { + float32_t3 direction = {}; + float distance = {}; + }; + + struct RotateManipulation + { + float pitch = {}, roll = {}, yaw = {}; + }; + + struct StateManipulation + { + uint32_t reset : 1; + uint32_t reserved : 31; + + StateManipulation() { memset(this, 0, sizeof(StateManipulation)); } + ~StateManipulation() {} + }; + + union ManipulationValue + { + StrafeManipulation strafe; + RotateManipulation rotation; + StateManipulation state; + + ManipulationValue() { memset(this, 0, sizeof(ManipulationValue)); } + ~ManipulationValue() {} + }; + + CVirtualEvent(VirtualEventType type, const ManipulationValue manipulation) + : m_type(type), m_manipulation(manipulation) + { + static_assert(sizeof(manipulation_encode_t) == sizeof(ManipulationValue)); + } + + // Returns the type of manipulation value + VirtualEventType getType() const + { + return m_type; + } + + // Returns manipulation value + ManipulationValue getManipulation() const + { + return m_manipulation; + } + + private: + VirtualEventType m_type; + ManipulationValue m_manipulation; + }; + CGimbal(const core::smart_refctd_ptr&& projection, const float32_t3& position, const float32_t3& lookat, const float32_t3& upVec = float32_t3(0.0f, 1.0f, 0.0f), const float32_t3& backupUpVec = float32_t3(0.5f, 1.0f, 0.0f)) : m_projection(projection), m_position(position), m_target(lookat), m_upVec(upVec), m_backupUpVec(backupUpVec), m_initialPosition(position), m_initialTarget(lookat), m_orientation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)), m_viewMatrix({}), m_isLeftHanded(isLeftHanded(m_projection->getProjectionMatrix())) { recomputeViewMatrix(); } + // TODO: ctor with core::path to json config file to load defaults + //! Start a gimbal manipulation session inline void begin() { - needsToRecomputeViewMatrix = false; + m_needsToRecomputeViewMatrix = false; + m_recordingManipulation = true; } - //! End the gimbal manipulation session, recompute matrices and check projection - inline void end() + //! Record manipulation of the gimbal, note those events are delta manipulations + void manipulate(const CVirtualEvent& virtualEvent) { - m_isLeftHanded = isLeftHanded(m_projection->getProjectionMatrix()); + if (!m_recordingManipulation) + return; // TODO: log it - // Recompute the view matrix - if(needsToRecomputeViewMatrix) - recomputeViewMatrix(); + const auto manipulation = virtualEvent.getManipulation(); - needsToRecomputeViewMatrix = false; + case VirtualEventType::Strafe: + { + strafe(manipulation.strafe.direction, manipulation.strafe.distance); + } break; + + case VirtualEventType::Rotate: + { + rotate(manipulation.rotation.pitch, manipulation.rotation.yaw, manipulation.rotation.roll); + } break; + + case VirtualEventType::State: + { + if (manipulation.state.reset) + reset(); + } break; + + default: + break; } - inline float32_t3 getLocalTarget() const + // Record change of position vector, global update + inline void setPosition(const float32_t3& position) { - return m_target - m_position; + if (!m_recordingManipulation) + return; // TODO: log it + + m_position = position; } - inline float32_t3 getForwardDirection() const + // Record change of target vector, global update + inline void setTarget(const float32_t3& target) { - return glm::normalize(getLocalTarget()); + if (!m_recordingManipulation) + return; // TODO: log it + + m_target = target; } + // Change up vector, global update + inline void setUpVector(const float32_t3& up) { m_upVec = up; } + + // Change backupUp vector, global update + inline void setBackupUpVector(const float32_t3& backupUp) { m_backupUpVec = backupUp; } + + //! End the gimbal manipulation session, recompute view matrix if required and update handedness state from projection + inline void end() + { + m_isLeftHanded = isLeftHanded(m_projection->getProjectionMatrix()); + + if (m_needsToRecomputeViewMatrix) + recomputeViewMatrix(); + + m_needsToRecomputeViewMatrix = false; + m_recordingManipulation = false; + } + + inline const float32_t3& getPosition() const { return m_position; } + inline const float32_t3& getTarget() const { return m_target; } + inline const float32_t3& getUpVector() const { return m_upVec; } + inline const float32_t3& getBackupUpVector() const { return m_backupUpVec; } + inline const float32_t3 getLocalTarget() const { return m_target - m_position; } + inline const float32_t3 getForwardDirection() const { return glm::normalize(getLocalTarget()); } + inline const projection_t* getProjection() { return m_projection.get(); } + + // TODO: getConcatenatedMatrix() + // TODO: getViewMatrix() + + private: //! Reset the gimbal to its initial position, target, and orientation inline void reset() { - m_position = m_initialPosition; + m_position = m_initialPosition; m_target = m_initialTarget; m_orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); recomputeViewMatrix(); // Recompute the view matrix after resetting } - //! Move the camera in the direction of strafe (mostly left/right, up/down) - void strafe(const glm::vec3& direction, float distance) + //! Move in the direction of strafe (mostly left/right, up/down) + inline void strafe(const glm::vec3& direction, float distance) { if (distance != 0.0f) { @@ -72,12 +244,12 @@ class ICameraController : virtual public core::IReferenceCounted m_position += strafeVector; m_target += strafeVector; - needsToRecomputeViewMatrix = true; + m_needsToRecomputeViewMatrix = true; } } - //! Update orientation of camera by rotating around all XYZ axes - delta rotations in radians - void rotate(float dPitchRadians, float dYawDeltaRadians, float dRollDeltaRadians) + //! Update orientation by rotating around all XYZ axes - delta rotations in radians + inline void rotate(float dPitchRadians, float dYawDeltaRadians, float dRollDeltaRadians) { // Rotate around X (pitch) glm::quat qPitch = glm::angleAxis(dPitchRadians, glm::vec3(1.0f, 0.0f, 0.0f)); @@ -101,14 +273,9 @@ class ICameraController : virtual public core::IReferenceCounted m_target = m_position + localTargetRotated; // TODO: std::any + nice checks for deltas (radians - periodic!) - needsToRecomputeViewMatrix = true; + m_needsToRecomputeViewMatrix = true; } - // TODO: ctor with core::path to json config file to load defaults - - const projection_t* getProjection() { return m_projection.get(); } - - private: inline void recomputeViewMatrix() { auto up = getPatchedUpVector(); @@ -138,49 +305,63 @@ class ICameraController : virtual public core::IReferenceCounted inline bool isLeftHanded(const auto& projectionMatrix) { - return nbl::hlsl::determinant(projectionMatrix) < 0.f; + return hlsl::determinant(projectionMatrix) < 0.f; } - const core::smart_refctd_ptr m_projection; + core::smart_refctd_ptr m_projection; float32_t3 m_position, m_target, m_upVec, m_backupUpVec; const float32_t3 m_initialPosition, m_initialTarget; glm::quat m_orientation; float64_t4x4 m_viewMatrix; - bool m_isLeftHanded; - bool needsToRecomputeViewMatrix = false; + bool m_isLeftHanded, + m_needsToRecomputeViewMatrix = false, + m_recordingManipulation = false; }; - ICameraController(core::smart_refctd_ptr&& gimbal) - : m_gimbal(std::move(gimbal)) {} + ICameraController() : {} - void processVirtualEvent(const CVirtualCameraEvent& virtualEvent) + // controller overrides how a manipulation is done for a given camera event with a gimbal + virtual void manipulate(CGimbal* gimbal, VirtualEventType event) = 0; + + // controller can override default set of event map + virtual void initKeysToEvent() { - const auto manipulation = virtualEvent.getManipulation(); + m_keysToEvent[MoveForward] = { ui::E_KEY_CODE::EKC_W }; + m_keysToEvent[MoveBackward] = { ui::E_KEY_CODE::EKC_S }; + m_keysToEvent[MoveLeft] = { ui::E_KEY_CODE::EKC_A }; + m_keysToEvent[MoveRight] = { ui::E_KEY_CODE::EKC_D }; + m_keysToEvent[MoveUp] = { ui::E_KEY_CODE::EKC_SPACE }; + m_keysToEvent[MoveDown] = { ui::E_KEY_CODE::EKC_LEFT_SHIFT }; + m_keysToEvent[TiltUp] = { ui::E_KEY_CODE::EKC_NONE }; + m_keysToEvent[TiltDown] = { ui::E_KEY_CODE::EKC_NONE }; + m_keysToEvent[PanLeft] = { ui::E_KEY_CODE::EKC_NONE }; + m_keysToEvent[PanRight] = { ui::E_KEY_CODE::EKC_NONE }; + m_keysToEvent[RollLeft] = { ui::E_KEY_CODE::EKC_NONE }; + m_keysToEvent[RollRight] = { ui::E_KEY_CODE::EKC_NONE }; + m_keysToEvent[Reset] = { ui::E_KEY_CODE::EKC_R }; + } - case VirtualEventType::Strafe: - { - m_gimbal->strafe(manipulation.strafe.direction, manipulation.strafe.distance); - } break; - - case VirtualEventType::Rotate: - { - m_gimbal->rotate(manipulation.rotation.pitch, manipulation.rotation.yaw, manipulation.rotation.roll); - } break; + // controller can override which keys correspond to which event + void updateKeysToEvent(const std::vector& codes, VirtualEventType event) + { + m_keysToEvent[event] = std::move(codes); + } - case VirtualEventType::State: - { - if (manipulation.state.reset) - m_gimbal->reset(); - } break; +protected: + std::array, EventsCount> m_keysToEvent = {}; - default: - break; - } + // speed factors + float m_moveSpeed = 1.f, m_rotateSpeed = 1.f; + + // states signaling if keys are pressed down or not + bool m_keysDown[EventsCount] = {}; + + // durations for which the key was being held down from lastVirtualUpTimeStamp(=last "guessed" presentation time) to nextPresentationTimeStamp + double m_perActionDt[EventsCount] = {}; -private: - core::smart_refctd_ptr m_gimbal; + std::chrono::microseconds nextPresentationTimeStamp, lastVirtualUpTimeStamp; }; } // nbl::hlsl namespace From fdd47a7518f460df596ea407ad62e4db25e44155 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Wed, 23 Oct 2024 18:22:20 +0200 Subject: [PATCH 08/83] add more getters & setters to ICameraController, remove some content from CCamera, mark TODOs for tomorrow --- common/include/CCamera.hpp | 74 +----------------------- common/include/camera/ICameraControl.hpp | 7 +++ 2 files changed, 10 insertions(+), 71 deletions(-) diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 54c6477a3..b2a56cead 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -24,62 +24,9 @@ class Camera : public ICameraController Camera() = default; ~Camera() = default; - - - - inline void setPosition(const nbl::core::vectorSIMDf& pos) - { - position.set(pos); - recomputeViewMatrix(); - } - - inline const nbl::core::vectorSIMDf& getPosition() const { return position; } - - inline void setTarget(const nbl::core::vectorSIMDf& pos) - { - target.set(pos); - recomputeViewMatrix(); - } - - inline const nbl::core::vectorSIMDf& getTarget() const { return target; } - - inline void setUpVector(const nbl::core::vectorSIMDf& up) { upVector = up; } - - inline void setBackupUpVector(const nbl::core::vectorSIMDf& up) { backupUpVector = up; } - - inline const nbl::core::vectorSIMDf& getUpVector() const { return upVector; } - - inline const nbl::core::vectorSIMDf& getBackupUpVector() const { return backupUpVector; } - - inline const float getMoveSpeed() const { return moveSpeed; } - - inline void setMoveSpeed(const float _moveSpeed) { moveSpeed = _moveSpeed; } - - inline const float getRotateSpeed() const { return rotateSpeed; } - - inline void setRotateSpeed(const float _rotateSpeed) { rotateSpeed = _rotateSpeed; } - - inline void recomputeViewMatrix() - { - nbl::core::vectorSIMDf pos = position; - nbl::core::vectorSIMDf localTarget = nbl::core::normalize(target - pos); - - // if upvector and vector to the target are the same, we have a - // problem. so solve this problem: - nbl::core::vectorSIMDf up = nbl::core::normalize(upVector); - nbl::core::vectorSIMDf cross = nbl::core::cross(localTarget, up); - bool upVectorNeedsChange = nbl::core::lengthsquared(cross)[0] == 0; - if (upVectorNeedsChange) - up = nbl::core::normalize(backupUpVector); - - if (leftHanded) - viewMatrix = nbl::core::matrix3x4SIMD::buildCameraLookAtMatrixLH(pos, target, up); - else - viewMatrix = nbl::core::matrix3x4SIMD::buildCameraLookAtMatrixRH(pos, target, up); - concatMatrix = nbl::core::matrix4SIMD::concatenateBFollowedByAPrecisely(projMatrix, nbl::core::matrix4SIMD(viewMatrix)); - } - - inline bool getLeftHanded() const { return leftHanded; } + /* + TODO: controller + gimbal to do all of this -> override virtual manipulate method + */ public: @@ -257,21 +204,6 @@ class Camera : public ICameraController mouseDown = false; } - -private: - nbl::core::vectorSIMDf initialPosition, initialTarget, position, target, upVector, backupUpVector; // TODO: make first 2 const + add default copy constructor - nbl::core::matrix3x4SIMD viewMatrix; - nbl::core::matrix4SIMD concatMatrix, projMatrix; - - float moveSpeed, rotateSpeed; - bool leftHanded, firstUpdate = true, mouseDown = false; - - std::array keysMap = { {nbl::ui::EKC_NONE} }; // map camera E_CAMERA_MOVE_KEYS to corresponding Nabla key codes, by default camera uses WSAD to move - // TODO: make them use std::array - bool keysDown[E_CAMERA_MOVE_KEYS::ECMK_COUNT] = {}; - double perActionDt[E_CAMERA_MOVE_KEYS::ECMK_COUNT] = {}; // durations for which the key was being held down from lastVirtualUpTimeStamp(=last "guessed" presentation time) to nextPresentationTimeStamp - - std::chrono::microseconds nextPresentationTimeStamp, lastVirtualUpTimeStamp; }; #endif // _CAMERA_IMPL_ \ No newline at end of file diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 0618f90de..9dfe758f1 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -350,6 +350,13 @@ class ICameraController : virtual public core::IReferenceCounted } protected: + + inline void setMoveSpeed(const float moveSpeed) { moveSpeed = m_moveSpeed; } + inline void setRotateSpeed(const float rotateSpeed) { rotateSpeed = m_rotateSpeed; } + + inline const float getMoveSpeed() const { return m_moveSpeed; } + inline const float getRotateSpeed() const { return m_rotateSpeed; } + std::array, EventsCount> m_keysToEvent = {}; // speed factors From 6b45fecf8c64e8b11fef8c2b3a7e5618edaca68d Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Wed, 23 Oct 2024 13:54:21 -0700 Subject: [PATCH 09/83] Modified example 09 --- 09_GeometryCreator/main.cpp | 8 ++++---- common/include/CCamera.hpp | 32 ++++++++++++++++---------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/09_GeometryCreator/main.cpp b/09_GeometryCreator/main.cpp index e87ee066b..daafdb247 100644 --- a/09_GeometryCreator/main.cpp +++ b/09_GeometryCreator/main.cpp @@ -310,14 +310,14 @@ class GeometryCreatorApp final : public examples::SimpleWindowedApplication hlsl::setRotation(modelMatrix, quaternion(0, 0, 0)); hlsl::float32_t3x4 modelViewMatrix = hlsl::concatenateBFollowedByA(viewMatrix, modelMatrix); - hlsl::float32_t4x4 modelViewProjectionMatrix = hlsl::concatenateBFollowedByA(viewProjectionMatrix, hlsl::getMatrix3x4As4x4(modelMatrix)); + hlsl::float32_t4x4 modelViewProjectionMatrix = mul(viewProjectionMatrix, hlsl::getMatrix3x4As4x4(modelMatrix)); core::matrix3x4SIMD normalMatrix; - modelViewMatrix.getSub3x3InverseTranspose(normalMatrix); + //modelViewMatrix.getSub3x3InverseTranspose(normalMatrix); SBasicViewParameters uboData; - memcpy(uboData.MVP, modelViewProjectionMatrix.pointer(), sizeof(uboData.MVP)); - memcpy(uboData.MV, modelViewMatrix.pointer(), sizeof(uboData.MV)); + memcpy(uboData.MVP, &modelViewProjectionMatrix, sizeof(uboData.MVP)); + memcpy(uboData.MV, &modelViewMatrix, sizeof(uboData.MV)); memcpy(uboData.NormalMat, normalMatrix.pointer(), sizeof(uboData.NormalMat)); { SBufferRange range; diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index b7d61c7e2..7ecb4f6ff 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -71,10 +71,10 @@ class Camera projMatrix = projection; leftHanded = nbl::hlsl::determinant(projection) < 0.f; - float64_t4x4 projMatPrecise = float64_t4x4(projMatrix); - float64_t4x4 viewMatPrecise = nbl::hlsl::getMatrix3x4As4x4(viewMatrix); + nbl::hlsl::float64_t4x4 projMatPrecise = nbl::hlsl::get64BitPrecisionMatrix(projMatrix); + nbl::hlsl::float64_t4x4 viewMatPrecise = nbl::hlsl::get64BitPrecisionMatrix(nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); - concatMatrix = nbl::hlsl::concatenateBFollowedByAPrecisely(projMatrix, nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); + concatMatrix = mul(projMatrix, nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); } inline void setPosition(const nbl::hlsl::float32_t3& pos) @@ -112,21 +112,21 @@ class Camera inline void recomputeViewMatrix() { nbl::hlsl::float32_t3 pos = position; - nbl::hlsl::float32_t3 localTarget = nbl::core::normalize(target - pos); + nbl::hlsl::float32_t3 localTarget = nbl::hlsl::normalize(target - pos); // if upvector and vector to the target are the same, we have a // problem. so solve this problem: - nbl::hlsl::float32_t3 up = nbl::core::normalize(upVector); - nbl::hlsl::float32_t3 cross = nbl::core::cross(localTarget, up); + nbl::hlsl::float32_t3 up = nbl::hlsl::normalize(upVector); + nbl::hlsl::float32_t3 cross = nbl::hlsl::cross(localTarget, up); bool upVectorNeedsChange = nbl::core::lengthsquared(cross)[0] == 0; if (upVectorNeedsChange) - up = nbl::core::normalize(backupUpVector); + up = nbl::hlsl::normalize(backupUpVector); if (leftHanded) viewMatrix = nbl::hlsl::buildCameraLookAtMatrixLH(pos, target, up); else viewMatrix = nbl::hlsl::buildCameraLookAtMatrixRH(pos, target, up); - concatMatrix = nbl::hlsl::concatenateBFollowedByAPrecisely(projMatrix, nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); + concatMatrix = mul(projMatrix, nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); } inline bool getLeftHanded() const { return leftHanded; } @@ -258,7 +258,7 @@ class Camera nbl::hlsl::float32_t3 movedir = localTarget; // TODO: //movedir.makeSafe3D(); - movedir = nbl::core::normalize(movedir); + movedir = nbl::hlsl::normalize(movedir); constexpr float MoveSpeedScale = 0.02f; @@ -269,21 +269,21 @@ class Camera // if upvector and vector to the target are the same, we have a // problem. so solve this problem: - nbl::hlsl::float32_t3 up = nbl::core::normalize(upVector); - nbl::hlsl::float32_t3 cross = nbl::core::cross(localTarget, up); - bool upVectorNeedsChange = nbl::core::lengthsquared(cross)[0] == 0; + nbl::hlsl::float32_t3 up = nbl::hlsl::normalize(upVector); + nbl::hlsl::float32_t3 cross = nbl::hlsl::cross(localTarget, up); + bool upVectorNeedsChange = nbl::hlsl::dot(cross, cross) == 0; if (upVectorNeedsChange) { - up = nbl::core::normalize(backupUpVector); + up = nbl::hlsl::normalize(backupUpVector); } nbl::hlsl::float32_t3 strafevect = localTarget; if (leftHanded) - strafevect = nbl::core::cross(strafevect, up); + strafevect = nbl::hlsl::cross(strafevect, up); else - strafevect = nbl::core::cross(up, strafevect); + strafevect = nbl::hlsl::cross(up, strafevect); - strafevect = nbl::core::normalize(strafevect); + strafevect = nbl::hlsl::normalize(strafevect); pos += strafevect * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_LEFT] * moveSpeed * MoveSpeedScale); pos -= strafevect * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_RIGHT] * moveSpeed * MoveSpeedScale); From 3ed3727285f8b7411c92008c064c58ed94e8903a Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Thu, 24 Oct 2024 20:24:01 +0200 Subject: [PATCH 10/83] save work, make classes compile (but runtime crashes), mark TODOs for tomorrow - make CCamera use gimbal & treat as FPS controller --- 61_UI/main.cpp | 159 +++++++------ common/include/CCamera.hpp | 273 +++++++++-------------- common/include/CGeomtryCreatorScene.hpp | 2 +- common/include/camera/ICameraControl.hpp | 271 ++++++++++++++-------- 4 files changed, 372 insertions(+), 333 deletions(-) diff --git a/61_UI/main.cpp b/61_UI/main.cpp index 37e50805c..374719bab 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -8,6 +8,11 @@ #include "camera/ICameraControl.hpp" #include "glm/glm/ext/matrix_clip_space.hpp" // TODO: TESTING +// FPS Camera, TESTS +using camera_t = Camera; +using gimbal_t = camera_t::CGimbal; +using projection_t = camera_t::base_t::projection_t; + /* Renders scene texture to an offline framebuffer which color attachment @@ -170,28 +175,32 @@ class UISampleApp final : public examples::SimpleWindowedApplication pass.ui.manager->registerListener([this]() -> void { ImGuiIO& io = ImGui::GetIO(); - - camera.setProjectionMatrix([&]() { - static matrix4SIMD projection; + auto& projection = gimbal->getProjection()->getProjectionMatrix(); + + + // TODO CASTS + + /* if (isPerspective) - if(isLH) - projection = matrix4SIMD::buildProjectionMatrixPerspectiveFovLH(core::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); + { + if (isLH) + projection = glm::perspectiveLH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); else - projection = matrix4SIMD::buildProjectionMatrixPerspectiveFovRH(core::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); + projection = glm::perspectiveRH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); + } else { float viewHeight = viewWidth * io.DisplaySize.y / io.DisplaySize.x; - if(isLH) - projection = matrix4SIMD::buildProjectionMatrixOrthoLH(viewWidth, viewHeight, zNear, zFar); + if (isLH) + projection = glm::orthoLH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar); else - projection = matrix4SIMD::buildProjectionMatrixOrthoRH(viewWidth, viewHeight, zNear, zFar); + projection = glm::orthoRH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar); } - - return projection; - }()); + */ + } ImGuizmo::SetOrthographic(false); ImGuizmo::BeginFrame(); @@ -250,15 +259,17 @@ class UISampleApp final : public examples::SimpleWindowedApplication if (viewDirty || firstFrame) { - core::vectorSIMDf cameraPosition(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance); - core::vectorSIMDf cameraTarget(0.f, 0.f, 0.f); - const static core::vectorSIMDf up(0.f, 1.f, 0.f); + float32_t3 cameraPosition(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance); + float32_t3 cameraTarget(0.f, 0.f, 0.f); + const static float32_t3 up(0.f, 1.f, 0.f); - camera.setPosition(cameraPosition); - camera.setTarget(cameraTarget); - camera.setBackupUpVector(up); - - camera.recomputeViewMatrix(); + gimbal->begin(); + { + gimbal->setPosition(cameraPosition); + gimbal->setTarget(cameraTarget); + gimbal->setBackupUpVector(up); + } + gimbal->end(); firstFrame = false; } @@ -326,35 +337,42 @@ class UISampleApp final : public examples::SimpleWindowedApplication static struct { - core::matrix4SIMD view, projection, model; + float32_t4x4 view, projection, model; } imguizmoM16InOut; ImGuizmo::SetID(0u); - imguizmoM16InOut.view = core::transpose(matrix4SIMD(camera.getViewMatrix())); - imguizmoM16InOut.projection = core::transpose(camera.getProjectionMatrix()); - imguizmoM16InOut.model = core::transpose(core::matrix4SIMD(pass.scene->object.model)); + imguizmoM16InOut.view = transpose(gimbal->getViewMatrix()); + imguizmoM16InOut.projection = transpose(gimbal->getProjection()->getProjectionMatrix()); + imguizmoM16InOut.model = transpose(pass.scene->object.model); { if (flipGizmoY) // note we allow to flip gizmo just to match our coordinates imguizmoM16InOut.projection[1][1] *= -1.f; // https://johannesugb.github.io/gpu-programming/why-do-opengl-proj-matrices-fail-in-vulkan/ transformParams.editTransformDecomposition = true; - EditTransform(imguizmoM16InOut.view.pointer(), imguizmoM16InOut.projection.pointer(), imguizmoM16InOut.model.pointer(), transformParams); + EditTransform(&imguizmoM16InOut.view[0][0], &imguizmoM16InOut.projection[0][0], &imguizmoM16InOut.model[0][0], transformParams); } + // to Nabla + update camera & model matrices - const auto& view = camera.getViewMatrix(); - const auto& projection = camera.getProjectionMatrix(); + const auto& view = gimbal->getViewMatrix(); + const auto& projection = gimbal->getProjection()->getProjectionMatrix(); + + + /* + + TODO!!! + // TODO: make it more nicely - const_cast(view) = core::transpose(imguizmoM16InOut.view).extractSub3x4(); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) + const_cast(view) = transpose(imguizmoM16InOut.view); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) camera.setProjectionMatrix(projection); // update concatanated matrix { static nbl::core::matrix3x4SIMD modelView, normal; static nbl::core::matrix4SIMD modelViewProjection; auto& hook = pass.scene->object; - hook.model = core::transpose(imguizmoM16InOut.model).extractSub3x4(); + hook.model = core::transpose(imguizmoM16InOut.model); { const auto& references = pass.scene->getResources().objects; const auto type = static_cast(gcIndex); @@ -382,6 +400,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication } } + // view matrices editor { ImGui::Begin("Matrices"); @@ -413,6 +432,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication ImGui::End(); } + */ // Nabla Imgui backend MDI buffer info // To be 100% accurate and not overly conservative we'd have to explicitly `cull_frees` and defragment each time, @@ -491,27 +511,18 @@ class UISampleApp final : public examples::SimpleWindowedApplication m_surface->recreateSwapchain(); m_winMgr->show(m_window.get()); oracle.reportBeginFrameRecord(); - camera.mapKeysToArrows(); /* TESTS, TODO: remove all once finished work & integrate with the example properly */ - using cube_projection_t = CCubeProjection; - using constraints_t = CCubeProjection<>::constraints_t; - using camera_control_t = ICameraController; - using gimbal_t = camera_control_t::CGimbal; - - cube_projection_t cubeProjection; // can init all at construction, but will init only first for tests - auto& projections = cubeProjection.getCubeFaceProjections(); - auto firstFaceProjection = projections.front(); - firstFaceProjection = make_smart_refctd_ptr(glm::perspectiveLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar)); - const float32_t3 position(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance), target(0.f, 0.f, 0.f), up(0.f, 1.f, 0.f); - auto gimbal = make_smart_refctd_ptr(smart_refctd_ptr(firstFaceProjection), position, target, up); - auto controller = make_smart_refctd_ptr(smart_refctd_ptr(gimbal)); + auto pMatrix = glm::perspectiveLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar); + auto projection = make_smart_refctd_ptr(); // TODO: CASTS FOR PROJ + gimbal = make_smart_refctd_ptr(smart_refctd_ptr(projection), position, target, up); + camera = make_smart_refctd_ptr(smart_refctd_ptr(gimbal)); // note we still have shared ownership, TESTS return true; } @@ -690,8 +701,8 @@ class UISampleApp final : public examples::SimpleWindowedApplication inline void update() { - camera.setMoveSpeed(moveSpeed); - camera.setRotateSpeed(rotateSpeed); + camera->setMoveSpeed(moveSpeed); + camera->setRotateSpeed(rotateSpeed); static std::chrono::microseconds previousEventTimestamp{}; @@ -716,47 +727,40 @@ class UISampleApp final : public examples::SimpleWindowedApplication std::vector mouse{}; std::vector keyboard{}; } capturedEvents; + + if (move) + camera->begin(nextPresentationTimestamp); - if (move) camera.beginInputProcessing(nextPresentationTimestamp); + mouse.consumeEvents([&](const IMouseEventChannel::range_t& events) -> void { - mouse.consumeEvents([&](const IMouseEventChannel::range_t& events) -> void + for (const auto& e : events) // here capture { - if (move) - camera.mouseProcess(events); // don't capture the events, only let camera handle them with its impl + if (e.timeStamp < previousEventTimestamp) + continue; - for (const auto& e : events) // here capture - { - if (e.timeStamp < previousEventTimestamp) - continue; - - previousEventTimestamp = e.timeStamp; - capturedEvents.mouse.emplace_back(e); + previousEventTimestamp = e.timeStamp; + capturedEvents.mouse.emplace_back(e); - if (e.type == nbl::ui::SMouseEvent::EET_SCROLL) - gcIndex = std::clamp(int16_t(gcIndex) + int16_t(core::sign(e.scrollEvent.verticalScroll)), int64_t(0), int64_t(OT_COUNT - (uint8_t)1u)); - } - }, m_logger.get()); + if (e.type == nbl::ui::SMouseEvent::EET_SCROLL) + gcIndex = std::clamp(int16_t(gcIndex) + int16_t(core::sign(e.scrollEvent.verticalScroll)), int64_t(0), int64_t(OT_COUNT - (uint8_t)1u)); + } + }, m_logger.get()); keyboard.consumeEvents([&](const IKeyboardEventChannel::range_t& events) -> void + { + for (const auto& e : events) // here capture { - if (move) - camera.keyboardProcess(events); // don't capture the events, only let camera handle them with its impl - - for (const auto& e : events) // here capture - { - if (e.timeStamp < previousEventTimestamp) - continue; + if (e.timeStamp < previousEventTimestamp) + continue; - previousEventTimestamp = e.timeStamp; - capturedEvents.keyboard.emplace_back(e); - } - }, m_logger.get()); - } - if (move) camera.endInputProcessing(nextPresentationTimestamp); + previousEventTimestamp = e.timeStamp; + capturedEvents.keyboard.emplace_back(e); + } + }, m_logger.get()); const auto cursorPosition = m_window->getCursorControl()->getPosition(); - nbl::ext::imgui::UI::SUpdateParameters params = + nbl::ext::imgui::UI::SUpdateParameters params = { .mousePosition = nbl::hlsl::float32_t2(cursorPosition.x, cursorPosition.y) - nbl::hlsl::float32_t2(m_window->getX(), m_window->getY()), .displaySize = { m_window->getWidth(), m_window->getHeight() }, @@ -764,6 +768,12 @@ class UISampleApp final : public examples::SimpleWindowedApplication .keyboardEvents = { capturedEvents.keyboard.data(), capturedEvents.keyboard.size() } }; + if (move) + { + camera->manipulate({ .mouseEvents = params.mouseEvents, .keyboardEvents = params.keyboardEvents, }); + camera->end(nextPresentationTimestamp); + } + pass.ui.manager->update(params); } @@ -805,7 +815,8 @@ class UISampleApp final : public examples::SimpleWindowedApplication C_UI ui; } pass; - Camera camera = Camera(core::vectorSIMDf(0, 0, 0), core::vectorSIMDf(0, 0, 0), core::matrix4SIMD()); + core::smart_refctd_ptr gimbal; + core::smart_refctd_ptr camera; video::CDumbPresentationOracle oracle; uint16_t gcIndex = {}; // note: this is dirty however since I assume only single object in scene I can leave it now, when this example is upgraded to support multiple objects this needs to be changed diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index b2a56cead..401c5aa4e 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -15,195 +15,132 @@ // FPS Camera, we will have more types soon +namespace nbl::hlsl // TODO: DIFFERENT NAMESPACE +{ + template class Camera : public ICameraController { public: - using matrix_t = T; - - Camera() = default; + using matrix_t = typename T; + using base_t = typename ICameraController; + using gimbal_t = typename base_t::CGimbal; + using gimbal_virtual_event_t = typename gimbal_t::CVirtualEvent; + using controller_virtual_event_t = typename base_t::CVirtualEvent; + + Camera(core::smart_refctd_ptr&& gimbal) + : base_t(core::smart_refctd_ptr(gimbal)) {} ~Camera() = default; - /* - TODO: controller + gimbal to do all of this -> override virtual manipulate method - */ - public: - void mouseProcess(const nbl::ui::IMouseEventChannel::range_t& events) + void manipulate(base_t::SUpdateParameters parameters) { - for (auto eventIt=events.begin(); eventIt!=events.end(); eventIt++) + auto* gimbal = base_t::m_gimbal.get(); + + auto process = [&](const std::vector& virtualEvents) -> void { - auto ev = *eventIt; + const auto forward = gimbal->getForwardDirection(); + const auto up = gimbal->getPatchedUpVector(); + const bool leftHanded = gimbal->isLeftHanded(); - if(ev.type == nbl::ui::SMouseEvent::EET_CLICK && ev.clickEvent.mouseButton == nbl::ui::EMB_LEFT_BUTTON) - if(ev.clickEvent.action == nbl::ui::SMouseEvent::SClickEvent::EA_PRESSED) - mouseDown = true; - else if (ev.clickEvent.action == nbl::ui::SMouseEvent::SClickEvent::EA_RELEASED) - mouseDown = false; + // strafe vector we move along when requesting left/right movements + const auto strafeLeftRight = leftHanded ? glm::normalize(glm::cross(forward, up)) : glm::normalize(glm::cross(up, forward)); - if(ev.type == nbl::ui::SMouseEvent::EET_MOVEMENT && mouseDown) - { - nbl::core::vectorSIMDf pos = getPosition(); - nbl::core::vectorSIMDf localTarget = getTarget() - pos; - - // Get Relative Rotation for localTarget in Radians - float relativeRotationX, relativeRotationY; - relativeRotationY = atan2(localTarget.X, localTarget.Z); - const double z1 = nbl::core::sqrt(localTarget.X*localTarget.X + localTarget.Z*localTarget.Z); - relativeRotationX = atan2(z1, localTarget.Y) - nbl::core::PI()/2; - - constexpr float RotateSpeedScale = 0.003f; - relativeRotationX -= ev.movementEvent.relativeMovementY * rotateSpeed * RotateSpeedScale * -1.0f; - float tmpYRot = ev.movementEvent.relativeMovementX * rotateSpeed * RotateSpeedScale * -1.0f; - - if (leftHanded) - relativeRotationY -= tmpYRot; - else - relativeRotationY += tmpYRot; - - const double MaxVerticalAngle = nbl::core::radians(88.0f); - - if (relativeRotationX > MaxVerticalAngle*2 && relativeRotationX < 2 * nbl::core::PI()-MaxVerticalAngle) - relativeRotationX = 2 * nbl::core::PI()-MaxVerticalAngle; - else - if (relativeRotationX > MaxVerticalAngle && relativeRotationX < 2 * nbl::core::PI()-MaxVerticalAngle) - relativeRotationX = MaxVerticalAngle; - - localTarget.set(0,0, nbl::core::max(1.f, nbl::core::length(pos)[0]), 1.f); - - nbl::core::matrix3x4SIMD mat; - mat.setRotation(nbl::core::quaternion(relativeRotationX, relativeRotationY, 0)); - mat.transformVect(localTarget); - - setTarget(localTarget + pos); - } - } - } + constexpr auto MoveSpeedScale = 0.003f; + constexpr auto RotateSpeedScale = 0.003f; - void keyboardProcess(const nbl::ui::IKeyboardEventChannel::range_t& events) - { - for(uint32_t k = 0; k < E_CAMERA_MOVE_KEYS::ECMK_COUNT; ++k) - perActionDt[k] = 0.0; + const auto dMoveFactor = base_t::m_moveSpeed * MoveSpeedScale; + const auto dRotateFactor = base_t::m_rotateSpeed * RotateSpeedScale; - /* - * If a Key was already being held down from previous frames - * Compute with this assumption that the key will be held down for this whole frame as well, - * And If an UP event was sent It will get subtracted it from this value. (Currently Disabled Because we Need better Oracle) - */ + // TODO: UB/LB for pitch [-88,88]!!! we are not in cosmos but handle FPS camera - for(uint32_t k = 0; k < E_CAMERA_MOVE_KEYS::ECMK_COUNT; ++k) - if(keysDown[k]) + for (const controller_virtual_event_t& ev : virtualEvents) { - auto timeDiff = std::chrono::duration_cast(nextPresentationTimeStamp - lastVirtualUpTimeStamp).count(); - assert(timeDiff >= 0); - perActionDt[k] += timeDiff; + const auto dMoveValue = ev.value * dMoveFactor; + const auto dRotateValue = ev.value * dRotateFactor; + + gimbal_virtual_event_t gimbalEvent; + + switch (ev.type) + { + case base_t::MoveForward: + { + gimbalEvent.type = gimbal_t::Strafe; + gimbalEvent.manipulation.strafe.direction = forward; + gimbalEvent.manipulation.strafe.distance = dMoveValue; + } break; + + case base_t::MoveBackward: + { + gimbalEvent.type = gimbal_t::Strafe; + gimbalEvent.manipulation.strafe.direction = -forward; + gimbalEvent.manipulation.strafe.distance = dMoveValue; + } break; + + case base_t::MoveLeft: + { + gimbalEvent.type = gimbal_t::Strafe; + gimbalEvent.manipulation.strafe.direction = -strafeLeftRight; + gimbalEvent.manipulation.strafe.distance = dMoveValue; + } break; + + case base_t::MoveRight: + { + gimbalEvent.type = gimbal_t::Strafe; + gimbalEvent.manipulation.strafe.direction = strafeLeftRight; + gimbalEvent.manipulation.strafe.distance = dMoveValue; + } break; + + case base_t::TiltUp: + { + gimbalEvent.type = gimbal_t::Rotate; + gimbalEvent.manipulation.rotation.pitch = dRotateValue; + gimbalEvent.manipulation.rotation.roll = 0.0f; + gimbalEvent.manipulation.rotation.yaw = 0.0f; + } break; + + case base_t::TiltDown: + { + gimbalEvent.type = gimbal_t::Rotate; + gimbalEvent.manipulation.rotation.pitch = -dRotateValue; + gimbalEvent.manipulation.rotation.roll = 0.0f; + gimbalEvent.manipulation.rotation.yaw = 0.0f; + } break; + + case base_t::PanLeft: + { + gimbalEvent.type = gimbal_t::Rotate; + gimbalEvent.manipulation.rotation.pitch = 0.0f; + gimbalEvent.manipulation.rotation.roll = 0.0f; + gimbalEvent.manipulation.rotation.yaw = -dRotateValue; + } break; + + case base_t::PanRight: + { + gimbalEvent.type = gimbal_t::Rotate; + gimbalEvent.manipulation.rotation.pitch = 0.0f; + gimbalEvent.manipulation.rotation.roll = 0.0f; + gimbalEvent.manipulation.rotation.yaw = dRotateValue; + } break; + + default: + continue; + } + + gimbal->manipulate(gimbalEvent); } + }; - for (auto eventIt=events.begin(); eventIt!=events.end(); eventIt++) + gimbal->begin(); { - const auto ev = *eventIt; - - // accumulate the periods for which a key was down - const auto timeDiff = std::chrono::duration_cast(nextPresentationTimeStamp - ev.timeStamp).count(); - assert(timeDiff >= 0); - - // handle camera movement - for (const auto logicalKey : { ECMK_MOVE_FORWARD, ECMK_MOVE_BACKWARD, ECMK_MOVE_LEFT, ECMK_MOVE_RIGHT }) - { - const auto code = keysMap[logicalKey]; - - if (ev.keyCode == code) - { - if (ev.action == nbl::ui::SKeyboardEvent::ECA_PRESSED && !keysDown[logicalKey]) - { - perActionDt[logicalKey] += timeDiff; - keysDown[logicalKey] = true; - } - else if (ev.action == nbl::ui::SKeyboardEvent::ECA_RELEASED) - { - // perActionDt[logicalKey] -= timeDiff; - keysDown[logicalKey] = false; - } - } - } - - // handle reset to default state - if (ev.keyCode == nbl::ui::EKC_HOME) - if (ev.action == nbl::ui::SKeyboardEvent::ECA_RELEASED) - { - position = initialPosition; - target = initialTarget; - recomputeViewMatrix(); - } + process(base_t::processMouse(parameters.mouseEvents)); + process(base_t::processKeyboard(parameters.keyboardEvents)); } - } - - void beginInputProcessing(std::chrono::microseconds _nextPresentationTimeStamp) - { - nextPresentationTimeStamp = _nextPresentationTimeStamp; - return; - } - - void endInputProcessing(std::chrono::microseconds _nextPresentationTimeStamp) - { - nbl::core::vectorSIMDf pos = getPosition(); - nbl::core::vectorSIMDf localTarget = getTarget() - pos; - - if (!firstUpdate) - { - nbl::core::vectorSIMDf movedir = localTarget; - movedir.makeSafe3D(); - movedir = nbl::core::normalize(movedir); - - constexpr float MoveSpeedScale = 0.02f; - - pos += movedir * perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_FORWARD] * moveSpeed * MoveSpeedScale; - pos -= movedir * perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_BACKWARD] * moveSpeed * MoveSpeedScale; - - // strafing - - // if upvector and vector to the target are the same, we have a - // problem. so solve this problem: - nbl::core::vectorSIMDf up = nbl::core::normalize(upVector); - nbl::core::vectorSIMDf cross = nbl::core::cross(localTarget, up); - bool upVectorNeedsChange = nbl::core::lengthsquared(cross)[0] == 0; - if (upVectorNeedsChange) - { - up = nbl::core::normalize(backupUpVector); - } - - nbl::core::vectorSIMDf strafevect = localTarget; - if (leftHanded) - strafevect = nbl::core::cross(strafevect, up); - else - strafevect = nbl::core::cross(up, strafevect); - - strafevect = nbl::core::normalize(strafevect); - - pos += strafevect * perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_LEFT] * moveSpeed * MoveSpeedScale; - pos -= strafevect * perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_RIGHT] * moveSpeed * MoveSpeedScale; - } - else - firstUpdate = false; - - setPosition(pos); - setTarget(localTarget+pos); - - lastVirtualUpTimeStamp = nextPresentationTimeStamp; - } - -private: - - inline void initDefaultKeysMap() { mapKeysToWASD(); } - - inline void allKeysUp() - { - for (uint32_t i=0; i< E_CAMERA_MOVE_KEYS::ECMK_COUNT; ++i) - keysDown[i] = false; - - mouseDown = false; + gimbal->end(); } }; +} + #endif // _CAMERA_IMPL_ \ No newline at end of file diff --git a/common/include/CGeomtryCreatorScene.hpp b/common/include/CGeomtryCreatorScene.hpp index ab90f59b9..547c0aaf7 100644 --- a/common/include/CGeomtryCreatorScene.hpp +++ b/common/include/CGeomtryCreatorScene.hpp @@ -1098,7 +1098,7 @@ class ResourceBuilder struct ObjectDrawHookCpu { - nbl::core::matrix3x4SIMD model; + nbl::hlsl::float32_t4x4 model; nbl::asset::SBasicViewParameters viewParameters; ObjectMeta meta; }; diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 9dfe758f1..c52558438 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -60,10 +60,19 @@ class ICameraController : virtual public core::IReferenceCounted EventsCount }; + //! Virtual event representing a manipulation + struct CVirtualEvent + { + using manipulation_encode_t = float64_t; + + VirtualEventType type; + manipulation_encode_t value; + }; + class CGimbal : virtual public core::IReferenceCounted { public: - //! Virtual event representing a manipulation + //! Virtual event representing a combined gimbal manipulation enum VirtualEventType { //! Move the camera in the direction of strafe vector @@ -111,31 +120,20 @@ class ICameraController : virtual public core::IReferenceCounted ~ManipulationValue() {} }; - CVirtualEvent(VirtualEventType type, const ManipulationValue manipulation) - : m_type(type), m_manipulation(manipulation) - { - static_assert(sizeof(manipulation_encode_t) == sizeof(ManipulationValue)); - } - - // Returns the type of manipulation value - VirtualEventType getType() const - { - return m_type; - } + CVirtualEvent() {} - // Returns manipulation value - ManipulationValue getManipulation() const + CVirtualEvent(VirtualEventType _type, const ManipulationValue _manipulation) + : type(_type), manipulation(_manipulation) { - return m_manipulation; + static_assert(sizeof(manipulation_encode_t) == sizeof(ManipulationValue)); } - private: - VirtualEventType m_type; - ManipulationValue m_manipulation; + VirtualEventType type; + ManipulationValue manipulation; }; CGimbal(const core::smart_refctd_ptr&& projection, const float32_t3& position, const float32_t3& lookat, const float32_t3& upVec = float32_t3(0.0f, 1.0f, 0.0f), const float32_t3& backupUpVec = float32_t3(0.5f, 1.0f, 0.0f)) - : m_projection(projection), m_position(position), m_target(lookat), m_upVec(upVec), m_backupUpVec(backupUpVec), m_initialPosition(position), m_initialTarget(lookat), m_orientation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)), m_viewMatrix({}), m_isLeftHanded(isLeftHanded(m_projection->getProjectionMatrix())) + : m_projection(projection), m_position(position), m_target(lookat), m_upVec(upVec), m_backupUpVec(backupUpVec), m_initialPosition(position), m_initialTarget(lookat), m_orientation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)), m_viewMatrix({}), m_isLeftHanded(checkIfLeftHanded(m_projection->getProjectionMatrix())) { recomputeViewMatrix(); } @@ -155,26 +153,29 @@ class ICameraController : virtual public core::IReferenceCounted if (!m_recordingManipulation) return; // TODO: log it - const auto manipulation = virtualEvent.getManipulation(); + const auto& manipulation = virtualEvent.manipulation; - case VirtualEventType::Strafe: + switch (virtualEvent.type) { - strafe(manipulation.strafe.direction, manipulation.strafe.distance); - } break; - - case VirtualEventType::Rotate: - { - rotate(manipulation.rotation.pitch, manipulation.rotation.yaw, manipulation.rotation.roll); - } break; - - case VirtualEventType::State: - { - if (manipulation.state.reset) - reset(); - } break; - - default: - break; + case VirtualEventType::Strafe: + { + strafe(manipulation.strafe.direction, manipulation.strafe.distance); + } break; + + case VirtualEventType::Rotate: + { + rotate(manipulation.rotation.pitch, manipulation.rotation.yaw, manipulation.rotation.roll); + } break; + + case VirtualEventType::State: + { + if (manipulation.state.reset) + reset(); + } break; + + default: + break; + } } // Record change of position vector, global update @@ -204,7 +205,7 @@ class ICameraController : virtual public core::IReferenceCounted //! End the gimbal manipulation session, recompute view matrix if required and update handedness state from projection inline void end() { - m_isLeftHanded = isLeftHanded(m_projection->getProjectionMatrix()); + m_isLeftHanded = checkIfLeftHanded(m_projection->getProjectionMatrix()); if (m_needsToRecomputeViewMatrix) recomputeViewMatrix(); @@ -213,13 +214,32 @@ class ICameraController : virtual public core::IReferenceCounted m_recordingManipulation = false; } + inline projection_t* getProjection() { return m_projection.get(); } inline const float32_t3& getPosition() const { return m_position; } inline const float32_t3& getTarget() const { return m_target; } inline const float32_t3& getUpVector() const { return m_upVec; } inline const float32_t3& getBackupUpVector() const { return m_backupUpVec; } inline const float32_t3 getLocalTarget() const { return m_target - m_position; } inline const float32_t3 getForwardDirection() const { return glm::normalize(getLocalTarget()); } - inline const projection_t* getProjection() { return m_projection.get(); } + inline const float32_t4x4& getViewMatrix() const { return m_viewMatrix; } + inline bool isLeftHanded() { return m_isLeftHanded; } + + inline float32_t3 getPatchedUpVector() + { + // if up vector and vector to the target are the same we patch the up vector + auto up = glm::normalize(m_upVec); + + const auto localTarget = getForwardDirection(); + const auto cross = glm::cross(localTarget, up); + + // we compute squared length but for checking if the len is 0 it doesnt matter + const bool upVectorZeroLength = glm::dot(cross, cross) == 0.f; + + if (upVectorZeroLength) + up = glm::normalize(m_backupUpVec); + + return up; + } // TODO: getConcatenatedMatrix() // TODO: getViewMatrix() @@ -257,7 +277,7 @@ class ICameraController : virtual public core::IReferenceCounted // Rotate around Y (yaw) glm::quat qYaw = glm::angleAxis(dYawDeltaRadians, glm::vec3(0.0f, 1.0f, 0.0f)); - // Rotate around Z (roll) // TODO: handness!! + // Rotate around Z (roll) glm::quat qRoll = glm::angleAxis(dRollDeltaRadians, glm::vec3(0.0f, 0.0f, 1.0f)); // Combine the new rotations with the current orientation @@ -280,30 +300,17 @@ class ICameraController : virtual public core::IReferenceCounted { auto up = getPatchedUpVector(); + // TODO!!!! CASTS + + /* if (m_isLeftHanded) m_viewMatrix = glm::lookAtLH(m_position, m_target, up); else m_viewMatrix = glm::lookAtRH(m_position, m_target, up); + */ } - inline float32_t3 getPatchedUpVector() - { - // if up vector and vector to the target are the same we patch the up vector - auto up = glm::normalize(m_upVec); - - const auto localTarget = getForwardDirection(); - const auto cross = glm::cross(localTarget, up); - - // we compute squared length but for checking if the len is 0 it doesnt matter - const bool upVectorZeroLength = glm::dot(cross, cross) == 0.f; - - if (upVectorZeroLength) - up = glm::normalize(m_backupUpVec); - - return up; - } - - inline bool isLeftHanded(const auto& projectionMatrix) + inline bool checkIfLeftHanded(const auto& projectionMatrix) { return hlsl::determinant(projectionMatrix) < 0.f; } @@ -313,35 +320,24 @@ class ICameraController : virtual public core::IReferenceCounted const float32_t3 m_initialPosition, m_initialTarget; glm::quat m_orientation; - float64_t4x4 m_viewMatrix; + float32_t4x4 m_viewMatrix; bool m_isLeftHanded, m_needsToRecomputeViewMatrix = false, m_recordingManipulation = false; }; - ICameraController() : {} + struct SUpdateParameters + { + //! Nabla mouse events you want to be handled with a controller + std::span mouseEvents = {}; - // controller overrides how a manipulation is done for a given camera event with a gimbal - virtual void manipulate(CGimbal* gimbal, VirtualEventType event) = 0; + //! Nabla keyboard events you want to be handled with a controller + std::span keyboardEvents = {}; + }; - // controller can override default set of event map - virtual void initKeysToEvent() - { - m_keysToEvent[MoveForward] = { ui::E_KEY_CODE::EKC_W }; - m_keysToEvent[MoveBackward] = { ui::E_KEY_CODE::EKC_S }; - m_keysToEvent[MoveLeft] = { ui::E_KEY_CODE::EKC_A }; - m_keysToEvent[MoveRight] = { ui::E_KEY_CODE::EKC_D }; - m_keysToEvent[MoveUp] = { ui::E_KEY_CODE::EKC_SPACE }; - m_keysToEvent[MoveDown] = { ui::E_KEY_CODE::EKC_LEFT_SHIFT }; - m_keysToEvent[TiltUp] = { ui::E_KEY_CODE::EKC_NONE }; - m_keysToEvent[TiltDown] = { ui::E_KEY_CODE::EKC_NONE }; - m_keysToEvent[PanLeft] = { ui::E_KEY_CODE::EKC_NONE }; - m_keysToEvent[PanRight] = { ui::E_KEY_CODE::EKC_NONE }; - m_keysToEvent[RollLeft] = { ui::E_KEY_CODE::EKC_NONE }; - m_keysToEvent[RollRight] = { ui::E_KEY_CODE::EKC_NONE }; - m_keysToEvent[Reset] = { ui::E_KEY_CODE::EKC_R }; - } + ICameraController(core::smart_refctd_ptr&& gimbal) + : m_gimbal(core::smart_refctd_ptr(gimbal)) {} // controller can override which keys correspond to which event void updateKeysToEvent(const std::vector& codes, VirtualEventType event) @@ -349,26 +345,121 @@ class ICameraController : virtual public core::IReferenceCounted m_keysToEvent[event] = std::move(codes); } -protected: + virtual void begin(std::chrono::microseconds nextPresentationTimeStamp) + { + m_nextPresentationTimeStamp = nextPresentationTimeStamp; + return; + } - inline void setMoveSpeed(const float moveSpeed) { moveSpeed = m_moveSpeed; } - inline void setRotateSpeed(const float rotateSpeed) { rotateSpeed = m_rotateSpeed; } + virtual void manipulate(SUpdateParameters parameters) = 0; + + void end(std::chrono::microseconds nextPresentationTimeStamp) + { + m_lastVirtualUpTimeStamp = nextPresentationTimeStamp; + } + + inline void setMoveSpeed(const float moveSpeed) { m_moveSpeed = moveSpeed; } + inline void setRotateSpeed(const float rotateSpeed) { m_rotateSpeed = rotateSpeed; } inline const float getMoveSpeed() const { return m_moveSpeed; } inline const float getRotateSpeed() const { return m_rotateSpeed; } - std::array, EventsCount> m_keysToEvent = {}; +protected: + // process keyboard to generate virtual manipulation events + std::vector processKeyboard(std::span events) + { + std::vector virtualEvents; - // speed factors - float m_moveSpeed = 1.f, m_rotateSpeed = 1.f; + for (const auto& ev : events) + { + constexpr auto NblVirtualKeys = std::to_array({ MoveForward, MoveBackward, MoveLeft, MoveRight, MoveUp, MoveDown, TiltUp, TiltDown, PanLeft, PanRight, RollLeft, RollRight, Reset }); + static_assert(NblVirtualKeys.size() == EventsCount); - // states signaling if keys are pressed down or not - bool m_keysDown[EventsCount] = {}; + for (const auto virtualKey : NblVirtualKeys) + { + const auto code = m_keysToEvent[virtualKey]; + + if (ev.keyCode == code) + { + if (code == ui::EKC_NONE) + continue; + + const auto dt = std::chrono::duration_cast(m_nextPresentationTimeStamp - ev.timeStamp).count(); + assert(dt >= 0); + + if (ev.action == nbl::ui::SKeyboardEvent::ECA_PRESSED && !m_keysDown[virtualKey]) + { + m_keysDown[virtualKey] = true; + virtualEvents.emplace_back(CVirtualEvent{ virtualKey, static_cast(dt) }); + } + else if (ev.action == nbl::ui::SKeyboardEvent::ECA_RELEASED) + { + m_keysDown[virtualKey] = false; + } + } + } + } + + return virtualEvents; + } + + /* + // [OPTIONAL]: process mouse to generate virtual manipulation events + // note: + // - all manipulations *may* be done with keyboard keys, it means you can have a pad/touch pad for which keys could be bound and skip the mouse + // - default implementation which is FPS camera-like controller doesn't perform roll rotation which is around Z axis! If you want more complex manipulations then override the method + // - it doesn't make the manipulation itself! It only process your mouse events you got from OS & accumulate data values to create manipulation virtual events! + */ + virtual std::vector processMouse(std::span events) const + { + // accumulate total pitch & yaw delta from mouse movement events + const auto [dTotalPitch, dTotalYaw] = [&]() + { + double dPitch = {}, dYaw = {}; + + for (const auto& ev : events) + if (ev.type == nbl::ui::SMouseEvent::EET_MOVEMENT) + { + dYaw += ev.movementEvent.relativeMovementX; // (yaw) + dPitch -= ev.movementEvent.relativeMovementY; // (pitch) + } + + return std::make_tuple(dPitch, dYaw); + }(); - // durations for which the key was being held down from lastVirtualUpTimeStamp(=last "guessed" presentation time) to nextPresentationTimeStamp - double m_perActionDt[EventsCount] = {}; + CVirtualEvent pitch; + pitch.type = (pitch.value = dTotalPitch) > 0.f ? TiltUp : TiltDown; + + CVirtualEvent yaw; + yaw.type = (yaw.value = dTotalYaw) > 0.f ? PanRight : PanLeft; + + return { pitch, yaw }; + } + + // controller can override default set of event map + virtual void initKeysToEvent() + { + m_keysToEvent[MoveForward] = ui::E_KEY_CODE::EKC_W ; + m_keysToEvent[MoveBackward] = ui::E_KEY_CODE::EKC_S ; + m_keysToEvent[MoveLeft] = ui::E_KEY_CODE::EKC_A ; + m_keysToEvent[MoveRight] = ui::E_KEY_CODE::EKC_D ; + m_keysToEvent[MoveUp] = ui::E_KEY_CODE::EKC_SPACE ; + m_keysToEvent[MoveDown] = ui::E_KEY_CODE::EKC_LEFT_SHIFT ; + m_keysToEvent[TiltUp] = ui::E_KEY_CODE::EKC_NONE ; + m_keysToEvent[TiltDown] = ui::E_KEY_CODE::EKC_NONE ; + m_keysToEvent[PanLeft] = ui::E_KEY_CODE::EKC_NONE ; + m_keysToEvent[PanRight] = ui::E_KEY_CODE::EKC_NONE ; + m_keysToEvent[RollLeft] = ui::E_KEY_CODE::EKC_NONE ; + m_keysToEvent[RollRight] = ui::E_KEY_CODE::EKC_NONE ; + m_keysToEvent[Reset] = ui::E_KEY_CODE::EKC_R ; + } + + core::smart_refctd_ptr m_gimbal; + std::array m_keysToEvent = {}; + float m_moveSpeed = 1.f, m_rotateSpeed = 1.f; + bool m_keysDown[EventsCount] = {}; - std::chrono::microseconds nextPresentationTimeStamp, lastVirtualUpTimeStamp; + std::chrono::microseconds m_nextPresentationTimeStamp, m_lastVirtualUpTimeStamp; }; } // nbl::hlsl namespace From 13df456b76c4e38996502fc71d9878334fd5ea18 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Fri, 25 Oct 2024 03:08:03 -0700 Subject: [PATCH 11/83] Saving work --- 09_GeometryCreator/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/09_GeometryCreator/main.cpp b/09_GeometryCreator/main.cpp index daafdb247..edbec9e4b 100644 --- a/09_GeometryCreator/main.cpp +++ b/09_GeometryCreator/main.cpp @@ -307,7 +307,7 @@ class GeometryCreatorApp final : public examples::SimpleWindowedApplication hlsl::float32_t3x4 modelMatrix; hlsl::setTranslation(modelMatrix, hlsl::float32_t3(0)); - hlsl::setRotation(modelMatrix, quaternion(0, 0, 0)); + hlsl::setRotation(modelMatrix, hlsl::quaternion(0, 0, 0)); hlsl::float32_t3x4 modelViewMatrix = hlsl::concatenateBFollowedByA(viewMatrix, modelMatrix); hlsl::float32_t4x4 modelViewProjectionMatrix = mul(viewProjectionMatrix, hlsl::getMatrix3x4As4x4(modelMatrix)); From 038c5d799269a026ffa71e48f5963013632e4634 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Fri, 25 Oct 2024 14:13:35 +0200 Subject: [PATCH 12/83] create ICamera.hpp interface for all types of cameraz, update IProjection with isLeftHanded method, update sources & some of matrices to HLSL - the pure virtual controller manipulate method now takes a gimbal + span of virtual events --- 61_UI/main.cpp | 71 +++---- common/include/CCamera.hpp | 233 +++++++++++------------ common/include/CGeomtryCreatorScene.hpp | 2 +- common/include/ICamera.hpp | 40 ++++ common/include/camera/ICameraControl.hpp | 72 +++---- common/include/camera/IProjection.hpp | 5 + 6 files changed, 222 insertions(+), 201 deletions(-) create mode 100644 common/include/ICamera.hpp diff --git a/61_UI/main.cpp b/61_UI/main.cpp index 374719bab..c78059ae5 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -7,9 +7,11 @@ #include "camera/CCubeProjection.hpp" #include "camera/ICameraControl.hpp" #include "glm/glm/ext/matrix_clip_space.hpp" // TODO: TESTING +#include "nbl/builtin/hlsl/matrix_utils/transformation_matrix_utils.hlsl" // FPS Camera, TESTS -using camera_t = Camera; +using projection_matrix_t = float32_t4x4; +using camera_t = Camera; using gimbal_t = camera_t::CGimbal; using projection_t = camera_t::base_t::projection_t; @@ -177,29 +179,23 @@ class UISampleApp final : public examples::SimpleWindowedApplication ImGuiIO& io = ImGui::GetIO(); { auto& projection = gimbal->getProjection()->getProjectionMatrix(); - - - // TODO CASTS - - /* if (isPerspective) { if (isLH) - projection = glm::perspectiveLH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); + projection = projection_t::value_t(glm::perspectiveLH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); else - projection = glm::perspectiveRH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); + projection = projection_t::value_t(glm::perspectiveRH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); } else { float viewHeight = viewWidth * io.DisplaySize.y / io.DisplaySize.x; if (isLH) - projection = glm::orthoLH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar); + projection = projection_t::value_t(glm::orthoLH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar)); else - projection = glm::orthoRH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar); + projection = projection_t::value_t(glm::orthoRH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar)); } - */ } ImGuizmo::SetOrthographic(false); @@ -335,14 +331,22 @@ class UISampleApp final : public examples::SimpleWindowedApplication * note it also modifies input view matrix but projection matrix is immutable */ + + + /* + + TODODOD + + + + static struct { float32_t4x4 view, projection, model; } imguizmoM16InOut; ImGuizmo::SetID(0u); - - imguizmoM16InOut.view = transpose(gimbal->getViewMatrix()); + imguizmoM16InOut.view = transpose(getMatrix3x4As4x4(gimbal->getViewMatrix())); imguizmoM16InOut.projection = transpose(gimbal->getProjection()->getProjectionMatrix()); imguizmoM16InOut.model = transpose(pass.scene->object.model); { @@ -353,26 +357,19 @@ class UISampleApp final : public examples::SimpleWindowedApplication EditTransform(&imguizmoM16InOut.view[0][0], &imguizmoM16InOut.projection[0][0], &imguizmoM16InOut.model[0][0], transformParams); } - // to Nabla + update camera & model matrices const auto& view = gimbal->getViewMatrix(); const auto& projection = gimbal->getProjection()->getProjectionMatrix(); - - - /* - - TODO!!! - - + // TODO: make it more nicely - const_cast(view) = transpose(imguizmoM16InOut.view); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) - camera.setProjectionMatrix(projection); // update concatanated matrix + const_cast(view) = float32_t3x4(transpose(imguizmoM16InOut.view)); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) + //camera.setProjectionMatrix(projection); // update concatanated matrix { - static nbl::core::matrix3x4SIMD modelView, normal; - static nbl::core::matrix4SIMD modelViewProjection; + static float32_t3x4 modelView, normal; + static float32_t4x4 modelViewProjection; auto& hook = pass.scene->object; - hook.model = core::transpose(imguizmoM16InOut.model); + hook.model = core::transpose(float32_t3x4(imguizmoM16InOut.model)); { const auto& references = pass.scene->getResources().objects; const auto type = static_cast(gcIndex); @@ -384,8 +381,10 @@ class UISampleApp final : public examples::SimpleWindowedApplication auto& ubo = hook.viewParameters; - modelView = nbl::core::concatenateBFollowedByA(view, hook.model); - modelView.getSub3x3InverseTranspose(normal); + modelView = concatenateBFollowedByA(view, hook.model); + + // TODO + //modelView.getSub3x3InverseTranspose(normal); modelViewProjection = nbl::core::concatenateBFollowedByA(camera.getConcatenatedMatrix(), hook.model); memcpy(ubo.MVP, modelViewProjection.pointer(), sizeof(ubo.MVP)); @@ -432,7 +431,8 @@ class UISampleApp final : public examples::SimpleWindowedApplication ImGui::End(); } - */ + + */ // Nabla Imgui backend MDI buffer info // To be 100% accurate and not overly conservative we'd have to explicitly `cull_frees` and defragment each time, @@ -522,7 +522,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication auto pMatrix = glm::perspectiveLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar); auto projection = make_smart_refctd_ptr(); // TODO: CASTS FOR PROJ gimbal = make_smart_refctd_ptr(smart_refctd_ptr(projection), position, target, up); - camera = make_smart_refctd_ptr(smart_refctd_ptr(gimbal)); // note we still have shared ownership, TESTS + camera = make_smart_refctd_ptr(); return true; } @@ -770,7 +770,14 @@ class UISampleApp final : public examples::SimpleWindowedApplication if (move) { - camera->manipulate({ .mouseEvents = params.mouseEvents, .keyboardEvents = params.keyboardEvents, }); + const auto virtualMouseEvents = camera->processMouse(params.mouseEvents); + const auto virtualKeyboardEvents = camera->processMouse(params.mouseEvents); + + gimbal->begin(); + camera->manipulate(gimbal.get(), { virtualMouseEvents.data(), virtualMouseEvents.size()}); + camera->manipulate(gimbal.get(), { virtualKeyboardEvents.data(), virtualKeyboardEvents.size()}); + gimbal->end(); + camera->end(nextPresentationTimestamp); } @@ -816,7 +823,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication } pass; core::smart_refctd_ptr gimbal; - core::smart_refctd_ptr camera; + core::smart_refctd_ptr> camera; video::CDumbPresentationOracle oracle; uint16_t gcIndex = {}; // note: this is dirty however since I assume only single object in scene I can leave it now, when this example is upgraded to support multiple objects this needs to be changed diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 401c5aa4e..1c306c651 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -2,145 +2,126 @@ // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h -#ifndef _CAMERA_IMPL_ -#define _CAMERA_IMPL_ +#ifndef _C_CAMERA_HPP_ +#define _C_CAMERA_HPP_ -#include -#include -#include -#include -#include - -#include "camera/ICameraControl.hpp" - -// FPS Camera, we will have more types soon +#include "ICamera.hpp" namespace nbl::hlsl // TODO: DIFFERENT NAMESPACE { +// FPS Camera template -class Camera : public ICameraController +class Camera : public ICamera { public: - using matrix_t = typename T; - using base_t = typename ICameraController; - using gimbal_t = typename base_t::CGimbal; - using gimbal_virtual_event_t = typename gimbal_t::CVirtualEvent; - using controller_virtual_event_t = typename base_t::CVirtualEvent; - - Camera(core::smart_refctd_ptr&& gimbal) - : base_t(core::smart_refctd_ptr(gimbal)) {} - ~Camera() = default; + using base_t = ICamera; + using traits_t = typename base_t::Traits; -public: + Camera() : base_t() {} + ~Camera() = default; - void manipulate(base_t::SUpdateParameters parameters) + virtual void manipulate(traits_t::gimbal_t* gimbal, std::span virtualEvents) override { - auto* gimbal = base_t::m_gimbal.get(); - - auto process = [&](const std::vector& virtualEvents) -> void - { - const auto forward = gimbal->getForwardDirection(); - const auto up = gimbal->getPatchedUpVector(); - const bool leftHanded = gimbal->isLeftHanded(); - - // strafe vector we move along when requesting left/right movements - const auto strafeLeftRight = leftHanded ? glm::normalize(glm::cross(forward, up)) : glm::normalize(glm::cross(up, forward)); - - constexpr auto MoveSpeedScale = 0.003f; - constexpr auto RotateSpeedScale = 0.003f; - - const auto dMoveFactor = base_t::m_moveSpeed * MoveSpeedScale; - const auto dRotateFactor = base_t::m_rotateSpeed * RotateSpeedScale; - - // TODO: UB/LB for pitch [-88,88]!!! we are not in cosmos but handle FPS camera - - for (const controller_virtual_event_t& ev : virtualEvents) - { - const auto dMoveValue = ev.value * dMoveFactor; - const auto dRotateValue = ev.value * dRotateFactor; - - gimbal_virtual_event_t gimbalEvent; - - switch (ev.type) - { - case base_t::MoveForward: - { - gimbalEvent.type = gimbal_t::Strafe; - gimbalEvent.manipulation.strafe.direction = forward; - gimbalEvent.manipulation.strafe.distance = dMoveValue; - } break; - - case base_t::MoveBackward: - { - gimbalEvent.type = gimbal_t::Strafe; - gimbalEvent.manipulation.strafe.direction = -forward; - gimbalEvent.manipulation.strafe.distance = dMoveValue; - } break; - - case base_t::MoveLeft: - { - gimbalEvent.type = gimbal_t::Strafe; - gimbalEvent.manipulation.strafe.direction = -strafeLeftRight; - gimbalEvent.manipulation.strafe.distance = dMoveValue; - } break; - - case base_t::MoveRight: - { - gimbalEvent.type = gimbal_t::Strafe; - gimbalEvent.manipulation.strafe.direction = strafeLeftRight; - gimbalEvent.manipulation.strafe.distance = dMoveValue; - } break; - - case base_t::TiltUp: - { - gimbalEvent.type = gimbal_t::Rotate; - gimbalEvent.manipulation.rotation.pitch = dRotateValue; - gimbalEvent.manipulation.rotation.roll = 0.0f; - gimbalEvent.manipulation.rotation.yaw = 0.0f; - } break; - - case base_t::TiltDown: - { - gimbalEvent.type = gimbal_t::Rotate; - gimbalEvent.manipulation.rotation.pitch = -dRotateValue; - gimbalEvent.manipulation.rotation.roll = 0.0f; - gimbalEvent.manipulation.rotation.yaw = 0.0f; - } break; - - case base_t::PanLeft: - { - gimbalEvent.type = gimbal_t::Rotate; - gimbalEvent.manipulation.rotation.pitch = 0.0f; - gimbalEvent.manipulation.rotation.roll = 0.0f; - gimbalEvent.manipulation.rotation.yaw = -dRotateValue; - } break; - - case base_t::PanRight: - { - gimbalEvent.type = gimbal_t::Rotate; - gimbalEvent.manipulation.rotation.pitch = 0.0f; - gimbalEvent.manipulation.rotation.roll = 0.0f; - gimbalEvent.manipulation.rotation.yaw = dRotateValue; - } break; - - default: - continue; - } - - gimbal->manipulate(gimbalEvent); - } - }; - - gimbal->begin(); - { - process(base_t::processMouse(parameters.mouseEvents)); - process(base_t::processKeyboard(parameters.keyboardEvents)); - } - gimbal->end(); + if (!gimbal) + return; // TODO: LOG + + if (!gimbal->isRecordingManipulation()) + return; // TODO: LOG + + const auto forward = gimbal->getForwardDirection(); + const auto up = gimbal->getPatchedUpVector(); + const bool leftHanded = gimbal->isLeftHanded(); + + // strafe vector we move along when requesting left/right movements + const auto strafeLeftRight = leftHanded ? glm::normalize(glm::cross(forward, up)) : glm::normalize(glm::cross(up, forward)); + + constexpr auto MoveSpeedScale = 0.003f; + constexpr auto RotateSpeedScale = 0.003f; + + const auto dMoveFactor = traits_t::controller_t::m_moveSpeed * MoveSpeedScale; + const auto dRotateFactor = traits_t::controller_t::m_rotateSpeed * RotateSpeedScale; + + // TODO: UB/LB for pitch [-88,88]!!! we are not in cosmos but handle FPS camera in default case + + for (const traits_t::controller_virtual_event_t& ev : virtualEvents) + { + const auto dMoveValue = ev.value * dMoveFactor; + const auto dRotateValue = ev.value * dRotateFactor; + + typename traits_t::gimbal_virtual_event_t gimbalEvent; + + switch (ev.type) + { + case traits_t::controller_t::MoveForward: + { + gimbalEvent.type = traits_t::gimbal_t::Strafe; + gimbalEvent.manipulation.strafe.direction = forward; + gimbalEvent.manipulation.strafe.distance = dMoveValue; + } break; + + case traits_t::controller_t::MoveBackward: + { + gimbalEvent.type = traits_t::gimbal_t::Strafe; + gimbalEvent.manipulation.strafe.direction = -forward; + gimbalEvent.manipulation.strafe.distance = dMoveValue; + } break; + + case traits_t::controller_t::MoveLeft: + { + gimbalEvent.type = traits_t::gimbal_t::Strafe; + gimbalEvent.manipulation.strafe.direction = -strafeLeftRight; + gimbalEvent.manipulation.strafe.distance = dMoveValue; + } break; + + case traits_t::controller_t::MoveRight: + { + gimbalEvent.type = traits_t::gimbal_t::Strafe; + gimbalEvent.manipulation.strafe.direction = strafeLeftRight; + gimbalEvent.manipulation.strafe.distance = dMoveValue; + } break; + + case traits_t::controller_t::TiltUp: + { + gimbalEvent.type = traits_t::gimbal_t::Rotate; + gimbalEvent.manipulation.rotation.pitch = dRotateValue; + gimbalEvent.manipulation.rotation.roll = 0.0f; + gimbalEvent.manipulation.rotation.yaw = 0.0f; + } break; + + case traits_t::controller_t::TiltDown: + { + gimbalEvent.type = traits_t::gimbal_t::Rotate; + gimbalEvent.manipulation.rotation.pitch = -dRotateValue; + gimbalEvent.manipulation.rotation.roll = 0.0f; + gimbalEvent.manipulation.rotation.yaw = 0.0f; + } break; + + case traits_t::controller_t::PanLeft: + { + gimbalEvent.type = traits_t::gimbal_t::Rotate; + gimbalEvent.manipulation.rotation.pitch = 0.0f; + gimbalEvent.manipulation.rotation.roll = 0.0f; + gimbalEvent.manipulation.rotation.yaw = -dRotateValue; + } break; + + case traits_t::controller_t::PanRight: + { + gimbalEvent.type = traits_t::gimbal_t::Rotate; + gimbalEvent.manipulation.rotation.pitch = 0.0f; + gimbalEvent.manipulation.rotation.roll = 0.0f; + gimbalEvent.manipulation.rotation.yaw = dRotateValue; + } break; + + default: + continue; + } + + gimbal->manipulate(gimbalEvent); + } } }; } -#endif // _CAMERA_IMPL_ \ No newline at end of file +#endif // _C_CAMERA_HPP_ \ No newline at end of file diff --git a/common/include/CGeomtryCreatorScene.hpp b/common/include/CGeomtryCreatorScene.hpp index 547c0aaf7..7b6492d11 100644 --- a/common/include/CGeomtryCreatorScene.hpp +++ b/common/include/CGeomtryCreatorScene.hpp @@ -1098,7 +1098,7 @@ class ResourceBuilder struct ObjectDrawHookCpu { - nbl::hlsl::float32_t4x4 model; + nbl::hlsl::float32_t3x4 model; nbl::asset::SBasicViewParameters viewParameters; ObjectMeta meta; }; diff --git a/common/include/ICamera.hpp b/common/include/ICamera.hpp new file mode 100644 index 000000000..22245c1e6 --- /dev/null +++ b/common/include/ICamera.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h + +#ifndef _I_CAMERA_HPP_ +#define _I_CAMERA_HPP_ + +#include +#include +#include +#include +#include + +#include "camera/ICameraControl.hpp" + +namespace nbl::hlsl // TODO: DIFFERENT NAMESPACE +{ + +template +class ICamera : public ICameraController +{ +public: + using base_t = typename ICameraController; + + struct Traits + { + using controller_t = base_t; + using projection_t = typename controller_t::projection_t; + using gimbal_t = typename controller_t::CGimbal; + using gimbal_virtual_event_t = typename gimbal_t::CVirtualEvent; + using controller_virtual_event_t = typename controller_t::CVirtualEvent; + }; + + ICamera() : base_t() {} + ~ICamera() = default; +}; + +} + +#endif // _I_CAMERA_HPP_ \ No newline at end of file diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index c52558438..bcc1b6d54 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -2,6 +2,7 @@ #define _NBL_I_CAMERA_CONTROLLER_HPP_ #include "IProjection.hpp" +#include "../ICamera.hpp" #include "CVirtualCameraEvent.hpp" #include "glm/glm/ext/matrix_transform.hpp" // TODO: TEMPORARY!!! whatever used will be moved to cpp #include "glm/glm/gtc/quaternion.hpp" @@ -133,7 +134,7 @@ class ICameraController : virtual public core::IReferenceCounted }; CGimbal(const core::smart_refctd_ptr&& projection, const float32_t3& position, const float32_t3& lookat, const float32_t3& upVec = float32_t3(0.0f, 1.0f, 0.0f), const float32_t3& backupUpVec = float32_t3(0.5f, 1.0f, 0.0f)) - : m_projection(projection), m_position(position), m_target(lookat), m_upVec(upVec), m_backupUpVec(backupUpVec), m_initialPosition(position), m_initialTarget(lookat), m_orientation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)), m_viewMatrix({}), m_isLeftHanded(checkIfLeftHanded(m_projection->getProjectionMatrix())) + : m_projection(projection), m_position(position), m_target(lookat), m_upVec(upVec), m_backupUpVec(backupUpVec), m_initialPosition(position), m_initialTarget(lookat), m_orientation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)), m_viewMatrix({}) { recomputeViewMatrix(); } @@ -205,8 +206,6 @@ class ICameraController : virtual public core::IReferenceCounted //! End the gimbal manipulation session, recompute view matrix if required and update handedness state from projection inline void end() { - m_isLeftHanded = checkIfLeftHanded(m_projection->getProjectionMatrix()); - if (m_needsToRecomputeViewMatrix) recomputeViewMatrix(); @@ -214,6 +213,7 @@ class ICameraController : virtual public core::IReferenceCounted m_recordingManipulation = false; } + inline bool isRecordingManipulation() { return m_recordingManipulation; } inline projection_t* getProjection() { return m_projection.get(); } inline const float32_t3& getPosition() const { return m_position; } inline const float32_t3& getTarget() const { return m_target; } @@ -221,7 +221,7 @@ class ICameraController : virtual public core::IReferenceCounted inline const float32_t3& getBackupUpVector() const { return m_backupUpVec; } inline const float32_t3 getLocalTarget() const { return m_target - m_position; } inline const float32_t3 getForwardDirection() const { return glm::normalize(getLocalTarget()); } - inline const float32_t4x4& getViewMatrix() const { return m_viewMatrix; } + inline const float32_t3x4& getViewMatrix() const { return m_viewMatrix; } inline bool isLeftHanded() { return m_isLeftHanded; } inline float32_t3 getPatchedUpVector() @@ -300,19 +300,12 @@ class ICameraController : virtual public core::IReferenceCounted { auto up = getPatchedUpVector(); - // TODO!!!! CASTS + m_isLeftHanded = m_projection->isLeftHanded(); - /* if (m_isLeftHanded) - m_viewMatrix = glm::lookAtLH(m_position, m_target, up); + m_viewMatrix = float32_t3x4(float32_t4x4(glm::lookAtLH(m_position, m_target, up))); else - m_viewMatrix = glm::lookAtRH(m_position, m_target, up); - */ - } - - inline bool checkIfLeftHanded(const auto& projectionMatrix) - { - return hlsl::determinant(projectionMatrix) < 0.f; + m_viewMatrix = float32_t3x4(float32_t4x4(glm::lookAtRH(m_position, m_target, up))); } core::smart_refctd_ptr m_projection; @@ -320,52 +313,42 @@ class ICameraController : virtual public core::IReferenceCounted const float32_t3 m_initialPosition, m_initialTarget; glm::quat m_orientation; - float32_t4x4 m_viewMatrix; + float32_t3x4 m_viewMatrix; - bool m_isLeftHanded, + bool m_isLeftHanded = false, m_needsToRecomputeViewMatrix = false, m_recordingManipulation = false; }; - struct SUpdateParameters - { - //! Nabla mouse events you want to be handled with a controller - std::span mouseEvents = {}; - - //! Nabla keyboard events you want to be handled with a controller - std::span keyboardEvents = {}; - }; - - ICameraController(core::smart_refctd_ptr&& gimbal) - : m_gimbal(core::smart_refctd_ptr(gimbal)) {} + ICameraController() {} - // controller can override which keys correspond to which event + // override controller keys map, it binds a key code to a virtual event void updateKeysToEvent(const std::vector& codes, VirtualEventType event) { m_keysToEvent[event] = std::move(codes); } + // start controller manipulation session virtual void begin(std::chrono::microseconds nextPresentationTimeStamp) { m_nextPresentationTimeStamp = nextPresentationTimeStamp; return; } - virtual void manipulate(SUpdateParameters parameters) = 0; + // manipulate camera with gimbal & virtual events, begin must be called before that! + virtual void manipulate(CGimbal* gimbal, std::span virtualEvents) = 0; + // finish controller manipulation session, call after last manipulate in the hot loop void end(std::chrono::microseconds nextPresentationTimeStamp) { m_lastVirtualUpTimeStamp = nextPresentationTimeStamp; } - inline void setMoveSpeed(const float moveSpeed) { m_moveSpeed = moveSpeed; } - inline void setRotateSpeed(const float rotateSpeed) { m_rotateSpeed = rotateSpeed; } - - inline const float getMoveSpeed() const { return m_moveSpeed; } - inline const float getRotateSpeed() const { return m_rotateSpeed; } - -protected: + /* // process keyboard to generate virtual manipulation events + // note that: + // - it doesn't make the manipulation itself! + */ std::vector processKeyboard(std::span events) { std::vector virtualEvents; @@ -405,12 +388,11 @@ class ICameraController : virtual public core::IReferenceCounted /* // [OPTIONAL]: process mouse to generate virtual manipulation events - // note: - // - all manipulations *may* be done with keyboard keys, it means you can have a pad/touch pad for which keys could be bound and skip the mouse - // - default implementation which is FPS camera-like controller doesn't perform roll rotation which is around Z axis! If you want more complex manipulations then override the method - // - it doesn't make the manipulation itself! It only process your mouse events you got from OS & accumulate data values to create manipulation virtual events! + // note that: + // - all manipulations *may* be done with keyboard keys (if you have a touchpad or sth an ui:: event could be a code!) + // - it doesn't make the manipulation itself! */ - virtual std::vector processMouse(std::span events) const + std::vector processMouse(std::span events) const { // accumulate total pitch & yaw delta from mouse movement events const auto [dTotalPitch, dTotalYaw] = [&]() @@ -436,6 +418,13 @@ class ICameraController : virtual public core::IReferenceCounted return { pitch, yaw }; } + inline void setMoveSpeed(const float moveSpeed) { m_moveSpeed = moveSpeed; } + inline void setRotateSpeed(const float rotateSpeed) { m_rotateSpeed = rotateSpeed; } + + inline const float getMoveSpeed() const { return m_moveSpeed; } + inline const float getRotateSpeed() const { return m_rotateSpeed; } + +protected: // controller can override default set of event map virtual void initKeysToEvent() { @@ -454,7 +443,6 @@ class ICameraController : virtual public core::IReferenceCounted m_keysToEvent[Reset] = ui::E_KEY_CODE::EKC_R ; } - core::smart_refctd_ptr m_gimbal; std::array m_keysToEvent = {}; float m_moveSpeed = 1.f, m_rotateSpeed = 1.f; bool m_keysDown[EventsCount] = {}; diff --git a/common/include/camera/IProjection.hpp b/common/include/camera/IProjection.hpp index f3edfccc4..2210da7e5 100644 --- a/common/include/camera/IProjection.hpp +++ b/common/include/camera/IProjection.hpp @@ -19,6 +19,11 @@ class IProjection : virtual public core::IReferenceCounted IProjection(const value_t& matrix = {}) : m_projectionMatrix(matrix) {} value_t& getProjectionMatrix() { return m_projectionMatrix; } + inline bool isLeftHanded() + { + return hlsl::determinant(m_projectionMatrix) < 0.f; + } + protected: value_t m_projectionMatrix; }; From 242a871561427d77e04267920c626002fe45a089 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Fri, 25 Oct 2024 15:18:47 +0200 Subject: [PATCH 13/83] improve IProjection, make the matrix private & allow to change it with a setter & get with a getter therefore determine at set time handness (compute determinant only once after the matrix gets changed!), update main.cpp & sources - time to test it --- 61_UI/main.cpp | 48 ++++++++++-------------- common/include/CCamera.hpp | 2 +- common/include/camera/ICameraControl.hpp | 12 +----- common/include/camera/IProjection.hpp | 19 +++++++--- 4 files changed, 36 insertions(+), 45 deletions(-) diff --git a/61_UI/main.cpp b/61_UI/main.cpp index c78059ae5..c561ab326 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -178,23 +178,23 @@ class UISampleApp final : public examples::SimpleWindowedApplication { ImGuiIO& io = ImGui::GetIO(); { - auto& projection = gimbal->getProjection()->getProjectionMatrix(); + auto* projection = gimbal->getProjection(); if (isPerspective) { if (isLH) - projection = projection_t::value_t(glm::perspectiveLH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); + projection->setMatrix(projection_t::value_t(glm::perspectiveLH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar))); else - projection = projection_t::value_t(glm::perspectiveRH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); + projection->setMatrix(projection_t::value_t(glm::perspectiveRH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar))); } else { float viewHeight = viewWidth * io.DisplaySize.y / io.DisplaySize.x; if (isLH) - projection = projection_t::value_t(glm::orthoLH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar)); + projection->setMatrix(projection_t::value_t(glm::orthoLH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar))); else - projection = projection_t::value_t(glm::orthoRH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar)); + projection->setMatrix(projection_t::value_t(glm::orthoRH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar))); } } @@ -331,24 +331,17 @@ class UISampleApp final : public examples::SimpleWindowedApplication * note it also modifies input view matrix but projection matrix is immutable */ - - - /* - - TODODOD - - - - static struct { float32_t4x4 view, projection, model; } imguizmoM16InOut; + const auto& projectionMatrix = gimbal->getProjection()->getMatrix(); + ImGuizmo::SetID(0u); imguizmoM16InOut.view = transpose(getMatrix3x4As4x4(gimbal->getViewMatrix())); - imguizmoM16InOut.projection = transpose(gimbal->getProjection()->getProjectionMatrix()); - imguizmoM16InOut.model = transpose(pass.scene->object.model); + imguizmoM16InOut.projection = transpose(projectionMatrix); + imguizmoM16InOut.model = transpose(getMatrix3x4As4x4(pass.scene->object.model)); { if (flipGizmoY) // note we allow to flip gizmo just to match our coordinates imguizmoM16InOut.projection[1][1] *= -1.f; // https://johannesugb.github.io/gpu-programming/why-do-opengl-proj-matrices-fail-in-vulkan/ @@ -359,17 +352,15 @@ class UISampleApp final : public examples::SimpleWindowedApplication // to Nabla + update camera & model matrices const auto& view = gimbal->getViewMatrix(); - const auto& projection = gimbal->getProjection()->getProjectionMatrix(); // TODO: make it more nicely const_cast(view) = float32_t3x4(transpose(imguizmoM16InOut.view)); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) - //camera.setProjectionMatrix(projection); // update concatanated matrix { static float32_t3x4 modelView, normal; static float32_t4x4 modelViewProjection; auto& hook = pass.scene->object; - hook.model = core::transpose(float32_t3x4(imguizmoM16InOut.model)); + hook.model = float32_t3x4(transpose(imguizmoM16InOut.model)); { const auto& references = pass.scene->getResources().objects; const auto type = static_cast(gcIndex); @@ -385,11 +376,13 @@ class UISampleApp final : public examples::SimpleWindowedApplication // TODO //modelView.getSub3x3InverseTranspose(normal); - modelViewProjection = nbl::core::concatenateBFollowedByA(camera.getConcatenatedMatrix(), hook.model); - memcpy(ubo.MVP, modelViewProjection.pointer(), sizeof(ubo.MVP)); - memcpy(ubo.MV, modelView.pointer(), sizeof(ubo.MV)); - memcpy(ubo.NormalMat, normal.pointer(), sizeof(ubo.NormalMat)); + auto concatMatrix = mul(projectionMatrix, getMatrix3x4As4x4(view)); + modelViewProjection = mul(concatMatrix, getMatrix3x4As4x4(hook.model)); + + memcpy(ubo.MVP, &modelViewProjection[0][0], sizeof(ubo.MVP)); + memcpy(ubo.MV, &modelView[0][0], sizeof(ubo.MV)); + memcpy(ubo.NormalMat, &normal[0][0], sizeof(ubo.NormalMat)); // object meta display { @@ -399,7 +392,6 @@ class UISampleApp final : public examples::SimpleWindowedApplication } } - // view matrices editor { ImGui::Begin("Matrices"); @@ -425,15 +417,13 @@ class UISampleApp final : public examples::SimpleWindowedApplication ImGui::Separator(); }; - addMatrixTable("Model Matrix", "ModelMatrixTable", 3, 4, pass.scene->object.model.pointer()); - addMatrixTable("Camera View Matrix", "ViewMatrixTable", 3, 4, view.pointer()); - addMatrixTable("Camera View Projection Matrix", "ViewProjectionMatrixTable", 4, 4, projection.pointer(), false); + addMatrixTable("Model Matrix", "ModelMatrixTable", 3, 4, &pass.scene->object.model[0][0]); + addMatrixTable("Camera Gimbal View Matrix", "ViewMatrixTable", 3, 4, &view[0][0]); + addMatrixTable("Camera Gimbal Projection Matrix", "ProjectionMatrixTable", 4, 4, &projectionMatrix[0][0], false); ImGui::End(); } - */ - // Nabla Imgui backend MDI buffer info // To be 100% accurate and not overly conservative we'd have to explicitly `cull_frees` and defragment each time, // so unless you do that, don't use this basic info to optimize the size of your IMGUI buffer. diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 1c306c651..7024e69a9 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -31,7 +31,7 @@ class Camera : public ICamera const auto forward = gimbal->getForwardDirection(); const auto up = gimbal->getPatchedUpVector(); - const bool leftHanded = gimbal->isLeftHanded(); + const bool leftHanded = gimbal->getProjection()->isLeftHanded(); // strafe vector we move along when requesting left/right movements const auto strafeLeftRight = leftHanded ? glm::normalize(glm::cross(forward, up)) : glm::normalize(glm::cross(up, forward)); diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index bcc1b6d54..c6cef13ad 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -222,7 +222,6 @@ class ICameraController : virtual public core::IReferenceCounted inline const float32_t3 getLocalTarget() const { return m_target - m_position; } inline const float32_t3 getForwardDirection() const { return glm::normalize(getLocalTarget()); } inline const float32_t3x4& getViewMatrix() const { return m_viewMatrix; } - inline bool isLeftHanded() { return m_isLeftHanded; } inline float32_t3 getPatchedUpVector() { @@ -241,9 +240,6 @@ class ICameraController : virtual public core::IReferenceCounted return up; } - // TODO: getConcatenatedMatrix() - // TODO: getViewMatrix() - private: //! Reset the gimbal to its initial position, target, and orientation inline void reset() @@ -292,7 +288,6 @@ class ICameraController : virtual public core::IReferenceCounted // And we can simply update target vector m_target = m_position + localTargetRotated; - // TODO: std::any + nice checks for deltas (radians - periodic!) m_needsToRecomputeViewMatrix = true; } @@ -300,9 +295,7 @@ class ICameraController : virtual public core::IReferenceCounted { auto up = getPatchedUpVector(); - m_isLeftHanded = m_projection->isLeftHanded(); - - if (m_isLeftHanded) + if (m_projection->isLeftHanded()) m_viewMatrix = float32_t3x4(float32_t4x4(glm::lookAtLH(m_position, m_target, up))); else m_viewMatrix = float32_t3x4(float32_t4x4(glm::lookAtRH(m_position, m_target, up))); @@ -315,8 +308,7 @@ class ICameraController : virtual public core::IReferenceCounted glm::quat m_orientation; float32_t3x4 m_viewMatrix; - bool m_isLeftHanded = false, - m_needsToRecomputeViewMatrix = false, + bool m_needsToRecomputeViewMatrix = true, m_recordingManipulation = false; }; diff --git a/common/include/camera/IProjection.hpp b/common/include/camera/IProjection.hpp index 2210da7e5..1384f8e87 100644 --- a/common/include/camera/IProjection.hpp +++ b/common/include/camera/IProjection.hpp @@ -16,16 +16,25 @@ class IProjection : virtual public core::IReferenceCounted public: using value_t = T; - IProjection(const value_t& matrix = {}) : m_projectionMatrix(matrix) {} - value_t& getProjectionMatrix() { return m_projectionMatrix; } + IProjection(const value_t& matrix = {}) : m_projectionMatrix(matrix) { updateHandnessState(); } - inline bool isLeftHanded() + inline void setMatrix(const value_t& projectionMatrix) { - return hlsl::determinant(m_projectionMatrix) < 0.f; + m_projectionMatrix = projectionMatrix; + updateHandnessState(); + } + + inline const value_t& getMatrix() { return m_projectionMatrix; } + inline bool isLeftHanded() { return m_isLeftHanded; } + +private: + inline void updateHandnessState() + { + m_isLeftHanded = hlsl::determinant(m_projectionMatrix) < 0.f; } -protected: value_t m_projectionMatrix; + bool m_isLeftHanded; }; template From 0415999a7035f56f3d9cca7255329916c697ab36 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Fri, 25 Oct 2024 16:21:40 +0200 Subject: [PATCH 14/83] address https://github.com/Devsh-Graphics-Programming/Nabla/pull/760/files#r1816728485 comment in https://github.com/Devsh-Graphics-Programming/Nabla/pull/760 PR --- 61_UI/main.cpp | 5 ++--- common/include/camera/ICameraControl.hpp | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/61_UI/main.cpp b/61_UI/main.cpp index c561ab326..321da0fce 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -7,7 +7,6 @@ #include "camera/CCubeProjection.hpp" #include "camera/ICameraControl.hpp" #include "glm/glm/ext/matrix_clip_space.hpp" // TODO: TESTING -#include "nbl/builtin/hlsl/matrix_utils/transformation_matrix_utils.hlsl" // FPS Camera, TESTS using projection_matrix_t = float32_t4x4; @@ -509,8 +508,8 @@ class UISampleApp final : public examples::SimpleWindowedApplication const float32_t3 position(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance), target(0.f, 0.f, 0.f), up(0.f, 1.f, 0.f); - auto pMatrix = glm::perspectiveLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar); - auto projection = make_smart_refctd_ptr(); // TODO: CASTS FOR PROJ + auto projection = make_smart_refctd_ptr(); + projection->setMatrix(projection_matrix_t(glm::perspectiveLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar))); gimbal = make_smart_refctd_ptr(smart_refctd_ptr(projection), position, target, up); camera = make_smart_refctd_ptr(); diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index c6cef13ad..96951dbb9 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -6,6 +6,7 @@ #include "CVirtualCameraEvent.hpp" #include "glm/glm/ext/matrix_transform.hpp" // TODO: TEMPORARY!!! whatever used will be moved to cpp #include "glm/glm/gtc/quaternion.hpp" +#include "nbl/builtin/hlsl/matrix_utils/transformation_matrix_utils.hlsl" // TODO: DIFFERENT NAMESPACE namespace nbl::hlsl @@ -296,9 +297,9 @@ class ICameraController : virtual public core::IReferenceCounted auto up = getPatchedUpVector(); if (m_projection->isLeftHanded()) - m_viewMatrix = float32_t3x4(float32_t4x4(glm::lookAtLH(m_position, m_target, up))); + m_viewMatrix = buildCameraLookAtMatrixLH(m_position, m_target, up); else - m_viewMatrix = float32_t3x4(float32_t4x4(glm::lookAtRH(m_position, m_target, up))); + m_viewMatrix = buildCameraLookAtMatrixRH(m_position, m_target, up); } core::smart_refctd_ptr m_projection; From 84f35e5d6259d0c814af72ccefcba0d00818668e Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Fri, 25 Oct 2024 16:55:34 +0200 Subject: [PATCH 15/83] init default keys to virtual events, make ICameraController inheritance virtual, init time stamps with defaults --- common/include/CCamera.hpp | 4 ++-- common/include/ICamera.hpp | 2 +- common/include/camera/ICameraControl.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 7024e69a9..11a532719 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -12,13 +12,13 @@ namespace nbl::hlsl // TODO: DIFFERENT NAMESPACE // FPS Camera template -class Camera : public ICamera +class Camera final : public ICamera { public: using base_t = ICamera; using traits_t = typename base_t::Traits; - Camera() : base_t() {} + Camera() : base_t() { traits_t::controller_t::initKeysToEvent(); } ~Camera() = default; virtual void manipulate(traits_t::gimbal_t* gimbal, std::span virtualEvents) override diff --git a/common/include/ICamera.hpp b/common/include/ICamera.hpp index 22245c1e6..da01f830b 100644 --- a/common/include/ICamera.hpp +++ b/common/include/ICamera.hpp @@ -17,7 +17,7 @@ namespace nbl::hlsl // TODO: DIFFERENT NAMESPACE { template -class ICamera : public ICameraController +class ICamera : public virtual ICameraController { public: using base_t = typename ICameraController; diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 96951dbb9..8896b5390 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -440,7 +440,7 @@ class ICameraController : virtual public core::IReferenceCounted float m_moveSpeed = 1.f, m_rotateSpeed = 1.f; bool m_keysDown[EventsCount] = {}; - std::chrono::microseconds m_nextPresentationTimeStamp, m_lastVirtualUpTimeStamp; + std::chrono::microseconds m_nextPresentationTimeStamp = {}, m_lastVirtualUpTimeStamp = {}; }; } // nbl::hlsl namespace From d8ff36a70a679e96718d098714db761e9b0a7a71 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Sat, 26 Oct 2024 17:41:40 +0200 Subject: [PATCH 16/83] split responsibilities & update sources --- 61_UI/main.cpp | 33 ++- common/include/CCamera.hpp | 130 +++++------- common/include/ICamera.hpp | 48 ++++- common/include/camera/ICameraControl.hpp | 245 ++++------------------- 4 files changed, 148 insertions(+), 308 deletions(-) diff --git a/61_UI/main.cpp b/61_UI/main.cpp index 321da0fce..388eab1e8 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -177,7 +177,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication { ImGuiIO& io = ImGui::GetIO(); { - auto* projection = gimbal->getProjection(); + auto* projection = camera->getProjection(); if (isPerspective) { @@ -256,15 +256,9 @@ class UISampleApp final : public examples::SimpleWindowedApplication { float32_t3 cameraPosition(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance); float32_t3 cameraTarget(0.f, 0.f, 0.f); - const static float32_t3 up(0.f, 1.f, 0.f); - gimbal->begin(); - { - gimbal->setPosition(cameraPosition); - gimbal->setTarget(cameraTarget); - gimbal->setBackupUpVector(up); - } - gimbal->end(); + gimbal->setPosition(cameraPosition); + camera->setTarget(cameraTarget); firstFrame = false; } @@ -335,10 +329,10 @@ class UISampleApp final : public examples::SimpleWindowedApplication float32_t4x4 view, projection, model; } imguizmoM16InOut; - const auto& projectionMatrix = gimbal->getProjection()->getMatrix(); + const auto& projectionMatrix = camera->getProjection()->getMatrix(); ImGuizmo::SetID(0u); - imguizmoM16InOut.view = transpose(getMatrix3x4As4x4(gimbal->getViewMatrix())); + imguizmoM16InOut.view = transpose(getMatrix3x4As4x4(camera->getViewMatrix())); imguizmoM16InOut.projection = transpose(projectionMatrix); imguizmoM16InOut.model = transpose(getMatrix3x4As4x4(pass.scene->object.model)); { @@ -350,7 +344,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication } // to Nabla + update camera & model matrices - const auto& view = gimbal->getViewMatrix(); + const auto& view = camera->getViewMatrix(); // TODO: make it more nicely const_cast(view) = float32_t3x4(transpose(imguizmoM16InOut.view)); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) @@ -449,6 +443,8 @@ class UISampleApp final : public examples::SimpleWindowedApplication ImGui::SetCursorPosX(windowPadding); + + if (freePercentage > 70.0f) ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.0f, 1.0f, 0.0f, 0.4f)); // Green else if (freePercentage > 30.0f) @@ -506,12 +502,13 @@ class UISampleApp final : public examples::SimpleWindowedApplication */ const float32_t3 position(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance), - target(0.f, 0.f, 0.f), up(0.f, 1.f, 0.f); + target(0.f, 0.f, 0.f); auto projection = make_smart_refctd_ptr(); projection->setMatrix(projection_matrix_t(glm::perspectiveLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar))); - gimbal = make_smart_refctd_ptr(smart_refctd_ptr(projection), position, target, up); - camera = make_smart_refctd_ptr(); + + gimbal = make_smart_refctd_ptr(position); + camera = make_smart_refctd_ptr(core::smart_refctd_ptr(gimbal), core::smart_refctd_ptr(projection), target); return true; } @@ -762,10 +759,8 @@ class UISampleApp final : public examples::SimpleWindowedApplication const auto virtualMouseEvents = camera->processMouse(params.mouseEvents); const auto virtualKeyboardEvents = camera->processMouse(params.mouseEvents); - gimbal->begin(); - camera->manipulate(gimbal.get(), { virtualMouseEvents.data(), virtualMouseEvents.size()}); - camera->manipulate(gimbal.get(), { virtualKeyboardEvents.data(), virtualKeyboardEvents.size()}); - gimbal->end(); + camera->manipulate({ virtualMouseEvents.data(), virtualMouseEvents.size()}); + camera->manipulate({ virtualKeyboardEvents.data(), virtualKeyboardEvents.size()}); camera->end(nextPresentationTimestamp); } diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 11a532719..bf33373a1 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -18,23 +18,20 @@ class Camera final : public ICamera using base_t = ICamera; using traits_t = typename base_t::Traits; - Camera() : base_t() { traits_t::controller_t::initKeysToEvent(); } + Camera(core::smart_refctd_ptr&& gimbal, core::smart_refctd_ptr projection, const float32_t3& target = { 0,0,0 }) + : base_t(core::smart_refctd_ptr(gimbal), core::smart_refctd_ptr(projection), target) { traits_t::controller_t::initKeysToEvent(); } ~Camera() = default; - virtual void manipulate(traits_t::gimbal_t* gimbal, std::span virtualEvents) override + virtual void manipulate(std::span virtualEvents) override { - if (!gimbal) - return; // TODO: LOG + auto* gimbal = traits_t::controller_t::m_gimbal.get(); + auto* projection = base_t::getProjection(); - if (!gimbal->isRecordingManipulation()) - return; // TODO: LOG + assert(gimbal); // TODO + assert(projection); // TODO - const auto forward = gimbal->getForwardDirection(); - const auto up = gimbal->getPatchedUpVector(); - const bool leftHanded = gimbal->getProjection()->isLeftHanded(); - - // strafe vector we move along when requesting left/right movements - const auto strafeLeftRight = leftHanded ? glm::normalize(glm::cross(forward, up)) : glm::normalize(glm::cross(up, forward)); + const auto [forward, up, right] = std::make_tuple(gimbal->getZAxis(), gimbal->getYAxis(), gimbal->getXAxis()); + const bool isLeftHanded = projection->isLeftHanded(); // TODO? constexpr auto MoveSpeedScale = 0.003f; constexpr auto RotateSpeedScale = 0.003f; @@ -43,81 +40,58 @@ class Camera final : public ICamera const auto dRotateFactor = traits_t::controller_t::m_rotateSpeed * RotateSpeedScale; // TODO: UB/LB for pitch [-88,88]!!! we are not in cosmos but handle FPS camera in default case + // TODO: accumulate move scalars & rotate scalars then do single move & rotate for (const traits_t::controller_virtual_event_t& ev : virtualEvents) { const auto dMoveValue = ev.value * dMoveFactor; const auto dRotateValue = ev.value * dRotateFactor; - typename traits_t::gimbal_virtual_event_t gimbalEvent; - switch (ev.type) { - case traits_t::controller_t::MoveForward: - { - gimbalEvent.type = traits_t::gimbal_t::Strafe; - gimbalEvent.manipulation.strafe.direction = forward; - gimbalEvent.manipulation.strafe.distance = dMoveValue; - } break; - - case traits_t::controller_t::MoveBackward: - { - gimbalEvent.type = traits_t::gimbal_t::Strafe; - gimbalEvent.manipulation.strafe.direction = -forward; - gimbalEvent.manipulation.strafe.distance = dMoveValue; - } break; - - case traits_t::controller_t::MoveLeft: - { - gimbalEvent.type = traits_t::gimbal_t::Strafe; - gimbalEvent.manipulation.strafe.direction = -strafeLeftRight; - gimbalEvent.manipulation.strafe.distance = dMoveValue; - } break; - - case traits_t::controller_t::MoveRight: - { - gimbalEvent.type = traits_t::gimbal_t::Strafe; - gimbalEvent.manipulation.strafe.direction = strafeLeftRight; - gimbalEvent.manipulation.strafe.distance = dMoveValue; - } break; - - case traits_t::controller_t::TiltUp: - { - gimbalEvent.type = traits_t::gimbal_t::Rotate; - gimbalEvent.manipulation.rotation.pitch = dRotateValue; - gimbalEvent.manipulation.rotation.roll = 0.0f; - gimbalEvent.manipulation.rotation.yaw = 0.0f; - } break; - - case traits_t::controller_t::TiltDown: - { - gimbalEvent.type = traits_t::gimbal_t::Rotate; - gimbalEvent.manipulation.rotation.pitch = -dRotateValue; - gimbalEvent.manipulation.rotation.roll = 0.0f; - gimbalEvent.manipulation.rotation.yaw = 0.0f; - } break; - - case traits_t::controller_t::PanLeft: - { - gimbalEvent.type = traits_t::gimbal_t::Rotate; - gimbalEvent.manipulation.rotation.pitch = 0.0f; - gimbalEvent.manipulation.rotation.roll = 0.0f; - gimbalEvent.manipulation.rotation.yaw = -dRotateValue; - } break; - - case traits_t::controller_t::PanRight: - { - gimbalEvent.type = traits_t::gimbal_t::Rotate; - gimbalEvent.manipulation.rotation.pitch = 0.0f; - gimbalEvent.manipulation.rotation.roll = 0.0f; - gimbalEvent.manipulation.rotation.yaw = dRotateValue; - } break; - - default: - continue; + case traits_t::controller_t::MoveForward: + { + gimbal->advance(dMoveValue); + } break; + + case traits_t::controller_t::MoveBackward: + { + gimbal->advance(-dMoveValue); + } break; + + case traits_t::controller_t::MoveLeft: + { + gimbal->strafe(dMoveValue); + } break; + + case traits_t::controller_t::MoveRight: + { + gimbal->strafe(-dMoveValue); + } break; + + case traits_t::controller_t::TiltUp: + { + gimbal->rotate(right, dRotateValue); + } break; + + case traits_t::controller_t::TiltDown: + { + gimbal->rotate(right, -dRotateValue); + } break; + + case traits_t::controller_t::PanLeft: + { + gimbal->rotate(up, dRotateValue); + } break; + + case traits_t::controller_t::PanRight: + { + gimbal->rotate(up, -dRotateValue); + } break; + + default: + continue; } - - gimbal->manipulate(gimbalEvent); } } }; diff --git a/common/include/ICamera.hpp b/common/include/ICamera.hpp index da01f830b..e436bd8d7 100644 --- a/common/include/ICamera.hpp +++ b/common/include/ICamera.hpp @@ -17,7 +17,7 @@ namespace nbl::hlsl // TODO: DIFFERENT NAMESPACE { template -class ICamera : public virtual ICameraController +class ICamera : public ICameraController { public: using base_t = typename ICameraController; @@ -27,12 +27,54 @@ class ICamera : public virtual ICameraController using controller_t = base_t; using projection_t = typename controller_t::projection_t; using gimbal_t = typename controller_t::CGimbal; - using gimbal_virtual_event_t = typename gimbal_t::CVirtualEvent; using controller_virtual_event_t = typename controller_t::CVirtualEvent; }; - ICamera() : base_t() {} + ICamera(core::smart_refctd_ptr&& gimbal, core::smart_refctd_ptr projection, const float32_t3& target = {0,0,0}) + : base_t(core::smart_refctd_ptr(gimbal)), m_projection(core::smart_refctd_ptr(projection)) { setTarget(target); } ~ICamera() = default; + + inline void setPosition(const float32_t3& position) + { + const auto* gimbal = base_t::m_gimbal.get(); + gimbal->setPosition(position); + recomputeViewMatrix(); + } + + inline void setTarget(const float32_t3& position) + { + m_target = position; + + const auto* gimbal = base_t::m_gimbal.get(); + auto localTarget = m_target - gimbal->getPosition(); + + // TODO: use gimbal to perform a rotation! + + recomputeViewMatrix(); + } + + inline const float32_t3& getPosition() { return base_t::m_gimbal->getPosition(); } + inline const float32_t3& getTarget() { return m_target; } + inline const float32_t3x4& getViewMatrix() const { return m_viewMatrix; } + inline Traits::projection_t* getProjection() { return m_projection.get(); } + +private: + inline void recomputeViewMatrix() + { + // TODO: adjust for handedness (axes flip) + const bool isLeftHanded = m_projection->isLeftHanded(); + const auto* gimbal = base_t::m_gimbal.get(); + const auto& position = gimbal->getPosition(); + + const auto [xaxis, yaxis, zaxis] = std::make_tuple(gimbal->getXAxis(), gimbal->getYAxis(), gimbal->getZAxis()); + m_viewMatrix[0u] = float32_t4(xaxis, -hlsl::dot(xaxis, position)); + m_viewMatrix[1u] = float32_t4(yaxis, -hlsl::dot(yaxis, position)); + m_viewMatrix[2u] = float32_t4(zaxis, -hlsl::dot(zaxis, position)); + } + + const core::smart_refctd_ptr m_projection; + float32_t3x4 m_viewMatrix; + float32_t3 m_target; }; } diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 8896b5390..96e738b65 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -74,246 +74,74 @@ class ICameraController : virtual public core::IReferenceCounted class CGimbal : virtual public core::IReferenceCounted { public: - //! Virtual event representing a combined gimbal manipulation - enum VirtualEventType - { - //! Move the camera in the direction of strafe vector - Strafe, - - //! Update orientation of camera by rotating around X, Y, Z axes - Rotate, - - //! Signals boolean state, for example "reset" - State - }; - - class CVirtualEvent - { - public: - using manipulation_encode_t = float32_t4; - - struct StrafeManipulation - { - float32_t3 direction = {}; - float distance = {}; - }; - - struct RotateManipulation - { - float pitch = {}, roll = {}, yaw = {}; - }; - - struct StateManipulation - { - uint32_t reset : 1; - uint32_t reserved : 31; - - StateManipulation() { memset(this, 0, sizeof(StateManipulation)); } - ~StateManipulation() {} - }; - - union ManipulationValue - { - StrafeManipulation strafe; - RotateManipulation rotation; - StateManipulation state; - - ManipulationValue() { memset(this, 0, sizeof(ManipulationValue)); } - ~ManipulationValue() {} - }; - - CVirtualEvent() {} - - CVirtualEvent(VirtualEventType _type, const ManipulationValue _manipulation) - : type(_type), manipulation(_manipulation) - { - static_assert(sizeof(manipulation_encode_t) == sizeof(ManipulationValue)); - } - - VirtualEventType type; - ManipulationValue manipulation; - }; + CGimbal(const float32_t3& position, glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f)) + : m_position(position), m_orientation(orientation) {} - CGimbal(const core::smart_refctd_ptr&& projection, const float32_t3& position, const float32_t3& lookat, const float32_t3& upVec = float32_t3(0.0f, 1.0f, 0.0f), const float32_t3& backupUpVec = float32_t3(0.5f, 1.0f, 0.0f)) - : m_projection(projection), m_position(position), m_target(lookat), m_upVec(upVec), m_backupUpVec(backupUpVec), m_initialPosition(position), m_initialTarget(lookat), m_orientation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f)), m_viewMatrix({}) - { - recomputeViewMatrix(); - } - - // TODO: ctor with core::path to json config file to load defaults - - //! Start a gimbal manipulation session - inline void begin() - { - m_needsToRecomputeViewMatrix = false; - m_recordingManipulation = true; - } - - //! Record manipulation of the gimbal, note those events are delta manipulations - void manipulate(const CVirtualEvent& virtualEvent) - { - if (!m_recordingManipulation) - return; // TODO: log it - - const auto& manipulation = virtualEvent.manipulation; - - switch (virtualEvent.type) - { - case VirtualEventType::Strafe: - { - strafe(manipulation.strafe.direction, manipulation.strafe.distance); - } break; - - case VirtualEventType::Rotate: - { - rotate(manipulation.rotation.pitch, manipulation.rotation.yaw, manipulation.rotation.roll); - } break; - - case VirtualEventType::State: - { - if (manipulation.state.reset) - reset(); - } break; - - default: - break; - } - } - - // Record change of position vector, global update inline void setPosition(const float32_t3& position) { - if (!m_recordingManipulation) - return; // TODO: log it - m_position = position; } - // Record change of target vector, global update - inline void setTarget(const float32_t3& target) + inline void rotate(const float32_t3& axis, float dRadians) { - if (!m_recordingManipulation) - return; // TODO: log it - - m_target = target; + glm::quat dRotation = glm::angleAxis(dRadians, axis); + m_orientation = glm::normalize(dRotation * m_orientation); + m_orthonormal = float32_t3x3(glm::mat3_cast(m_orientation)); } - // Change up vector, global update - inline void setUpVector(const float32_t3& up) { m_upVec = up; } - - // Change backupUp vector, global update - inline void setBackupUpVector(const float32_t3& backupUp) { m_backupUpVec = backupUp; } - - //! End the gimbal manipulation session, recompute view matrix if required and update handedness state from projection - inline void end() + inline void strafe(float distance) { - if (m_needsToRecomputeViewMatrix) - recomputeViewMatrix(); - - m_needsToRecomputeViewMatrix = false; - m_recordingManipulation = false; + move({ 0.f, distance, 0.f }); } - inline bool isRecordingManipulation() { return m_recordingManipulation; } - inline projection_t* getProjection() { return m_projection.get(); } - inline const float32_t3& getPosition() const { return m_position; } - inline const float32_t3& getTarget() const { return m_target; } - inline const float32_t3& getUpVector() const { return m_upVec; } - inline const float32_t3& getBackupUpVector() const { return m_backupUpVec; } - inline const float32_t3 getLocalTarget() const { return m_target - m_position; } - inline const float32_t3 getForwardDirection() const { return glm::normalize(getLocalTarget()); } - inline const float32_t3x4& getViewMatrix() const { return m_viewMatrix; } - - inline float32_t3 getPatchedUpVector() + inline void climb(float distance) { - // if up vector and vector to the target are the same we patch the up vector - auto up = glm::normalize(m_upVec); - - const auto localTarget = getForwardDirection(); - const auto cross = glm::cross(localTarget, up); - - // we compute squared length but for checking if the len is 0 it doesnt matter - const bool upVectorZeroLength = glm::dot(cross, cross) == 0.f; - - if (upVectorZeroLength) - up = glm::normalize(m_backupUpVec); - - return up; + move({ 0.f, 0.f, distance }); } - private: - //! Reset the gimbal to its initial position, target, and orientation - inline void reset() + inline void advance(float distance) { - m_position = m_initialPosition; - m_target = m_initialTarget; - m_orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); - - recomputeViewMatrix(); // Recompute the view matrix after resetting + move({ distance, 0.f, 0.f }); } - //! Move in the direction of strafe (mostly left/right, up/down) - inline void strafe(const glm::vec3& direction, float distance) + inline void move(float32_t3 delta) { - if (distance != 0.0f) - { - const auto strafeVector = glm::normalize(direction) * distance; - m_position += strafeVector; - m_target += strafeVector; - - m_needsToRecomputeViewMatrix = true; - } + m_position += mul(m_orthonormal, delta); } - //! Update orientation by rotating around all XYZ axes - delta rotations in radians - inline void rotate(float dPitchRadians, float dYawDeltaRadians, float dRollDeltaRadians) + inline void reset() { - // Rotate around X (pitch) - glm::quat qPitch = glm::angleAxis(dPitchRadians, glm::vec3(1.0f, 0.0f, 0.0f)); - - // Rotate around Y (yaw) - glm::quat qYaw = glm::angleAxis(dYawDeltaRadians, glm::vec3(0.0f, 1.0f, 0.0f)); - - // Rotate around Z (roll) - glm::quat qRoll = glm::angleAxis(dRollDeltaRadians, glm::vec3(0.0f, 0.0f, 1.0f)); - - // Combine the new rotations with the current orientation - m_orientation = glm::normalize(qYaw * qPitch * qRoll * m_orientation); - - // Now we have rotation transformation as 3x3 matrix - auto rotate = glm::mat3_cast(m_orientation); + // TODO + } - // We do not change magnitude of the vector - auto localTargetRotated = rotate * getLocalTarget(); + // Position of gimbal + inline const float32_t3& getPosition() const { return m_position; } - // And we can simply update target vector - m_target = m_position + localTargetRotated; + // Orientation of gimbal + inline const glm::quat& getOrientation() const { return m_orientation; } - m_needsToRecomputeViewMatrix = true; - } + // Orthonormal [getXAxis(), getYAxis(), getZAxis()] matrix + inline const float32_t3x3& getOrthonornalMatrix() const { return m_orthonormal; } - inline void recomputeViewMatrix() - { - auto up = getPatchedUpVector(); + // Base right vector in orthonormal basis, base "right" vector (X-axis) + inline const float32_t3& getXAxis() const { return m_orthonormal[0u]; } - if (m_projection->isLeftHanded()) - m_viewMatrix = buildCameraLookAtMatrixLH(m_position, m_target, up); - else - m_viewMatrix = buildCameraLookAtMatrixRH(m_position, m_target, up); - } + // Base up vector in orthonormal basis, base "up" vector (Y-axis) + inline const float32_t3& getYAxis() const { return m_orthonormal[1u]; } - core::smart_refctd_ptr m_projection; - float32_t3 m_position, m_target, m_upVec, m_backupUpVec; - const float32_t3 m_initialPosition, m_initialTarget; + // Base forward vector in orthonormal basis, base "forward" vector (Z-axis) + inline const float32_t3& getZAxis() const { return m_orthonormal[2u]; } + private: + float32_t3 m_position; glm::quat m_orientation; - float32_t3x4 m_viewMatrix; - bool m_needsToRecomputeViewMatrix = true, - m_recordingManipulation = false; + // Represents the camera's orthonormal basis + // https://en.wikipedia.org/wiki/Orthonormal_basis + float32_t3x3 m_orthonormal; }; - ICameraController() {} + ICameraController(core::smart_refctd_ptr&& gimbal) : m_gimbal(core::smart_refctd_ptr(gimbal)) {} // override controller keys map, it binds a key code to a virtual event void updateKeysToEvent(const std::vector& codes, VirtualEventType event) @@ -329,7 +157,7 @@ class ICameraController : virtual public core::IReferenceCounted } // manipulate camera with gimbal & virtual events, begin must be called before that! - virtual void manipulate(CGimbal* gimbal, std::span virtualEvents) = 0; + virtual void manipulate(std::span virtualEvents) = 0; // finish controller manipulation session, call after last manipulate in the hot loop void end(std::chrono::microseconds nextPresentationTimeStamp) @@ -436,6 +264,7 @@ class ICameraController : virtual public core::IReferenceCounted m_keysToEvent[Reset] = ui::E_KEY_CODE::EKC_R ; } + core::smart_refctd_ptr m_gimbal; std::array m_keysToEvent = {}; float m_moveSpeed = 1.f, m_rotateSpeed = 1.f; bool m_keysDown[EventsCount] = {}; From e0c66bd8ef9a5d91feb7100f37663eee38eefdff Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Sat, 26 Oct 2024 17:50:08 +0200 Subject: [PATCH 17/83] add updateOrthonormalMatrix --- common/include/camera/ICameraControl.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 96e738b65..e650324f5 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -75,7 +75,7 @@ class ICameraController : virtual public core::IReferenceCounted { public: CGimbal(const float32_t3& position, glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f)) - : m_position(position), m_orientation(orientation) {} + : m_position(position), m_orientation(orientation) { updateOrthonormalMatrix(); } inline void setPosition(const float32_t3& position) { @@ -86,7 +86,7 @@ class ICameraController : virtual public core::IReferenceCounted { glm::quat dRotation = glm::angleAxis(dRadians, axis); m_orientation = glm::normalize(dRotation * m_orientation); - m_orthonormal = float32_t3x3(glm::mat3_cast(m_orientation)); + updateOrthonormalMatrix(); } inline void strafe(float distance) @@ -133,6 +133,8 @@ class ICameraController : virtual public core::IReferenceCounted inline const float32_t3& getZAxis() const { return m_orthonormal[2u]; } private: + inline void updateOrthonormalMatrix() { m_orthonormal = float32_t3x3(glm::mat3_cast(glm::normalize(m_orientation))); } + float32_t3 m_position; glm::quat m_orientation; From d1c0e9f7e6bb05dbacd2318da86909d3a93e08f3 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Sat, 26 Oct 2024 09:10:55 -0700 Subject: [PATCH 18/83] Saving work --- 09_GeometryCreator/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/09_GeometryCreator/main.cpp b/09_GeometryCreator/main.cpp index edbec9e4b..90ca78bbf 100644 --- a/09_GeometryCreator/main.cpp +++ b/09_GeometryCreator/main.cpp @@ -312,13 +312,13 @@ class GeometryCreatorApp final : public examples::SimpleWindowedApplication hlsl::float32_t3x4 modelViewMatrix = hlsl::concatenateBFollowedByA(viewMatrix, modelMatrix); hlsl::float32_t4x4 modelViewProjectionMatrix = mul(viewProjectionMatrix, hlsl::getMatrix3x4As4x4(modelMatrix)); - core::matrix3x4SIMD normalMatrix; + hlsl::float32_t3x4 normalMatrix; //modelViewMatrix.getSub3x3InverseTranspose(normalMatrix); SBasicViewParameters uboData; memcpy(uboData.MVP, &modelViewProjectionMatrix, sizeof(uboData.MVP)); memcpy(uboData.MV, &modelViewMatrix, sizeof(uboData.MV)); - memcpy(uboData.NormalMat, normalMatrix.pointer(), sizeof(uboData.NormalMat)); + memcpy(uboData.NormalMat, &normalMatrix, sizeof(uboData.NormalMat)); { SBufferRange range; range.buffer = core::smart_refctd_ptr(resources.ubo.buffer); From 0574d725b2d0ae02a0d0e409e642a14981bc1e97 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Sat, 26 Oct 2024 18:14:49 +0200 Subject: [PATCH 19/83] start eliminating first runtime bugs & typos --- 61_UI/main.cpp | 2 +- common/include/CCamera.hpp | 2 +- common/include/camera/ICameraControl.hpp | 42 +++++++++++++----------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/61_UI/main.cpp b/61_UI/main.cpp index 388eab1e8..aca5ec34d 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -757,7 +757,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication if (move) { const auto virtualMouseEvents = camera->processMouse(params.mouseEvents); - const auto virtualKeyboardEvents = camera->processMouse(params.mouseEvents); + const auto virtualKeyboardEvents = camera->processKeyboard(params.keyboardEvents); camera->manipulate({ virtualMouseEvents.data(), virtualMouseEvents.size()}); camera->manipulate({ virtualKeyboardEvents.data(), virtualKeyboardEvents.size()}); diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index bf33373a1..2b610082c 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -40,7 +40,7 @@ class Camera final : public ICamera const auto dRotateFactor = traits_t::controller_t::m_rotateSpeed * RotateSpeedScale; // TODO: UB/LB for pitch [-88,88]!!! we are not in cosmos but handle FPS camera in default case - // TODO: accumulate move scalars & rotate scalars then do single move & rotate + // TODO: accumulate move & rotate scalars then do single move & rotate gimbal manipulation for (const traits_t::controller_virtual_event_t& ev : virtualEvents) { diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index e650324f5..67781b250 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -174,7 +174,7 @@ class ICameraController : virtual public core::IReferenceCounted */ std::vector processKeyboard(std::span events) { - std::vector virtualEvents; + std::vector output; for (const auto& ev : events) { @@ -196,7 +196,7 @@ class ICameraController : virtual public core::IReferenceCounted if (ev.action == nbl::ui::SKeyboardEvent::ECA_PRESSED && !m_keysDown[virtualKey]) { m_keysDown[virtualKey] = true; - virtualEvents.emplace_back(CVirtualEvent{ virtualKey, static_cast(dt) }); + output.emplace_back(CVirtualEvent{ virtualKey, static_cast(dt) }); } else if (ev.action == nbl::ui::SKeyboardEvent::ECA_RELEASED) { @@ -206,7 +206,7 @@ class ICameraController : virtual public core::IReferenceCounted } } - return virtualEvents; + return output; } /* @@ -217,28 +217,30 @@ class ICameraController : virtual public core::IReferenceCounted */ std::vector processMouse(std::span events) const { - // accumulate total pitch & yaw delta from mouse movement events - const auto [dTotalPitch, dTotalYaw] = [&]() - { - double dPitch = {}, dYaw = {}; + double dPitch = {}, dYaw = {}; - for (const auto& ev : events) - if (ev.type == nbl::ui::SMouseEvent::EET_MOVEMENT) - { - dYaw += ev.movementEvent.relativeMovementX; // (yaw) - dPitch -= ev.movementEvent.relativeMovementY; // (pitch) - } + for (const auto& ev : events) + if (ev.type == nbl::ui::SMouseEvent::EET_MOVEMENT) + { + dYaw += ev.movementEvent.relativeMovementX; + dPitch += ev.movementEvent.relativeMovementY; + } - return std::make_tuple(dPitch, dYaw); - }(); + std::vector output; - CVirtualEvent pitch; - pitch.type = (pitch.value = dTotalPitch) > 0.f ? TiltUp : TiltDown; + if (dPitch) + { + auto& pitch = output.emplace_back(); + pitch.type = (pitch.value = dPitch) > 0.f ? TiltUp : TiltDown; + } - CVirtualEvent yaw; - yaw.type = (yaw.value = dTotalYaw) > 0.f ? PanRight : PanLeft; + if (dYaw) + { + auto& yaw = output.emplace_back(); + yaw.type = (yaw.value = dYaw) > 0.f ? PanRight : PanLeft; + } - return { pitch, yaw }; + return output; } inline void setMoveSpeed(const float moveSpeed) { m_moveSpeed = moveSpeed; } From 221e1121e1581ab44d880bd26fd92797d573a243 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Mon, 28 Oct 2024 12:29:23 +0100 Subject: [PATCH 20/83] add debug asserts for matrix base checks --- common/include/camera/ICameraControl.hpp | 26 +++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 67781b250..00fe649a2 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -133,7 +133,31 @@ class ICameraController : virtual public core::IReferenceCounted inline const float32_t3& getZAxis() const { return m_orthonormal[2u]; } private: - inline void updateOrthonormalMatrix() { m_orthonormal = float32_t3x3(glm::mat3_cast(glm::normalize(m_orientation))); } + inline void updateOrthonormalMatrix() + { + m_orthonormal = float32_t3x3(glm::mat3_cast(glm::normalize(m_orientation))); + + // DEBUG + const auto [xaxis, yaxis, zaxis] = std::make_tuple(getXAxis(),getYAxis(), getZAxis()); + + auto isNormalized = [](const auto& v, float epsilon) -> bool + { + return glm::epsilonEqual(glm::length(v), 1.0f, epsilon); + }; + + auto isOrthogonal = [](const auto& a, const auto& b, float epsilon) -> bool + { + return glm::epsilonEqual(glm::dot(a, b), 0.0f, epsilon); + }; + + auto isOrthoBase = [&](const auto& x, const auto& y, const auto& z, float epsilon = 1e-6f) -> bool + { + return isNormalized(x, epsilon) && isNormalized(y, epsilon) && isNormalized(z, epsilon) && + isOrthogonal(x, y, epsilon) && isOrthogonal(x, z, epsilon) && isOrthogonal(y, z, epsilon); + }; + + assert(isOrthoBase(xaxis, yaxis, zaxis)); + } float32_t3 m_position; glm::quat m_orientation; From 13613c359318468819252dba1068c86e6dd9e54d Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Mon, 28 Oct 2024 15:45:43 +0100 Subject: [PATCH 21/83] fix another bugs, make the rotation work! --- 61_UI/main.cpp | 21 ++++++++++++++------- common/include/CCamera.hpp | 12 +++++++++--- common/include/ICamera.hpp | 2 +- common/include/camera/ICameraControl.hpp | 6 ++++-- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/61_UI/main.cpp b/61_UI/main.cpp index aca5ec34d..9e65776a7 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -182,18 +182,18 @@ class UISampleApp final : public examples::SimpleWindowedApplication if (isPerspective) { if (isLH) - projection->setMatrix(projection_t::value_t(glm::perspectiveLH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar))); + projection->setMatrix(buildProjectionMatrixPerspectiveFovLH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); else - projection->setMatrix(projection_t::value_t(glm::perspectiveRH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar))); + projection->setMatrix(buildProjectionMatrixPerspectiveFovRH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); } else { float viewHeight = viewWidth * io.DisplaySize.y / io.DisplaySize.x; if (isLH) - projection->setMatrix(projection_t::value_t(glm::orthoLH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar))); + projection->setMatrix(buildProjectionMatrixOrthoLH(viewWidth, viewHeight, zNear, zFar)); else - projection->setMatrix(projection_t::value_t(glm::orthoRH(-viewWidth / 2.0f, viewWidth / 2.0f, -viewHeight / 2.0f, viewHeight / 2.0f, zNear, zFar))); + projection->setMatrix(buildProjectionMatrixOrthoRH(viewWidth, viewHeight, zNear, zFar)); } } @@ -410,7 +410,16 @@ class UISampleApp final : public examples::SimpleWindowedApplication ImGui::Separator(); }; + auto& orientation = gimbal->getOrthonornalMatrix(); + addMatrixTable("Model Matrix", "ModelMatrixTable", 3, 4, &pass.scene->object.model[0][0]); + + addMatrixTable("Right", "OrientationRightVec", 1, 3, &gimbal->getXAxis()[0]); + addMatrixTable("Up", "OrientationUpVec", 1, 3, &gimbal->getYAxis()[0]); + addMatrixTable("Forward", "OrientationForwardVec", 1, 3, &gimbal->getZAxis()[0]); + addMatrixTable("Position", "PositionForwardVec", 1, 3, &gimbal->getPosition()[0]); + + //addMatrixTable("Camera Gimbal Orientation Matrix", "OrientationMatrixTable", 3, 3, &orientation[0][0]); addMatrixTable("Camera Gimbal View Matrix", "ViewMatrixTable", 3, 4, &view[0][0]); addMatrixTable("Camera Gimbal Projection Matrix", "ProjectionMatrixTable", 4, 4, &projectionMatrix[0][0], false); @@ -443,8 +452,6 @@ class UISampleApp final : public examples::SimpleWindowedApplication ImGui::SetCursorPosX(windowPadding); - - if (freePercentage > 70.0f) ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.0f, 1.0f, 0.0f, 0.4f)); // Green else if (freePercentage > 30.0f) @@ -505,7 +512,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication target(0.f, 0.f, 0.f); auto projection = make_smart_refctd_ptr(); - projection->setMatrix(projection_matrix_t(glm::perspectiveLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar))); + projection->setMatrix(buildProjectionMatrixPerspectiveFovLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar)); gimbal = make_smart_refctd_ptr(position); camera = make_smart_refctd_ptr(core::smart_refctd_ptr(gimbal), core::smart_refctd_ptr(projection), target); diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 2b610082c..2f9751969 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -19,7 +19,11 @@ class Camera final : public ICamera using traits_t = typename base_t::Traits; Camera(core::smart_refctd_ptr&& gimbal, core::smart_refctd_ptr projection, const float32_t3& target = { 0,0,0 }) - : base_t(core::smart_refctd_ptr(gimbal), core::smart_refctd_ptr(projection), target) { traits_t::controller_t::initKeysToEvent(); } + : base_t(core::smart_refctd_ptr(gimbal), core::smart_refctd_ptr(projection), target) + { + traits_t::controller_t::initKeysToEvent(); + base_t::recomputeViewMatrix(); + } ~Camera() = default; virtual void manipulate(std::span virtualEvents) override @@ -79,12 +83,12 @@ class Camera final : public ICamera gimbal->rotate(right, -dRotateValue); } break; - case traits_t::controller_t::PanLeft: + case traits_t::controller_t::PanRight: { gimbal->rotate(up, dRotateValue); } break; - case traits_t::controller_t::PanRight: + case traits_t::controller_t::PanLeft: { gimbal->rotate(up, -dRotateValue); } break; @@ -93,6 +97,8 @@ class Camera final : public ICamera continue; } } + + base_t::recomputeViewMatrix(); } }; diff --git a/common/include/ICamera.hpp b/common/include/ICamera.hpp index e436bd8d7..2f17fe79d 100644 --- a/common/include/ICamera.hpp +++ b/common/include/ICamera.hpp @@ -58,7 +58,7 @@ class ICamera : public ICameraController inline const float32_t3x4& getViewMatrix() const { return m_viewMatrix; } inline Traits::projection_t* getProjection() { return m_projection.get(); } -private: +protected: inline void recomputeViewMatrix() { // TODO: adjust for handedness (axes flip) diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 00fe649a2..52a6020ed 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -255,13 +255,15 @@ class ICameraController : virtual public core::IReferenceCounted if (dPitch) { auto& pitch = output.emplace_back(); - pitch.type = (pitch.value = dPitch) > 0.f ? TiltUp : TiltDown; + pitch.type = dPitch > 0.f ? TiltUp : TiltDown; + pitch.value = std::abs(dPitch); } if (dYaw) { auto& yaw = output.emplace_back(); - yaw.type = (yaw.value = dYaw) > 0.f ? PanRight : PanLeft; + yaw.type = dYaw > 0.f ? PanRight : PanLeft; + yaw.value = std::abs(dYaw); } return output; From db77a10ab0be16b629a3ec3c3b6690c5b5951cae Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Mon, 28 Oct 2024 17:16:22 +0100 Subject: [PATCH 22/83] movement fixes, finally gimbal fully controls camera position & orientation (TODO: constraints for type of camera + I broke continuity of events signaling & need those keysPressed bools I guess) --- common/include/CCamera.hpp | 18 ++++++++++-------- common/include/camera/ICameraControl.hpp | 11 ++--------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 2f9751969..9ccd59521 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -37,6 +37,8 @@ class Camera final : public ICamera const auto [forward, up, right] = std::make_tuple(gimbal->getZAxis(), gimbal->getYAxis(), gimbal->getXAxis()); const bool isLeftHanded = projection->isLeftHanded(); // TODO? + const auto moveDirection = float32_t3(gimbal->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f)); + constexpr auto MoveSpeedScale = 0.003f; constexpr auto RotateSpeedScale = 0.003f; @@ -48,29 +50,29 @@ class Camera final : public ICamera for (const traits_t::controller_virtual_event_t& ev : virtualEvents) { - const auto dMoveValue = ev.value * dMoveFactor; - const auto dRotateValue = ev.value * dRotateFactor; + const float dMoveValue = ev.value * dMoveFactor; + const float dRotateValue = ev.value * dRotateFactor; switch (ev.type) { case traits_t::controller_t::MoveForward: { - gimbal->advance(dMoveValue); + gimbal->move(moveDirection * dMoveValue); } break; case traits_t::controller_t::MoveBackward: { - gimbal->advance(-dMoveValue); + gimbal->move(moveDirection * (-dMoveValue)); } break; - case traits_t::controller_t::MoveLeft: + case traits_t::controller_t::MoveRight: { - gimbal->strafe(dMoveValue); + gimbal->move(right * dMoveValue); } break; - case traits_t::controller_t::MoveRight: + case traits_t::controller_t::MoveLeft: { - gimbal->strafe(-dMoveValue); + gimbal->move(right * (-dMoveValue)); } break; case traits_t::controller_t::TiltUp: diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 52a6020ed..fe248c76d 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -106,7 +106,7 @@ class ICameraController : virtual public core::IReferenceCounted inline void move(float32_t3 delta) { - m_position += mul(m_orthonormal, delta); + m_position += delta; } inline void reset() @@ -217,15 +217,8 @@ class ICameraController : virtual public core::IReferenceCounted const auto dt = std::chrono::duration_cast(m_nextPresentationTimeStamp - ev.timeStamp).count(); assert(dt >= 0); - if (ev.action == nbl::ui::SKeyboardEvent::ECA_PRESSED && !m_keysDown[virtualKey]) - { - m_keysDown[virtualKey] = true; + if (ev.action == nbl::ui::SKeyboardEvent::ECA_PRESSED) output.emplace_back(CVirtualEvent{ virtualKey, static_cast(dt) }); - } - else if (ev.action == nbl::ui::SKeyboardEvent::ECA_RELEASED) - { - m_keysDown[virtualKey] = false; - } } } } From ae2b5201ca039e502d9e743cf587f6ef92431f49 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Mon, 28 Oct 2024 18:17:35 +0100 Subject: [PATCH 23/83] small typo --- common/include/CCamera.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 9ccd59521..7a49fffe1 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -34,11 +34,8 @@ class Camera final : public ICamera assert(gimbal); // TODO assert(projection); // TODO - const auto [forward, up, right] = std::make_tuple(gimbal->getZAxis(), gimbal->getYAxis(), gimbal->getXAxis()); const bool isLeftHanded = projection->isLeftHanded(); // TODO? - const auto moveDirection = float32_t3(gimbal->getOrientation() * glm::vec3(0.0f, 0.0f, 1.0f)); - constexpr auto MoveSpeedScale = 0.003f; constexpr auto RotateSpeedScale = 0.003f; @@ -50,6 +47,7 @@ class Camera final : public ICamera for (const traits_t::controller_virtual_event_t& ev : virtualEvents) { + const auto& forward = gimbal->getZAxis(), up = gimbal->getYAxis(), right = gimbal->getXAxis(); const float dMoveValue = ev.value * dMoveFactor; const float dRotateValue = ev.value * dRotateFactor; @@ -57,12 +55,12 @@ class Camera final : public ICamera { case traits_t::controller_t::MoveForward: { - gimbal->move(moveDirection * dMoveValue); + gimbal->move(forward * dMoveValue); } break; case traits_t::controller_t::MoveBackward: { - gimbal->move(moveDirection * (-dMoveValue)); + gimbal->move(forward * (-dMoveValue)); } break; case traits_t::controller_t::MoveRight: From d21bd96d60c5b03ebcf593f6d7a7baaa6de1a110 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Tue, 29 Oct 2024 16:48:57 +0100 Subject: [PATCH 24/83] accumulate move & rotation deltas, add setOrientation & correct processKeyboard a bit --- common/include/CCamera.hpp | 114 ++++++++++------------- common/include/camera/ICameraControl.hpp | 55 ++++++++--- 2 files changed, 92 insertions(+), 77 deletions(-) diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 7a49fffe1..31a105824 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -26,80 +26,68 @@ class Camera final : public ICamera } ~Camera() = default; - virtual void manipulate(std::span virtualEvents) override - { + virtual void manipulate(std::span virtualEvents) override + { auto* gimbal = traits_t::controller_t::m_gimbal.get(); - auto* projection = base_t::getProjection(); + assert(gimbal); - assert(gimbal); // TODO - assert(projection); // TODO + constexpr float MoveSpeedScale = 0.01f, RotateSpeedScale = 0.003f, MaxVerticalAngle = glm::radians(88.0f), MinVerticalAngle = -MaxVerticalAngle; + const auto& gForward = gimbal->getZAxis(), gRight = gimbal->getXAxis(); - const bool isLeftHanded = projection->isLeftHanded(); // TODO? - - constexpr auto MoveSpeedScale = 0.003f; - constexpr auto RotateSpeedScale = 0.003f; - - const auto dMoveFactor = traits_t::controller_t::m_moveSpeed * MoveSpeedScale; - const auto dRotateFactor = traits_t::controller_t::m_rotateSpeed * RotateSpeedScale; - - // TODO: UB/LB for pitch [-88,88]!!! we are not in cosmos but handle FPS camera in default case - // TODO: accumulate move & rotate scalars then do single move & rotate gimbal manipulation + struct + { + float dPitch = 0.f, dYaw = 0.f; + float32_t3 dMove = { 0.f, 0.f, 0.f }; + } accumulated; - for (const traits_t::controller_virtual_event_t& ev : virtualEvents) + for (const auto& event : virtualEvents) { - const auto& forward = gimbal->getZAxis(), up = gimbal->getYAxis(), right = gimbal->getXAxis(); - const float dMoveValue = ev.value * dMoveFactor; - const float dRotateValue = ev.value * dRotateFactor; + const float moveScalar = event.value * MoveSpeedScale; + const float rotateScalar = event.value * RotateSpeedScale; - switch (ev.type) + switch (event.type) { - case traits_t::controller_t::MoveForward: - { - gimbal->move(forward * dMoveValue); - } break; - - case traits_t::controller_t::MoveBackward: - { - gimbal->move(forward * (-dMoveValue)); - } break; - - case traits_t::controller_t::MoveRight: - { - gimbal->move(right * dMoveValue); - } break; - - case traits_t::controller_t::MoveLeft: - { - gimbal->move(right * (-dMoveValue)); - } break; - - case traits_t::controller_t::TiltUp: - { - gimbal->rotate(right, dRotateValue); - } break; - - case traits_t::controller_t::TiltDown: - { - gimbal->rotate(right, -dRotateValue); - } break; - - case traits_t::controller_t::PanRight: - { - gimbal->rotate(up, dRotateValue); - } break; - - case traits_t::controller_t::PanLeft: - { - gimbal->rotate(up, -dRotateValue); - } break; - - default: - continue; + case traits_t::controller_t::MoveForward: + accumulated.dMove += gForward * moveScalar; + break; + case traits_t::controller_t::MoveBackward: + accumulated.dMove -= gForward * moveScalar; + break; + case traits_t::controller_t::MoveRight: + accumulated.dMove += gRight * moveScalar; + break; + case traits_t::controller_t::MoveLeft: + accumulated.dMove -= gRight * moveScalar; + break; + case traits_t::controller_t::TiltUp: + accumulated.dPitch += rotateScalar; + break; + case traits_t::controller_t::TiltDown: + accumulated.dPitch -= rotateScalar; + break; + case traits_t::controller_t::PanRight: + accumulated.dYaw += rotateScalar; + break; + case traits_t::controller_t::PanLeft: + accumulated.dYaw -= rotateScalar; + break; + default: + break; } } + float currentPitch = atan2(glm::length(glm::vec2(gForward.x, gForward.z)), gForward.y) - glm::half_pi(); + float currentYaw = atan2(gForward.x, gForward.z); + + currentPitch = std::clamp(currentPitch + accumulated.dPitch, MinVerticalAngle, MaxVerticalAngle); + currentYaw += accumulated.dYaw; + + glm::quat orientation = glm::quat(glm::vec3(currentPitch, currentYaw, 0.0f)); + gimbal->setOrientation(orientation); + gimbal->move(accumulated.dMove); + base_t::recomputeViewMatrix(); - } + } }; } diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index fe248c76d..8503746da 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -82,6 +82,12 @@ class ICameraController : virtual public core::IReferenceCounted m_position = position; } + inline void setOrientation(const glm::quat& orientation) + { + m_orientation = glm::normalize(orientation); + updateOrthonormalMatrix(); + } + inline void rotate(const float32_t3& axis, float dRadians) { glm::quat dRotation = glm::angleAxis(dRadians, axis); @@ -198,29 +204,50 @@ class ICameraController : virtual public core::IReferenceCounted */ std::vector processKeyboard(std::span events) { + if (events.empty()) + return {}; + std::vector output; - for (const auto& ev : events) + constexpr auto NblVirtualKeys = std::to_array({ MoveForward, MoveBackward, MoveLeft, MoveRight, MoveUp, MoveDown, TiltUp, TiltDown, PanLeft, PanRight, RollLeft, RollRight, Reset }); + static_assert(NblVirtualKeys.size() == EventsCount); + + for (const auto virtualKey : NblVirtualKeys) { - constexpr auto NblVirtualKeys = std::to_array({ MoveForward, MoveBackward, MoveLeft, MoveRight, MoveUp, MoveDown, TiltUp, TiltDown, PanLeft, PanRight, RollLeft, RollRight, Reset }); - static_assert(NblVirtualKeys.size() == EventsCount); + const auto code = m_keysToEvent[virtualKey]; + bool& keyDown = m_keysDown[virtualKey]; - for (const auto virtualKey : NblVirtualKeys) + using virtual_key_state_t = std::tuple; + + auto updateVirtualState = [&]() -> virtual_key_state_t { - const auto code = m_keysToEvent[virtualKey]; + virtual_key_state_t state = { ui::E_KEY_CODE::EKC_NONE, false, 0.f }; - if (ev.keyCode == code) + for (const auto& ev : events) // TODO: improve the search { - if (code == ui::EKC_NONE) - continue; + if (ev.keyCode == code) + { + if (ev.action == nbl::ui::SKeyboardEvent::ECA_PRESSED && !keyDown) + keyDown = true; + else if (ev.action == nbl::ui::SKeyboardEvent::ECA_RELEASED) + keyDown = false; + + const auto dt = std::chrono::duration_cast(m_nextPresentationTimeStamp - ev.timeStamp).count(); + assert(dt >= 0); + + state = std::make_tuple(code, keyDown, dt); + break; + } + } + + return state; + }; - const auto dt = std::chrono::duration_cast(m_nextPresentationTimeStamp - ev.timeStamp).count(); - assert(dt >= 0); + const auto&& [physicalKey, isDown, dtAction] = updateVirtualState(); - if (ev.action == nbl::ui::SKeyboardEvent::ECA_PRESSED) - output.emplace_back(CVirtualEvent{ virtualKey, static_cast(dt) }); - } - } + if (physicalKey != ui::E_KEY_CODE::EKC_NONE) + if (isDown) + output.emplace_back(CVirtualEvent{ virtualKey, static_cast(dtAction) }); } return output; From 6cbd85caa3d646969d7724ca7f07b0b6a72e0957 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Tue, 29 Oct 2024 10:03:26 -0700 Subject: [PATCH 25/83] Saving work --- 09_GeometryCreator/main.cpp | 2 +- common/include/CCamera.hpp | 20 ++++++++++---------- common/include/CGeomtryCreatorScene.hpp | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/09_GeometryCreator/main.cpp b/09_GeometryCreator/main.cpp index 90ca78bbf..f54fe923f 100644 --- a/09_GeometryCreator/main.cpp +++ b/09_GeometryCreator/main.cpp @@ -307,7 +307,7 @@ class GeometryCreatorApp final : public examples::SimpleWindowedApplication hlsl::float32_t3x4 modelMatrix; hlsl::setTranslation(modelMatrix, hlsl::float32_t3(0)); - hlsl::setRotation(modelMatrix, hlsl::quaternion(0, 0, 0)); + hlsl::setRotation(modelMatrix, hlsl::quaternion::create(0, 0, 0)); hlsl::float32_t3x4 modelViewMatrix = hlsl::concatenateBFollowedByA(viewMatrix, modelMatrix); hlsl::float32_t4x4 modelViewProjectionMatrix = mul(viewProjectionMatrix, hlsl::getMatrix3x4As4x4(modelMatrix)); diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 7ecb4f6ff..28cbf0e57 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -71,8 +71,8 @@ class Camera projMatrix = projection; leftHanded = nbl::hlsl::determinant(projection) < 0.f; - nbl::hlsl::float64_t4x4 projMatPrecise = nbl::hlsl::get64BitPrecisionMatrix(projMatrix); - nbl::hlsl::float64_t4x4 viewMatPrecise = nbl::hlsl::get64BitPrecisionMatrix(nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); + nbl::hlsl::float64_t4x4 projMatPrecise = nbl::hlsl::getAs64BitPrecisionMatrix(projMatrix); + nbl::hlsl::float64_t4x4 viewMatPrecise = nbl::hlsl::getAs64BitPrecisionMatrix(nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); concatMatrix = mul(projMatrix, nbl::hlsl::getMatrix3x4As4x4(viewMatrix)); } @@ -112,15 +112,15 @@ class Camera inline void recomputeViewMatrix() { nbl::hlsl::float32_t3 pos = position; - nbl::hlsl::float32_t3 localTarget = nbl::hlsl::normalize(target - pos); + nbl::hlsl::float32_t3 localTarget = nbl::core::normalize(target - pos); // if upvector and vector to the target are the same, we have a // problem. so solve this problem: - nbl::hlsl::float32_t3 up = nbl::hlsl::normalize(upVector); + nbl::hlsl::float32_t3 up = nbl::core::normalize(upVector); nbl::hlsl::float32_t3 cross = nbl::hlsl::cross(localTarget, up); bool upVectorNeedsChange = nbl::core::lengthsquared(cross)[0] == 0; if (upVectorNeedsChange) - up = nbl::hlsl::normalize(backupUpVector); + up = nbl::core::normalize(backupUpVector); if (leftHanded) viewMatrix = nbl::hlsl::buildCameraLookAtMatrixLH(pos, target, up); @@ -176,7 +176,7 @@ class Camera localTarget = nbl::hlsl::float32_t3(0,0, nbl::core::max(1.f, nbl::core::length(pos)[0])); nbl::hlsl::float32_t3x4 mat; - nbl::hlsl::setRotation(mat, nbl::core::quaternion(relativeRotationX, relativeRotationY, 0)); + nbl::hlsl::setRotation(mat, nbl::hlsl::quaternion::create(relativeRotationX, relativeRotationY, 0)); localTarget = mul(mat, nbl::hlsl::float32_t4(localTarget, 1.0f)); // TODO: w = 1.0f for sure? setTarget(localTarget + pos); @@ -258,7 +258,7 @@ class Camera nbl::hlsl::float32_t3 movedir = localTarget; // TODO: //movedir.makeSafe3D(); - movedir = nbl::hlsl::normalize(movedir); + movedir = nbl::core::normalize(movedir); constexpr float MoveSpeedScale = 0.02f; @@ -269,12 +269,12 @@ class Camera // if upvector and vector to the target are the same, we have a // problem. so solve this problem: - nbl::hlsl::float32_t3 up = nbl::hlsl::normalize(upVector); + nbl::hlsl::float32_t3 up = nbl::core::normalize(upVector); nbl::hlsl::float32_t3 cross = nbl::hlsl::cross(localTarget, up); bool upVectorNeedsChange = nbl::hlsl::dot(cross, cross) == 0; if (upVectorNeedsChange) { - up = nbl::hlsl::normalize(backupUpVector); + up = nbl::core::normalize(backupUpVector); } nbl::hlsl::float32_t3 strafevect = localTarget; @@ -283,7 +283,7 @@ class Camera else strafevect = nbl::hlsl::cross(up, strafevect); - strafevect = nbl::hlsl::normalize(strafevect); + strafevect = nbl::core::normalize(strafevect); pos += strafevect * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_LEFT] * moveSpeed * MoveSpeedScale); pos -= strafevect * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_RIGHT] * moveSpeed * MoveSpeedScale); diff --git a/common/include/CGeomtryCreatorScene.hpp b/common/include/CGeomtryCreatorScene.hpp index ab90f59b9..7b6492d11 100644 --- a/common/include/CGeomtryCreatorScene.hpp +++ b/common/include/CGeomtryCreatorScene.hpp @@ -1098,7 +1098,7 @@ class ResourceBuilder struct ObjectDrawHookCpu { - nbl::core::matrix3x4SIMD model; + nbl::hlsl::float32_t3x4 model; nbl::asset::SBasicViewParameters viewParameters; ObjectMeta meta; }; From b69152cb350ddd994c5d7fde9a89a1d989fef61b Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Tue, 29 Oct 2024 14:38:49 -0700 Subject: [PATCH 26/83] Fixed CCamera.hpp --- common/include/CCamera.hpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/common/include/CCamera.hpp b/common/include/CCamera.hpp index 28cbf0e57..2fb3c626f 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CCamera.hpp @@ -7,12 +7,13 @@ #include #include +#include #include #include #include #include -class Camera +class Camera { public: Camera() = default; @@ -112,15 +113,15 @@ class Camera inline void recomputeViewMatrix() { nbl::hlsl::float32_t3 pos = position; - nbl::hlsl::float32_t3 localTarget = nbl::core::normalize(target - pos); + nbl::hlsl::float32_t3 localTarget = nbl::hlsl::normalize(target - pos); // if upvector and vector to the target are the same, we have a // problem. so solve this problem: - nbl::hlsl::float32_t3 up = nbl::core::normalize(upVector); + nbl::hlsl::float32_t3 up = nbl::hlsl::normalize(upVector); nbl::hlsl::float32_t3 cross = nbl::hlsl::cross(localTarget, up); - bool upVectorNeedsChange = nbl::core::lengthsquared(cross)[0] == 0; + bool upVectorNeedsChange = nbl::hlsl::lengthsquared(cross) == 0; if (upVectorNeedsChange) - up = nbl::core::normalize(backupUpVector); + up = nbl::hlsl::normalize(backupUpVector); if (leftHanded) viewMatrix = nbl::hlsl::buildCameraLookAtMatrixLH(pos, target, up); @@ -173,7 +174,7 @@ class Camera if (relativeRotationX > MaxVerticalAngle && relativeRotationX < 2 * nbl::core::PI()-MaxVerticalAngle) relativeRotationX = MaxVerticalAngle; - localTarget = nbl::hlsl::float32_t3(0,0, nbl::core::max(1.f, nbl::core::length(pos)[0])); + localTarget = nbl::hlsl::float32_t3(0,0, nbl::core::max(1.f, nbl::hlsl::length(pos))); nbl::hlsl::float32_t3x4 mat; nbl::hlsl::setRotation(mat, nbl::hlsl::quaternion::create(relativeRotationX, relativeRotationY, 0)); @@ -258,7 +259,7 @@ class Camera nbl::hlsl::float32_t3 movedir = localTarget; // TODO: //movedir.makeSafe3D(); - movedir = nbl::core::normalize(movedir); + movedir = nbl::hlsl::normalize(movedir); constexpr float MoveSpeedScale = 0.02f; @@ -269,12 +270,12 @@ class Camera // if upvector and vector to the target are the same, we have a // problem. so solve this problem: - nbl::hlsl::float32_t3 up = nbl::core::normalize(upVector); + nbl::hlsl::float32_t3 up = nbl::hlsl::normalize(upVector); nbl::hlsl::float32_t3 cross = nbl::hlsl::cross(localTarget, up); bool upVectorNeedsChange = nbl::hlsl::dot(cross, cross) == 0; if (upVectorNeedsChange) { - up = nbl::core::normalize(backupUpVector); + up = nbl::hlsl::normalize(backupUpVector); } nbl::hlsl::float32_t3 strafevect = localTarget; @@ -283,7 +284,7 @@ class Camera else strafevect = nbl::hlsl::cross(up, strafevect); - strafevect = nbl::core::normalize(strafevect); + strafevect = nbl::hlsl::normalize(strafevect); pos += strafevect * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_LEFT] * moveSpeed * MoveSpeedScale); pos -= strafevect * nbl::hlsl::float32_t3(perActionDt[E_CAMERA_MOVE_KEYS::ECMK_MOVE_RIGHT] * moveSpeed * MoveSpeedScale); From b1d968927dc75a83f8f2292ed03f48cdb9d10847 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Tue, 29 Oct 2024 17:45:50 -0700 Subject: [PATCH 27/83] Fixed example 62 --- 62_CAD/curves.cpp | 2 +- 62_CAD/curves.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/62_CAD/curves.cpp b/62_CAD/curves.cpp index 99438766b..2995859ee 100644 --- a/62_CAD/curves.cpp +++ b/62_CAD/curves.cpp @@ -53,7 +53,7 @@ float64_t ParametricCurve::inverseArcLen(float64_t targetLen, float64_t min, flo float64_t ParametricCurve::differentialArcLen(float64_t t) const { - return length(computeTangent(t)); + return hlsl::length(computeTangent(t)); } float64_t ExplicitCurve::differentialArcLen(float64_t x) const diff --git a/62_CAD/curves.h b/62_CAD/curves.h index f9dbb7a0e..c19fea4ec 100644 --- a/62_CAD/curves.h +++ b/62_CAD/curves.h @@ -6,6 +6,7 @@ #include #include #include +using namespace nbl; using namespace nbl::hlsl; #include @@ -127,7 +128,7 @@ struct CircularArc final : public ParametricCurve CircularArc(float64_t2 v, float64_t sweepAngle) : originY(-v.y), sweepAngle(sweepAngle) { - r = length(v); + r = hlsl::length(v); startAngle = getSign(v.y) * acos(v.x / r); } @@ -135,7 +136,7 @@ struct CircularArc final : public ParametricCurve CircularArc(float64_t2 v) : originY(-v.y) { - r = length(v); + r = hlsl::length(v); startAngle = getSign(v.y) * acos(v.x / r); sweepAngle = -2.0 * getSign(v.y) * acos(abs(originY) / r); } From ccbb37cf2bf150dec0c9ad8ea5d328fbb3806745 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Wed, 30 Oct 2024 07:46:11 +0100 Subject: [PATCH 28/83] remove old test methods --- common/include/camera/ICameraControl.hpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 8503746da..cafbbf1b0 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -95,21 +95,6 @@ class ICameraController : virtual public core::IReferenceCounted updateOrthonormalMatrix(); } - inline void strafe(float distance) - { - move({ 0.f, distance, 0.f }); - } - - inline void climb(float distance) - { - move({ 0.f, 0.f, distance }); - } - - inline void advance(float distance) - { - move({ distance, 0.f, 0.f }); - } - inline void move(float32_t3 delta) { m_position += delta; From 1a694ebbd26cd62a92d791fed4ac1b35f176d531 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Tue, 29 Oct 2024 12:50:49 -0700 Subject: [PATCH 29/83] Fixed example 61 --- 61_UI/main.cpp | 64 +++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/61_UI/main.cpp b/61_UI/main.cpp index ef03d88d6..ccb6e7b99 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -2,6 +2,7 @@ // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h +#include "nbl/builtin/hlsl/projection/projection.hlsl" #include "common.hpp" /* @@ -169,21 +170,21 @@ class UISampleApp final : public examples::SimpleWindowedApplication camera.setProjectionMatrix([&]() { - static matrix4SIMD projection; + static hlsl::float32_t4x4 projection; if (isPerspective) if(isLH) - projection = matrix4SIMD::buildProjectionMatrixPerspectiveFovLH(core::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); + projection = hlsl::buildProjectionMatrixPerspectiveFovLH(core::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); else - projection = matrix4SIMD::buildProjectionMatrixPerspectiveFovRH(core::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); + projection = hlsl::buildProjectionMatrixPerspectiveFovRH(core::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar); else { float viewHeight = viewWidth * io.DisplaySize.y / io.DisplaySize.x; if(isLH) - projection = matrix4SIMD::buildProjectionMatrixOrthoLH(viewWidth, viewHeight, zNear, zFar); + projection = hlsl::buildProjectionMatrixOrthoLH(viewWidth, viewHeight, zNear, zFar); else - projection = matrix4SIMD::buildProjectionMatrixOrthoRH(viewWidth, viewHeight, zNear, zFar); + projection = hlsl::buildProjectionMatrixOrthoRH(viewWidth, viewHeight, zNear, zFar); } return projection; @@ -246,9 +247,9 @@ class UISampleApp final : public examples::SimpleWindowedApplication if (viewDirty || firstFrame) { - core::vectorSIMDf cameraPosition(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance); - core::vectorSIMDf cameraTarget(0.f, 0.f, 0.f); - const static core::vectorSIMDf up(0.f, 1.f, 0.f); + hlsl::float32_t3 cameraPosition(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance); + hlsl::float32_t3 cameraTarget(0.f, 0.f, 0.f); + const static hlsl::float32_t3 up(0.f, 1.f, 0.f); camera.setPosition(cameraPosition); camera.setTarget(cameraTarget); @@ -322,20 +323,23 @@ class UISampleApp final : public examples::SimpleWindowedApplication static struct { - core::matrix4SIMD view, projection, model; + hlsl::float32_t4x4 view, projection, model; } imguizmoM16InOut; ImGuizmo::SetID(0u); - imguizmoM16InOut.view = core::transpose(matrix4SIMD(camera.getViewMatrix())); - imguizmoM16InOut.projection = core::transpose(camera.getProjectionMatrix()); - imguizmoM16InOut.model = core::transpose(core::matrix4SIMD(pass.scene->object.model)); + imguizmoM16InOut.view = hlsl::transpose(hlsl::getMatrix3x4As4x4(camera.getViewMatrix())); + imguizmoM16InOut.projection = hlsl::transpose(camera.getProjectionMatrix()); + imguizmoM16InOut.model = hlsl::transpose(hlsl::getMatrix3x4As4x4(pass.scene->object.model)); { if (flipGizmoY) // note we allow to flip gizmo just to match our coordinates imguizmoM16InOut.projection[1][1] *= -1.f; // https://johannesugb.github.io/gpu-programming/why-do-opengl-proj-matrices-fail-in-vulkan/ transformParams.editTransformDecomposition = true; - EditTransform(imguizmoM16InOut.view.pointer(), imguizmoM16InOut.projection.pointer(), imguizmoM16InOut.model.pointer(), transformParams); + EditTransform(reinterpret_cast(&imguizmoM16InOut.view), + reinterpret_cast(&imguizmoM16InOut.projection), + reinterpret_cast(&imguizmoM16InOut.model), + transformParams); } // to Nabla + update camera & model matrices @@ -343,14 +347,14 @@ class UISampleApp final : public examples::SimpleWindowedApplication const auto& projection = camera.getProjectionMatrix(); // TODO: make it more nicely - const_cast(view) = core::transpose(imguizmoM16InOut.view).extractSub3x4(); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) + const_cast(view) = float32_t3x4(hlsl::transpose(imguizmoM16InOut.view)); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) camera.setProjectionMatrix(projection); // update concatanated matrix { - static nbl::core::matrix3x4SIMD modelView, normal; - static nbl::core::matrix4SIMD modelViewProjection; + static nbl::hlsl::float32_t3x4 modelView, normal; + static nbl::hlsl::float32_t4x4 modelViewProjection; auto& hook = pass.scene->object; - hook.model = core::transpose(imguizmoM16InOut.model).extractSub3x4(); + hook.model = float32_t3x4(hlsl::transpose(imguizmoM16InOut.model)); { const auto& references = pass.scene->getResources().objects; const auto type = static_cast(gcIndex); @@ -362,13 +366,19 @@ class UISampleApp final : public examples::SimpleWindowedApplication auto& ubo = hook.viewParameters; - modelView = nbl::core::concatenateBFollowedByA(view, hook.model); - modelView.getSub3x3InverseTranspose(normal); - modelViewProjection = nbl::core::concatenateBFollowedByA(camera.getConcatenatedMatrix(), hook.model); + modelView = nbl::hlsl::concatenateBFollowedByA(view, hook.model); + float32_t3x3 normalTmp; + hlsl::getSub3x3InverseTranspose(modelView, normalTmp); + normal = float32_t3x4( + float32_t4(normalTmp[0], 0), + float32_t4(normalTmp[0], 0), + float32_t4(normalTmp[0], 0) + ); + //modelViewProjection = camera.getConcatenatedMatrix() * hlsl::getMatrix3x4As4x4(hook.model); - memcpy(ubo.MVP, modelViewProjection.pointer(), sizeof(ubo.MVP)); - memcpy(ubo.MV, modelView.pointer(), sizeof(ubo.MV)); - memcpy(ubo.NormalMat, normal.pointer(), sizeof(ubo.NormalMat)); + memcpy(ubo.MVP, reinterpret_cast(&modelViewProjection), sizeof(ubo.MVP)); + memcpy(ubo.MV, reinterpret_cast(&modelView), sizeof(ubo.MV)); + memcpy(ubo.NormalMat, reinterpret_cast(&normal), sizeof(ubo.NormalMat)); // object meta display { @@ -403,9 +413,9 @@ class UISampleApp final : public examples::SimpleWindowedApplication ImGui::Separator(); }; - addMatrixTable("Model Matrix", "ModelMatrixTable", 3, 4, pass.scene->object.model.pointer()); - addMatrixTable("Camera View Matrix", "ViewMatrixTable", 3, 4, view.pointer()); - addMatrixTable("Camera View Projection Matrix", "ViewProjectionMatrixTable", 4, 4, projection.pointer(), false); + addMatrixTable("Model Matrix", "ModelMatrixTable", 3, 4, reinterpret_cast(&(pass.scene->object.model))); + addMatrixTable("Camera View Matrix", "ViewMatrixTable", 3, 4, reinterpret_cast(&view)); + addMatrixTable("Camera View Projection Matrix", "ViewProjectionMatrixTable", 4, 4, reinterpret_cast(&projection), false); ImGui::End(); } @@ -781,7 +791,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication C_UI ui; } pass; - Camera camera = Camera(core::vectorSIMDf(0, 0, 0), core::vectorSIMDf(0, 0, 0), core::matrix4SIMD()); + Camera camera = Camera(hlsl::float32_t3(0, 0, 0), hlsl::float32_t3(0, 0, 0), hlsl::IdentityFloat32_t4x4); video::CDumbPresentationOracle oracle; uint16_t gcIndex = {}; // note: this is dirty however since I assume only single object in scene I can leave it now, when this example is upgraded to support multiple objects this needs to be changed From d3f325d6d2b4c9c623b8e70a0882a1bae17471fb Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Sat, 2 Nov 2024 15:49:33 +0100 Subject: [PATCH 30/83] remove gimbal member from camera interface, have matrix precision typename, rename CCamera to CFPSCamera, create GeneralPurposeRange and update sources, remove unused files, add some concepts, mark notes & todos --- 61_UI/include/common.hpp | 2 +- 61_UI/main.cpp | 45 +++++++------- .../include/{CCamera.hpp => CFPSCamera.hpp} | 33 ++++++----- common/include/ICamera.hpp | 58 ++++++------------- common/include/IRange.hpp | 29 ++++++++++ common/include/camera/CVirtualCameraEvent.hpp | 12 ---- common/include/camera/ICameraControl.hpp | 45 +++++++++++--- common/include/camera/IProjection.hpp | 35 ++++++----- 8 files changed, 147 insertions(+), 112 deletions(-) rename common/include/{CCamera.hpp => CFPSCamera.hpp} (77%) create mode 100644 common/include/IRange.hpp delete mode 100644 common/include/camera/CVirtualCameraEvent.hpp diff --git a/61_UI/include/common.hpp b/61_UI/include/common.hpp index a5def7551..cf8afeea8 100644 --- a/61_UI/include/common.hpp +++ b/61_UI/include/common.hpp @@ -4,7 +4,7 @@ #include // common api -#include "CCamera.hpp" +#include "CFPSCamera.hpp" #include "SimpleWindowedApplication.hpp" #include "CEventCallback.hpp" diff --git a/61_UI/main.cpp b/61_UI/main.cpp index 9e65776a7..b9a72c618 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -3,16 +3,13 @@ // For conditions of distribution and use, see copyright notice in nabla.h #include "common.hpp" - #include "camera/CCubeProjection.hpp" -#include "camera/ICameraControl.hpp" #include "glm/glm/ext/matrix_clip_space.hpp" // TODO: TESTING // FPS Camera, TESTS -using projection_matrix_t = float32_t4x4; -using camera_t = Camera; -using gimbal_t = camera_t::CGimbal; -using projection_t = camera_t::base_t::projection_t; +using matrix_precision_t = float32_t; +using camera_t = CFPSCamera; +using projection_t = camera_t::traits_t::projection_t; /* Renders scene texture to an offline @@ -182,18 +179,18 @@ class UISampleApp final : public examples::SimpleWindowedApplication if (isPerspective) { if (isLH) - projection->setMatrix(buildProjectionMatrixPerspectiveFovLH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); + projection->setMatrix(buildProjectionMatrixPerspectiveFovLH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); else - projection->setMatrix(buildProjectionMatrixPerspectiveFovRH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); + projection->setMatrix(buildProjectionMatrixPerspectiveFovRH(glm::radians(fov), io.DisplaySize.x / io.DisplaySize.y, zNear, zFar)); } else { float viewHeight = viewWidth * io.DisplaySize.y / io.DisplaySize.x; if (isLH) - projection->setMatrix(buildProjectionMatrixOrthoLH(viewWidth, viewHeight, zNear, zFar)); + projection->setMatrix(buildProjectionMatrixOrthoLH(viewWidth, viewHeight, zNear, zFar)); else - projection->setMatrix(buildProjectionMatrixOrthoRH(viewWidth, viewHeight, zNear, zFar)); + projection->setMatrix(buildProjectionMatrixOrthoRH(viewWidth, viewHeight, zNear, zFar)); } } @@ -257,8 +254,11 @@ class UISampleApp final : public examples::SimpleWindowedApplication float32_t3 cameraPosition(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance); float32_t3 cameraTarget(0.f, 0.f, 0.f); - gimbal->setPosition(cameraPosition); - camera->setTarget(cameraTarget); + // TODO: lets generate events and make it + // happen purely on gimbal manipulation! + + //camera->getGimbal()->setPosition(cameraPosition); + //camera->getGimbal()->setTarget(cameraTarget); firstFrame = false; } @@ -410,14 +410,14 @@ class UISampleApp final : public examples::SimpleWindowedApplication ImGui::Separator(); }; - auto& orientation = gimbal->getOrthonornalMatrix(); + const auto& orientation = camera->getGimbal().getOrthonornalMatrix(); addMatrixTable("Model Matrix", "ModelMatrixTable", 3, 4, &pass.scene->object.model[0][0]); - addMatrixTable("Right", "OrientationRightVec", 1, 3, &gimbal->getXAxis()[0]); - addMatrixTable("Up", "OrientationUpVec", 1, 3, &gimbal->getYAxis()[0]); - addMatrixTable("Forward", "OrientationForwardVec", 1, 3, &gimbal->getZAxis()[0]); - addMatrixTable("Position", "PositionForwardVec", 1, 3, &gimbal->getPosition()[0]); + addMatrixTable("Right", "OrientationRightVec", 1, 3, &camera->getGimbal().getXAxis()[0]); + addMatrixTable("Up", "OrientationUpVec", 1, 3, &camera->getGimbal().getYAxis()[0]); + addMatrixTable("Forward", "OrientationForwardVec", 1, 3, &camera->getGimbal().getZAxis()[0]); + addMatrixTable("Position", "PositionForwardVec", 1, 3, &camera->getGimbal().getPosition()[0]); //addMatrixTable("Camera Gimbal Orientation Matrix", "OrientationMatrixTable", 3, 3, &orientation[0][0]); addMatrixTable("Camera Gimbal View Matrix", "ViewMatrixTable", 3, 4, &view[0][0]); @@ -508,14 +508,12 @@ class UISampleApp final : public examples::SimpleWindowedApplication TESTS, TODO: remove all once finished work & integrate with the example properly */ - const float32_t3 position(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance), - target(0.f, 0.f, 0.f); + const float32_t3 position(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance); auto projection = make_smart_refctd_ptr(); - projection->setMatrix(buildProjectionMatrixPerspectiveFovLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar)); + projection->setMatrix(buildProjectionMatrixPerspectiveFovLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar)); - gimbal = make_smart_refctd_ptr(position); - camera = make_smart_refctd_ptr(core::smart_refctd_ptr(gimbal), core::smart_refctd_ptr(projection), target); + camera = make_smart_refctd_ptr(core::smart_refctd_ptr(projection), position); return true; } @@ -813,8 +811,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication C_UI ui; } pass; - core::smart_refctd_ptr gimbal; - core::smart_refctd_ptr> camera; + core::smart_refctd_ptr> camera; video::CDumbPresentationOracle oracle; uint16_t gcIndex = {}; // note: this is dirty however since I assume only single object in scene I can leave it now, when this example is upgraded to support multiple objects this needs to be changed diff --git a/common/include/CCamera.hpp b/common/include/CFPSCamera.hpp similarity index 77% rename from common/include/CCamera.hpp rename to common/include/CFPSCamera.hpp index 31a105824..8962a521c 100644 --- a/common/include/CCamera.hpp +++ b/common/include/CFPSCamera.hpp @@ -11,28 +11,30 @@ namespace nbl::hlsl // TODO: DIFFERENT NAMESPACE { // FPS Camera -template -class Camera final : public ICamera +template +class CFPSCamera final : public ICamera { public: - using base_t = ICamera; + using base_t = ICamera; using traits_t = typename base_t::Traits; - Camera(core::smart_refctd_ptr&& gimbal, core::smart_refctd_ptr projection, const float32_t3& target = { 0,0,0 }) - : base_t(core::smart_refctd_ptr(gimbal), core::smart_refctd_ptr(projection), target) + CFPSCamera(core::smart_refctd_ptr projection, const float32_t3& position, glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f)) + : base_t(core::smart_refctd_ptr(projection)), m_gimbal(position, orientation) { traits_t::controller_t::initKeysToEvent(); - base_t::recomputeViewMatrix(); + base_t::recomputeViewMatrix(m_gimbal); } - ~Camera() = default; + ~CFPSCamera() = default; - virtual void manipulate(std::span virtualEvents) override + const typename traits_t::gimbal_t& getGimbal() override { - auto* gimbal = traits_t::controller_t::m_gimbal.get(); - assert(gimbal); + return m_gimbal; + } + virtual void manipulate(std::span virtualEvents) override + { constexpr float MoveSpeedScale = 0.01f, RotateSpeedScale = 0.003f, MaxVerticalAngle = glm::radians(88.0f), MinVerticalAngle = -MaxVerticalAngle; - const auto& gForward = gimbal->getZAxis(), gRight = gimbal->getXAxis(); + const auto& gForward = m_gimbal.getZAxis(), gRight = m_gimbal.getXAxis(); struct { @@ -83,11 +85,14 @@ class Camera final : public ICamera currentYaw += accumulated.dYaw; glm::quat orientation = glm::quat(glm::vec3(currentPitch, currentYaw, 0.0f)); - gimbal->setOrientation(orientation); - gimbal->move(accumulated.dMove); + m_gimbal.setOrientation(orientation); + m_gimbal.move(accumulated.dMove); - base_t::recomputeViewMatrix(); + base_t::recomputeViewMatrix(m_gimbal); } + +private: + traits_t::gimbal_t m_gimbal; }; } diff --git a/common/include/ICamera.hpp b/common/include/ICamera.hpp index 2f17fe79d..b7978d100 100644 --- a/common/include/ICamera.hpp +++ b/common/include/ICamera.hpp @@ -16,11 +16,11 @@ namespace nbl::hlsl // TODO: DIFFERENT NAMESPACE { -template -class ICamera : public ICameraController +template +class ICamera : public ICameraController { public: - using base_t = typename ICameraController; + using base_t = typename ICameraController; struct Traits { @@ -28,53 +28,33 @@ class ICamera : public ICameraController using projection_t = typename controller_t::projection_t; using gimbal_t = typename controller_t::CGimbal; using controller_virtual_event_t = typename controller_t::CVirtualEvent; + using matrix_precision_t = typename T; // TODO: actually all vectors/scalars should have precision type T and because of projection matrix constraints allowed is only float32_t & float64_t }; - ICamera(core::smart_refctd_ptr&& gimbal, core::smart_refctd_ptr projection, const float32_t3& target = {0,0,0}) - : base_t(core::smart_refctd_ptr(gimbal)), m_projection(core::smart_refctd_ptr(projection)) { setTarget(target); } + ICamera(core::smart_refctd_ptr projection) + : base_t(), m_projection(core::smart_refctd_ptr(projection)) {} ~ICamera() = default; - inline void setPosition(const float32_t3& position) - { - const auto* gimbal = base_t::m_gimbal.get(); - gimbal->setPosition(position); - recomputeViewMatrix(); - } - - inline void setTarget(const float32_t3& position) - { - m_target = position; + // NOTE: I dont like to make it virtual but if we assume we can + // have more gimbals & we dont store single one in the interface + // then one of them must be the one we model the camera view with + // eg "Follow Camera" -> range of 2 gimbals but only first + // models the camera view + virtual const Traits::gimbal_t& getGimbal() = 0u; - const auto* gimbal = base_t::m_gimbal.get(); - auto localTarget = m_target - gimbal->getPosition(); - - // TODO: use gimbal to perform a rotation! - - recomputeViewMatrix(); - } - - inline const float32_t3& getPosition() { return base_t::m_gimbal->getPosition(); } - inline const float32_t3& getTarget() { return m_target; } - inline const float32_t3x4& getViewMatrix() const { return m_viewMatrix; } + inline const matrix& getViewMatrix() const { return m_viewMatrix; } inline Traits::projection_t* getProjection() { return m_projection.get(); } protected: - inline void recomputeViewMatrix() + // Recomputes view matrix for a given gimbal. Note that a camera type implementation could have multiple gimbals - not all of them will be used to model the camera view itself but one + // (TODO: (*) unless? I guess its to decide if we talk bout single view or to allow to have view per gimbal, but imho we should have 1 -> could just spam more instances of camera type to cover more views) + inline void recomputeViewMatrix(Traits::gimbal_t& gimbal) { - // TODO: adjust for handedness (axes flip) - const bool isLeftHanded = m_projection->isLeftHanded(); - const auto* gimbal = base_t::m_gimbal.get(); - const auto& position = gimbal->getPosition(); - - const auto [xaxis, yaxis, zaxis] = std::make_tuple(gimbal->getXAxis(), gimbal->getYAxis(), gimbal->getZAxis()); - m_viewMatrix[0u] = float32_t4(xaxis, -hlsl::dot(xaxis, position)); - m_viewMatrix[1u] = float32_t4(yaxis, -hlsl::dot(yaxis, position)); - m_viewMatrix[2u] = float32_t4(zaxis, -hlsl::dot(zaxis, position)); + gimbal.computeViewMatrix(m_viewMatrix, m_projection->isLeftHanded()); } - const core::smart_refctd_ptr m_projection; - float32_t3x4 m_viewMatrix; - float32_t3 m_target; + const core::smart_refctd_ptr m_projection; // TODO: move it from here + matrix m_viewMatrix; }; } diff --git a/common/include/IRange.hpp b/common/include/IRange.hpp new file mode 100644 index 000000000..5c6fe751b --- /dev/null +++ b/common/include/IRange.hpp @@ -0,0 +1,29 @@ +#ifndef _NBL_IRANGE_HPP_ +#define _NBL_IRANGE_HPP_ + +namespace nbl::hlsl +{ + +template +concept GeneralPurposeRange = requires +{ + typename std::ranges::range_value_t; +}; + +//! Interface class for a general purpose range +template +class IRange +{ +public: + using range_t = Range; + using range_value_t = std::ranges::range_value_t; + + IRange(range_t&& range) : m_range(std::move(range)) {} + +protected: + range_t m_range; +}; + +} // namespace nbl::hlsl + +#endif // _NBL_IRANGE_HPP_ \ No newline at end of file diff --git a/common/include/camera/CVirtualCameraEvent.hpp b/common/include/camera/CVirtualCameraEvent.hpp deleted file mode 100644 index 309c91662..000000000 --- a/common/include/camera/CVirtualCameraEvent.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _NBL_VIRTUAL_CAMERA_EVENT_HPP_ -#define _NBL_VIRTUAL_CAMERA_EVENT_HPP_ - -#include "nbl/builtin/hlsl/cpp_compat/matrix.hlsl" - -// TODO: DIFFERENT NAMESPACE -namespace nbl::hlsl -{ - -} - -#endif // _NBL_VIRTUAL_CAMERA_EVENT_HPP_ \ No newline at end of file diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index cafbbf1b0..565b7970a 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -2,8 +2,6 @@ #define _NBL_I_CAMERA_CONTROLLER_HPP_ #include "IProjection.hpp" -#include "../ICamera.hpp" -#include "CVirtualCameraEvent.hpp" #include "glm/glm/ext/matrix_transform.hpp" // TODO: TEMPORARY!!! whatever used will be moved to cpp #include "glm/glm/gtc/quaternion.hpp" #include "nbl/builtin/hlsl/matrix_utils/transformation_matrix_utils.hlsl" @@ -12,11 +10,12 @@ namespace nbl::hlsl { -template +template class ICameraController : virtual public core::IReferenceCounted { public: - using projection_t = typename IProjection; + using matrix_precision_t = typename T; + using projection_t = typename IProjection>; enum VirtualEventType : uint8_t { @@ -71,7 +70,7 @@ class ICameraController : virtual public core::IReferenceCounted manipulation_encode_t value; }; - class CGimbal : virtual public core::IReferenceCounted + class CGimbal { public: CGimbal(const float32_t3& position, glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f)) @@ -123,6 +122,14 @@ class ICameraController : virtual public core::IReferenceCounted // Base forward vector in orthonormal basis, base "forward" vector (Z-axis) inline const float32_t3& getZAxis() const { return m_orthonormal[2u]; } + inline void computeViewMatrix(matrix& output, bool isLeftHanded) + { + const auto&& [xaxis, yaxis, zaxis] = std::make_tuple(getXAxis(), getYAxis(), getZAxis() * (isLeftHanded ? 1.f : -1.f)); + output[0u] = vector(xaxis, -hlsl::dot(xaxis, m_position)); + output[1u] = vector(yaxis, -hlsl::dot(yaxis, m_position)); + output[2u] = vector(zaxis, -hlsl::dot(zaxis, m_position)); + } + private: inline void updateOrthonormalMatrix() { @@ -158,7 +165,7 @@ class ICameraController : virtual public core::IReferenceCounted float32_t3x3 m_orthonormal; }; - ICameraController(core::smart_refctd_ptr&& gimbal) : m_gimbal(core::smart_refctd_ptr(gimbal)) {} + ICameraController() {} // override controller keys map, it binds a key code to a virtual event void updateKeysToEvent(const std::vector& codes, VirtualEventType event) @@ -299,7 +306,6 @@ class ICameraController : virtual public core::IReferenceCounted m_keysToEvent[Reset] = ui::E_KEY_CODE::EKC_R ; } - core::smart_refctd_ptr m_gimbal; std::array m_keysToEvent = {}; float m_moveSpeed = 1.f, m_rotateSpeed = 1.f; bool m_keysDown[EventsCount] = {}; @@ -307,6 +313,31 @@ class ICameraController : virtual public core::IReferenceCounted std::chrono::microseconds m_nextPresentationTimeStamp = {}, m_lastVirtualUpTimeStamp = {}; }; +template +concept GimbalRange = GeneralPurposeRange && requires +{ + requires ProjectionMatrix::projection_t>; + requires std::same_as, typename ICameraController::projection_t>::CGimbal>; +}; + +template +class IGimbalRange : public IRange +{ +public: + using base_t = IRange; + using range_t = typename base_t::range_t; + using gimbal_t = typename base_t::range_value_t; + + IGimbalRange(range_t&& gimbals) : base_t(std::move(gimbals)) {} + inline const range_t& getGimbals() const { return base_t::m_range; } + +protected: + inline range_t& getGimbals() const { return base_t::m_range; } +}; + +// TODO NOTE: eg. "follow camera" should use GimbalRange::CGimbal, 2u>>, +// one per camera itself and one for target it follows + } // nbl::hlsl namespace #endif // _NBL_I_CAMERA_CONTROLLER_HPP_ \ No newline at end of file diff --git a/common/include/camera/IProjection.hpp b/common/include/camera/IProjection.hpp index 1384f8e87..8de5c19f6 100644 --- a/common/include/camera/IProjection.hpp +++ b/common/include/camera/IProjection.hpp @@ -2,12 +2,13 @@ #define _NBL_IPROJECTION_HPP_ #include "nbl/builtin/hlsl/cpp_compat/matrix.hlsl" +#include "IRange.hpp" namespace nbl::hlsl { template -concept ProjectionMatrix = is_any_of_v; +concept ProjectionMatrix = is_any_of_v; //! Interface class for projection template @@ -37,29 +38,33 @@ class IProjection : virtual public core::IReferenceCounted bool m_isLeftHanded; }; +template +struct is_projection : std::false_type {}; + +template +struct is_projection> : std::true_type {}; + +template +inline constexpr bool is_projection_v = is_projection::value; + template -concept ProjectionRange = requires +concept ProjectionRange = GeneralPurposeRange && requires { - typename std::ranges::range_value_t; - // TODO: smart_refctd_ptr check for range_value_t + its type check to grant IProjection + requires core::is_smart_refctd_ptr_v>; + requires is_projection_v::pointee>; }; //! Interface class for a range of IProjection projections template>, 1u>> -class IProjectionRange +class IProjectionRange : public IRange { public: - using range_t = Range; - using projection_t = std::ranges::range_value_t; - - //! Constructor for the range of projections - IProjectionRange(range_t&& projections) : m_projectionRange(std::move(projections)) {} - - //! Get the stored range of projections - const range_t& getProjections() const { return m_projectionRange; } + using base_t = IRange; + using range_t = typename base_t::range_t; + using projection_t = typename base_t::range_value_t; -protected: - range_t m_projectionRange; + IProjectionRange(range_t&& projections) : base_t(std::move(projections)) {} + const range_t& getProjections() const { return base_t::m_range; } }; } // namespace nbl::hlsl From f9fce56971dd80264eb107c413ba0b038f4ebf96 Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Sun, 3 Nov 2024 19:29:23 +0100 Subject: [PATCH 31/83] move virtual events outside templates into CVirtualGimbalEvent, have nice constexpr table to iterate over them, move view responsibility modeling to gimbal + make it optional! (yes - it's a good idea imo), keep manipulation state flag & manipulation counter to avoid updating the view too frequently, remove projection from cameras (projections will own/reference cameras), update a few structs, sources, clean some code, mark TODOs & notes --- 61_UI/main.cpp | 41 ++- common/include/CFPSCamera.hpp | 54 ++-- common/include/ICamera.hpp | 25 +- common/include/camera/ICameraControl.hpp | 338 ++++++++++++++--------- 4 files changed, 259 insertions(+), 199 deletions(-) diff --git a/61_UI/main.cpp b/61_UI/main.cpp index b9a72c618..1d6016830 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -9,7 +9,7 @@ // FPS Camera, TESTS using matrix_precision_t = float32_t; using camera_t = CFPSCamera; -using projection_t = camera_t::traits_t::projection_t; +using projection_t = IProjection>; // TODO: temporary -> projections will own/reference cameras /* Renders scene texture to an offline @@ -174,8 +174,6 @@ class UISampleApp final : public examples::SimpleWindowedApplication { ImGuiIO& io = ImGui::GetIO(); { - auto* projection = camera->getProjection(); - if (isPerspective) { if (isLH) @@ -329,10 +327,11 @@ class UISampleApp final : public examples::SimpleWindowedApplication float32_t4x4 view, projection, model; } imguizmoM16InOut; - const auto& projectionMatrix = camera->getProjection()->getMatrix(); + const auto& projectionMatrix = projection->getMatrix(); + const auto& view = camera->getGimbal().getView().value(); ImGuizmo::SetID(0u); - imguizmoM16InOut.view = transpose(getMatrix3x4As4x4(camera->getViewMatrix())); + imguizmoM16InOut.view = transpose(getMatrix3x4As4x4(view.matrix)); imguizmoM16InOut.projection = transpose(projectionMatrix); imguizmoM16InOut.model = transpose(getMatrix3x4As4x4(pass.scene->object.model)); { @@ -344,10 +343,9 @@ class UISampleApp final : public examples::SimpleWindowedApplication } // to Nabla + update camera & model matrices - const auto& view = camera->getViewMatrix(); // TODO: make it more nicely - const_cast(view) = float32_t3x4(transpose(imguizmoM16InOut.view)); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) + const_cast(view.matrix) = float32_t3x4(transpose(imguizmoM16InOut.view)); // a hack, correct way would be to use inverse matrix and get position + target because now it will bring you back to last position & target when switching from gizmo move to manual move (but from manual to gizmo is ok) { static float32_t3x4 modelView, normal; static float32_t4x4 modelViewProjection; @@ -365,12 +363,12 @@ class UISampleApp final : public examples::SimpleWindowedApplication auto& ubo = hook.viewParameters; - modelView = concatenateBFollowedByA(view, hook.model); + modelView = concatenateBFollowedByA(view.matrix, hook.model); // TODO //modelView.getSub3x3InverseTranspose(normal); - auto concatMatrix = mul(projectionMatrix, getMatrix3x4As4x4(view)); + auto concatMatrix = mul(projectionMatrix, getMatrix3x4As4x4(view.matrix)); modelViewProjection = mul(concatMatrix, getMatrix3x4As4x4(hook.model)); memcpy(ubo.MVP, &modelViewProjection[0][0], sizeof(ubo.MVP)); @@ -420,7 +418,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication addMatrixTable("Position", "PositionForwardVec", 1, 3, &camera->getGimbal().getPosition()[0]); //addMatrixTable("Camera Gimbal Orientation Matrix", "OrientationMatrixTable", 3, 3, &orientation[0][0]); - addMatrixTable("Camera Gimbal View Matrix", "ViewMatrixTable", 3, 4, &view[0][0]); + addMatrixTable("Camera Gimbal View Matrix", "ViewMatrixTable", 3, 4, &view.matrix[0][0]); addMatrixTable("Camera Gimbal Projection Matrix", "ProjectionMatrixTable", 4, 4, &projectionMatrix[0][0], false); ImGui::End(); @@ -509,11 +507,8 @@ class UISampleApp final : public examples::SimpleWindowedApplication */ const float32_t3 position(cosf(camYAngle)* cosf(camXAngle)* transformParams.camDistance, sinf(camXAngle)* transformParams.camDistance, sinf(camYAngle)* cosf(camXAngle)* transformParams.camDistance); - - auto projection = make_smart_refctd_ptr(); projection->setMatrix(buildProjectionMatrixPerspectiveFovLH(glm::radians(fov), float(m_window->getWidth()) / float(m_window->getHeight()), zNear, zFar)); - - camera = make_smart_refctd_ptr(core::smart_refctd_ptr(projection), position); + camera = make_smart_refctd_ptr(position); return true; } @@ -692,9 +687,6 @@ class UISampleApp final : public examples::SimpleWindowedApplication inline void update() { - camera->setMoveSpeed(moveSpeed); - camera->setRotateSpeed(rotateSpeed); - static std::chrono::microseconds previousEventTimestamp{}; m_inputSystem->getDefaultMouse(&mouse); @@ -718,9 +710,6 @@ class UISampleApp final : public examples::SimpleWindowedApplication std::vector mouse{}; std::vector keyboard{}; } capturedEvents; - - if (move) - camera->begin(nextPresentationTimestamp); mouse.consumeEvents([&](const IMouseEventChannel::range_t& events) -> void { @@ -761,13 +750,14 @@ class UISampleApp final : public examples::SimpleWindowedApplication if (move) { - const auto virtualMouseEvents = camera->processMouse(params.mouseEvents); - const auto virtualKeyboardEvents = camera->processKeyboard(params.keyboardEvents); + static std::vector virtualMouseEvents(CVirtualGimbalEvent::VirtualEventsTypeTable.size()), virtualKeyboardEvents(CVirtualGimbalEvent::VirtualEventsTypeTable.size()); + uint32_t vEventsMouseCount, vEventsKeyboardCount; - camera->manipulate({ virtualMouseEvents.data(), virtualMouseEvents.size()}); - camera->manipulate({ virtualKeyboardEvents.data(), virtualKeyboardEvents.size()}); + camera->processMouse(virtualMouseEvents.data(), vEventsMouseCount, params.mouseEvents); + camera->processKeyboard(virtualKeyboardEvents.data(), vEventsKeyboardCount, params.keyboardEvents); - camera->end(nextPresentationTimestamp); + camera->manipulate({ virtualMouseEvents.data(), vEventsMouseCount }); + camera->manipulate({ virtualKeyboardEvents.data(), vEventsKeyboardCount }); } pass.ui.manager->update(params); @@ -811,6 +801,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication C_UI ui; } pass; + smart_refctd_ptr projection = make_smart_refctd_ptr(); // TMP! core::smart_refctd_ptr> camera; video::CDumbPresentationOracle oracle; diff --git a/common/include/CFPSCamera.hpp b/common/include/CFPSCamera.hpp index 8962a521c..58e07e1c0 100644 --- a/common/include/CFPSCamera.hpp +++ b/common/include/CFPSCamera.hpp @@ -18,11 +18,10 @@ class CFPSCamera final : public ICamera using base_t = ICamera; using traits_t = typename base_t::Traits; - CFPSCamera(core::smart_refctd_ptr projection, const float32_t3& position, glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f)) - : base_t(core::smart_refctd_ptr(projection)), m_gimbal(position, orientation) + CFPSCamera(const float32_t3& position, glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f)) + : base_t(), m_gimbal({ .position = position, .orientation = orientation, .withView = true }) { - traits_t::controller_t::initKeysToEvent(); - base_t::recomputeViewMatrix(m_gimbal); + initKeysToEvent(); } ~CFPSCamera() = default; @@ -31,8 +30,11 @@ class CFPSCamera final : public ICamera return m_gimbal; } - virtual void manipulate(std::span virtualEvents) override + virtual void manipulate(std::span virtualEvents) override { + if (!virtualEvents.size()) + return; + constexpr float MoveSpeedScale = 0.01f, RotateSpeedScale = 0.003f, MaxVerticalAngle = glm::radians(88.0f), MinVerticalAngle = -MaxVerticalAngle; const auto& gForward = m_gimbal.getZAxis(), gRight = m_gimbal.getXAxis(); @@ -44,33 +46,33 @@ class CFPSCamera final : public ICamera for (const auto& event : virtualEvents) { - const float moveScalar = event.value * MoveSpeedScale; - const float rotateScalar = event.value * RotateSpeedScale; + const float moveScalar = event.magnitude * MoveSpeedScale; + const float rotateScalar = event.magnitude * RotateSpeedScale; switch (event.type) { - case traits_t::controller_t::MoveForward: + case CVirtualGimbalEvent::MoveForward: accumulated.dMove += gForward * moveScalar; break; - case traits_t::controller_t::MoveBackward: + case CVirtualGimbalEvent::MoveBackward: accumulated.dMove -= gForward * moveScalar; break; - case traits_t::controller_t::MoveRight: + case CVirtualGimbalEvent::MoveRight: accumulated.dMove += gRight * moveScalar; break; - case traits_t::controller_t::MoveLeft: + case CVirtualGimbalEvent::MoveLeft: accumulated.dMove -= gRight * moveScalar; break; - case traits_t::controller_t::TiltUp: + case CVirtualGimbalEvent::TiltUp: accumulated.dPitch += rotateScalar; break; - case traits_t::controller_t::TiltDown: + case CVirtualGimbalEvent::TiltDown: accumulated.dPitch -= rotateScalar; break; - case traits_t::controller_t::PanRight: + case CVirtualGimbalEvent::PanRight: accumulated.dYaw += rotateScalar; break; - case traits_t::controller_t::PanLeft: + case CVirtualGimbalEvent::PanLeft: accumulated.dYaw -= rotateScalar; break; default: @@ -85,13 +87,29 @@ class CFPSCamera final : public ICamera currentYaw += accumulated.dYaw; glm::quat orientation = glm::quat(glm::vec3(currentPitch, currentYaw, 0.0f)); - m_gimbal.setOrientation(orientation); - m_gimbal.move(accumulated.dMove); - base_t::recomputeViewMatrix(m_gimbal); + m_gimbal.begin(); + { + m_gimbal.setOrientation(orientation); + m_gimbal.move(accumulated.dMove); + } + m_gimbal.end(); } private: + void initKeysToEvent() override + { + traits_t::controller_t::updateKeysToEvent([](CVirtualGimbalEvent::keys_to_virtual_events_t& keys) + { + keys[CVirtualGimbalEvent::MoveForward] = ui::E_KEY_CODE::EKC_W; + keys[CVirtualGimbalEvent::MoveBackward] = ui::E_KEY_CODE::EKC_S; + keys[CVirtualGimbalEvent::MoveLeft] = ui::E_KEY_CODE::EKC_A; + keys[CVirtualGimbalEvent::MoveRight] = ui::E_KEY_CODE::EKC_D; + keys[CVirtualGimbalEvent::MoveUp] = ui::E_KEY_CODE::EKC_SPACE; + keys[CVirtualGimbalEvent::MoveDown] = ui::E_KEY_CODE::EKC_LEFT_SHIFT; + }); + } + traits_t::gimbal_t m_gimbal; }; diff --git a/common/include/ICamera.hpp b/common/include/ICamera.hpp index b7978d100..4faebe536 100644 --- a/common/include/ICamera.hpp +++ b/common/include/ICamera.hpp @@ -25,36 +25,15 @@ class ICamera : public ICameraController struct Traits { using controller_t = base_t; - using projection_t = typename controller_t::projection_t; using gimbal_t = typename controller_t::CGimbal; - using controller_virtual_event_t = typename controller_t::CVirtualEvent; using matrix_precision_t = typename T; // TODO: actually all vectors/scalars should have precision type T and because of projection matrix constraints allowed is only float32_t & float64_t }; - ICamera(core::smart_refctd_ptr projection) - : base_t(), m_projection(core::smart_refctd_ptr(projection)) {} + ICamera() : base_t() {} ~ICamera() = default; - // NOTE: I dont like to make it virtual but if we assume we can - // have more gimbals & we dont store single one in the interface - // then one of them must be the one we model the camera view with - // eg "Follow Camera" -> range of 2 gimbals but only first - // models the camera view + // Returns a gimbal which *models the camera view*, note that a camera type implementation may have multiple gimbals under the hood virtual const Traits::gimbal_t& getGimbal() = 0u; - - inline const matrix& getViewMatrix() const { return m_viewMatrix; } - inline Traits::projection_t* getProjection() { return m_projection.get(); } - -protected: - // Recomputes view matrix for a given gimbal. Note that a camera type implementation could have multiple gimbals - not all of them will be used to model the camera view itself but one - // (TODO: (*) unless? I guess its to decide if we talk bout single view or to allow to have view per gimbal, but imho we should have 1 -> could just spam more instances of camera type to cover more views) - inline void recomputeViewMatrix(Traits::gimbal_t& gimbal) - { - gimbal.computeViewMatrix(m_viewMatrix, m_projection->isLeftHanded()); - } - - const core::smart_refctd_ptr m_projection; // TODO: move it from here - matrix m_viewMatrix; }; } diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index 565b7970a..ff918faa4 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -10,13 +10,9 @@ namespace nbl::hlsl { -template -class ICameraController : virtual public core::IReferenceCounted +struct CVirtualGimbalEvent { -public: - using matrix_precision_t = typename T; - using projection_t = typename IProjection>; - + //! Virtual event representing a gimbal manipulation enum VirtualEventType : uint8_t { // Strafe forward @@ -55,53 +51,125 @@ class ICameraController : virtual public core::IReferenceCounted // Roll the camera clockwise around the forward axis (roll) RollRight, - // Reset the camera to the default state - Reset, - EventsCount }; - //! Virtual event representing a manipulation - struct CVirtualEvent + using manipulation_encode_t = float64_t; + using keys_to_virtual_events_t = std::array; + + VirtualEventType type; + manipulation_encode_t magnitude; + + static inline constexpr auto VirtualEventsTypeTable = []() { - using manipulation_encode_t = float64_t; + std::array output; - VirtualEventType type; - manipulation_encode_t value; - }; + for (uint16_t i = 0u; i < EventsCount - 1u; ++i) + { + output[i] = static_cast(i); + } + + return output; + }(); +}; + +template +class ICameraController : virtual public core::IReferenceCounted +{ +public: + using matrix_precision_t = typename T; class CGimbal { public: - CGimbal(const float32_t3& position, glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f)) - : m_position(position), m_orientation(orientation) { updateOrthonormalMatrix(); } + struct SCreationParameters + { + float32_t3 position; + glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); + bool withView = true; + }; + + // Gimbal's view matrix consists of an orthonormal basis (https://en.wikipedia.org/wiki/Orthonormal_basis) + // for orientation and a translation component that positions the world relative to the gimbal's position. + // Any camera type is supposed to manipulate a position & orientation of a gimbal + // with "virtual events" which model its view bound to the camera + struct SView + { + matrix matrix = {}; + bool isLeftHandSystem = true; + }; + + CGimbal(SCreationParameters&& parameters) + : m_position(parameters.position), m_orientation(parameters.orientation) + { + updateOrthonormalOrientationBase(); + + if (parameters.withView) + { + m_view = std::optional(SView{}); // RVO + updateView(); + } + } + + void begin() + { + m_isManipulating = true; + m_counter = 0u; + } inline void setPosition(const float32_t3& position) { + assert(m_isManipulating); // TODO: log error and return without doing nothing + + if (m_position != position) + m_counter++; + m_position = position; } inline void setOrientation(const glm::quat& orientation) { + assert(m_isManipulating); // TODO: log error and return without doing nothing + + if(m_orientation != orientation) + m_counter++; + m_orientation = glm::normalize(orientation); - updateOrthonormalMatrix(); + updateOrthonormalOrientationBase(); } inline void rotate(const float32_t3& axis, float dRadians) { + assert(m_isManipulating); // TODO: log error and return without doing nothing + + if(dRadians) + m_counter++; + glm::quat dRotation = glm::angleAxis(dRadians, axis); m_orientation = glm::normalize(dRotation * m_orientation); - updateOrthonormalMatrix(); + updateOrthonormalOrientationBase(); } inline void move(float32_t3 delta) { - m_position += delta; + assert(m_isManipulating); // TODO: log error and return without doing nothing + + auto newPosition = m_position + delta; + + if (newPosition != m_position) + m_counter++; + + m_position = newPosition; } - inline void reset() + void end() { - // TODO + m_isManipulating = false; + + if (m_counter > 0u) + updateView(); + + m_counter = 0u; } // Position of gimbal @@ -110,104 +178,113 @@ class ICameraController : virtual public core::IReferenceCounted // Orientation of gimbal inline const glm::quat& getOrientation() const { return m_orientation; } - // Orthonormal [getXAxis(), getYAxis(), getZAxis()] matrix + // Orthonormal [getXAxis(), getYAxis(), getZAxis()] orientation matrix inline const float32_t3x3& getOrthonornalMatrix() const { return m_orthonormal; } - // Base right vector in orthonormal basis, base "right" vector (X-axis) + // Base "right" vector in orthonormal orientation basis (X-axis) inline const float32_t3& getXAxis() const { return m_orthonormal[0u]; } - // Base up vector in orthonormal basis, base "up" vector (Y-axis) + // Base "up" vector in orthonormal orientation basis (Y-axis) inline const float32_t3& getYAxis() const { return m_orthonormal[1u]; } - // Base forward vector in orthonormal basis, base "forward" vector (Z-axis) + // Base "forward" vector in orthonormal orientation basis (Z-axis) inline const float32_t3& getZAxis() const { return m_orthonormal[2u]; } - inline void computeViewMatrix(matrix& output, bool isLeftHanded) + // Optional view of a gimbal + inline const std::optional& getView() const { return m_view; } + + inline const size_t& getManipulationCounter() { return m_counter; } + inline bool isManipulating() const { return m_isManipulating; } + + private: + inline void updateOrthonormalOrientationBase() { - const auto&& [xaxis, yaxis, zaxis] = std::make_tuple(getXAxis(), getYAxis(), getZAxis() * (isLeftHanded ? 1.f : -1.f)); - output[0u] = vector(xaxis, -hlsl::dot(xaxis, m_position)); - output[1u] = vector(yaxis, -hlsl::dot(yaxis, m_position)); - output[2u] = vector(zaxis, -hlsl::dot(zaxis, m_position)); + m_orthonormal = matrix(glm::mat3_cast(glm::normalize(m_orientation))); } - private: - inline void updateOrthonormalMatrix() - { - m_orthonormal = float32_t3x3(glm::mat3_cast(glm::normalize(m_orientation))); + inline void updateView() + { + if (m_view.has_value()) // TODO: this could be templated + constexpr actually if gimbal doesn't init this on runtime depending on sth + { + auto& view = m_view.value(); + const auto& gRight = getXAxis(), gUp = getYAxis(), gForward = getZAxis(); - // DEBUG - const auto [xaxis, yaxis, zaxis] = std::make_tuple(getXAxis(),getYAxis(), getZAxis()); + // TODO: I think I will provide convert utility allowing to go from one hand system to another, its just a matter to take care of m_view->matrix[2u] to perform a LH/RH flip + // in general this should not know about projections which are now supposed to be independent and store reference to a camera (or own it) + view.isLeftHandSystem = hlsl::determinant(m_orthonormal) < 0.0f; - auto isNormalized = [](const auto& v, float epsilon) -> bool - { - return glm::epsilonEqual(glm::length(v), 1.0f, epsilon); - }; + auto isNormalized = [](const auto& v, float epsilon) -> bool + { + return glm::epsilonEqual(glm::length(v), 1.0f, epsilon); + }; - auto isOrthogonal = [](const auto& a, const auto& b, float epsilon) -> bool - { - return glm::epsilonEqual(glm::dot(a, b), 0.0f, epsilon); - }; + auto isOrthogonal = [](const auto& a, const auto& b, float epsilon) -> bool + { + return glm::epsilonEqual(glm::dot(a, b), 0.0f, epsilon); + }; - auto isOrthoBase = [&](const auto& x, const auto& y, const auto& z, float epsilon = 1e-6f) -> bool - { - return isNormalized(x, epsilon) && isNormalized(y, epsilon) && isNormalized(z, epsilon) && - isOrthogonal(x, y, epsilon) && isOrthogonal(x, z, epsilon) && isOrthogonal(y, z, epsilon); - }; + auto isOrthoBase = [&](const auto& x, const auto& y, const auto& z, float epsilon = 1e-6f) -> bool + { + return isNormalized(x, epsilon) && isNormalized(y, epsilon) && isNormalized(z, epsilon) && + isOrthogonal(x, y, epsilon) && isOrthogonal(x, z, epsilon) && isOrthogonal(y, z, epsilon); + }; + + assert(isOrthoBase(gRight, gUp, gForward)); - assert(isOrthoBase(xaxis, yaxis, zaxis)); + view.matrix[0u] = vector(gRight, -glm::dot(gRight, m_position)); + view.matrix[1u] = vector(gUp, -glm::dot(gUp, m_position)); + view.matrix[2u] = vector(gForward, -glm::dot(gForward, m_position)); + } } float32_t3 m_position; glm::quat m_orientation; + matrix m_orthonormal; + + // For a camera implementation at least one gimbal models its view but not all gimbals (if multiple) are expected to do so + std::optional m_view = std::nullopt; + + // Counts *performed* manipulations, a manipulation with 0 delta is not counted! + size_t m_counter = {}; - // Represents the camera's orthonormal basis - // https://en.wikipedia.org/wiki/Orthonormal_basis - float32_t3x3 m_orthonormal; + // Records manipulation state + bool m_isManipulating = false; }; ICameraController() {} - // override controller keys map, it binds a key code to a virtual event - void updateKeysToEvent(const std::vector& codes, VirtualEventType event) + // Binds key codes to virtual events, the mapKeys lambda will be executed with controller CVirtualGimbalEvent::keys_to_virtual_events_t table + void updateKeysToEvent(const std::function& mapKeys) { - m_keysToEvent[event] = std::move(codes); + mapKeys(m_keysToVirtualEvents); } - // start controller manipulation session - virtual void begin(std::chrono::microseconds nextPresentationTimeStamp) - { - m_nextPresentationTimeStamp = nextPresentationTimeStamp; - return; - } + // Manipulates camera with view gimbal & virtual events + virtual void manipulate(std::span virtualEvents) = 0; - // manipulate camera with gimbal & virtual events, begin must be called before that! - virtual void manipulate(std::span virtualEvents) = 0; + // TODO: *maybe* would be good to have a class interface for virtual event generators, + // eg keyboard, mouse but maybe custom stuff too eg events from gimbal drag & drop - // finish controller manipulation session, call after last manipulate in the hot loop - void end(std::chrono::microseconds nextPresentationTimeStamp) + // Processes keyboard events to generate virtual manipulation events, note that it doesn't make the manipulation itself! + void processKeyboard(CVirtualGimbalEvent* output, uint32_t& count, std::span events) { - m_lastVirtualUpTimeStamp = nextPresentationTimeStamp; - } + if (!output) + { + count = CVirtualGimbalEvent::EventsCount; + return; + } - /* - // process keyboard to generate virtual manipulation events - // note that: - // - it doesn't make the manipulation itself! - */ - std::vector processKeyboard(std::span events) - { - if (events.empty()) - return {}; + count = 0u; - std::vector output; + if (events.empty()) + return; - constexpr auto NblVirtualKeys = std::to_array({ MoveForward, MoveBackward, MoveLeft, MoveRight, MoveUp, MoveDown, TiltUp, TiltDown, PanLeft, PanRight, RollLeft, RollRight, Reset }); - static_assert(NblVirtualKeys.size() == EventsCount); + const auto timestamp = getEventGenerationTimestamp(); - for (const auto virtualKey : NblVirtualKeys) + for (const auto virtualEventType : CVirtualGimbalEvent::VirtualEventsTypeTable) { - const auto code = m_keysToEvent[virtualKey]; - bool& keyDown = m_keysDown[virtualKey]; + const auto code = m_keysToVirtualEvents[virtualEventType]; + bool& keyDown = m_keysDown[virtualEventType]; using virtual_key_state_t = std::tuple; @@ -224,7 +301,7 @@ class ICameraController : virtual public core::IReferenceCounted else if (ev.action == nbl::ui::SKeyboardEvent::ECA_RELEASED) keyDown = false; - const auto dt = std::chrono::duration_cast(m_nextPresentationTimeStamp - ev.timeStamp).count(); + const auto dt = std::chrono::duration_cast(timestamp - ev.timeStamp).count(); assert(dt >= 0); state = std::make_tuple(code, keyDown, dt); @@ -239,21 +316,34 @@ class ICameraController : virtual public core::IReferenceCounted if (physicalKey != ui::E_KEY_CODE::EKC_NONE) if (isDown) - output.emplace_back(CVirtualEvent{ virtualKey, static_cast(dtAction) }); - } + { + auto* virtualEvent = output + count; + assert(virtualEvent); // TODO: maybe just log error and return 0 count - return output; + virtualEvent->type = virtualEventType; + virtualEvent->magnitude = static_cast(dtAction); + ++count; + } + } } - /* - // [OPTIONAL]: process mouse to generate virtual manipulation events - // note that: - // - all manipulations *may* be done with keyboard keys (if you have a touchpad or sth an ui:: event could be a code!) - // - it doesn't make the manipulation itself! - */ - std::vector processMouse(std::span events) const + // Processes mouse events to generate virtual manipulation events, note that it doesn't make the manipulation itself! + // Limited to Pan & Tilt rotation events, camera type implements how event magnitudes should be interpreted + void processMouse(CVirtualGimbalEvent* output, uint32_t& count, std::span events) { - double dPitch = {}, dYaw = {}; + if (!output) + { + count = 2u; + return; + } + + count = 0u; + + if (events.empty()) + return; + + const auto timestamp = getEventGenerationTimestamp(); + double dYaw = {}, dPitch = {}; for (const auto& ev : events) if (ev.type == nbl::ui::SMouseEvent::EET_MOVEMENT) @@ -262,57 +352,38 @@ class ICameraController : virtual public core::IReferenceCounted dPitch += ev.movementEvent.relativeMovementY; } - std::vector output; - if (dPitch) { - auto& pitch = output.emplace_back(); - pitch.type = dPitch > 0.f ? TiltUp : TiltDown; - pitch.value = std::abs(dPitch); + auto* pitch = output + count; + assert(pitch); // TODO: maybe just log error and return 0 count + pitch->type = dPitch > 0.f ? CVirtualGimbalEvent::TiltUp : CVirtualGimbalEvent::TiltDown; + pitch->magnitude = std::abs(dPitch); + count++; } if (dYaw) { - auto& yaw = output.emplace_back(); - yaw.type = dYaw > 0.f ? PanRight : PanLeft; - yaw.value = std::abs(dYaw); + auto* yaw = output + count; + assert(yaw); // TODO: maybe just log error and return 0 count + yaw->type = dYaw > 0.f ? CVirtualGimbalEvent::PanRight : CVirtualGimbalEvent::PanLeft; + yaw->magnitude = std::abs(dYaw); + count++; } - - return output; } - inline void setMoveSpeed(const float moveSpeed) { m_moveSpeed = moveSpeed; } - inline void setRotateSpeed(const float rotateSpeed) { m_rotateSpeed = rotateSpeed; } - - inline const float getMoveSpeed() const { return m_moveSpeed; } - inline const float getRotateSpeed() const { return m_rotateSpeed; } - protected: - // controller can override default set of event map - virtual void initKeysToEvent() - { - m_keysToEvent[MoveForward] = ui::E_KEY_CODE::EKC_W ; - m_keysToEvent[MoveBackward] = ui::E_KEY_CODE::EKC_S ; - m_keysToEvent[MoveLeft] = ui::E_KEY_CODE::EKC_A ; - m_keysToEvent[MoveRight] = ui::E_KEY_CODE::EKC_D ; - m_keysToEvent[MoveUp] = ui::E_KEY_CODE::EKC_SPACE ; - m_keysToEvent[MoveDown] = ui::E_KEY_CODE::EKC_LEFT_SHIFT ; - m_keysToEvent[TiltUp] = ui::E_KEY_CODE::EKC_NONE ; - m_keysToEvent[TiltDown] = ui::E_KEY_CODE::EKC_NONE ; - m_keysToEvent[PanLeft] = ui::E_KEY_CODE::EKC_NONE ; - m_keysToEvent[PanRight] = ui::E_KEY_CODE::EKC_NONE ; - m_keysToEvent[RollLeft] = ui::E_KEY_CODE::EKC_NONE ; - m_keysToEvent[RollRight] = ui::E_KEY_CODE::EKC_NONE ; - m_keysToEvent[Reset] = ui::E_KEY_CODE::EKC_R ; - } + virtual void initKeysToEvent() = 0; - std::array m_keysToEvent = {}; - float m_moveSpeed = 1.f, m_rotateSpeed = 1.f; - bool m_keysDown[EventsCount] = {}; +private: + CVirtualGimbalEvent::keys_to_virtual_events_t m_keysToVirtualEvents = { { ui::E_KEY_CODE::EKC_NONE } }; + bool m_keysDown[CVirtualGimbalEvent::EventsCount] = {}; - std::chrono::microseconds m_nextPresentationTimeStamp = {}, m_lastVirtualUpTimeStamp = {}; + // exactly what our Nabla events do, actually I don't want users to pass timestamp since I know when it should be best to make a request -> just before generating events! + // TODO: need to think about this + inline std::chrono::microseconds getEventGenerationTimestamp() { return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()); } }; +#if 0 // TOOD: update template concept GimbalRange = GeneralPurposeRange && requires { @@ -337,6 +408,7 @@ class IGimbalRange : public IRange // TODO NOTE: eg. "follow camera" should use GimbalRange::CGimbal, 2u>>, // one per camera itself and one for target it follows +#endif } // nbl::hlsl namespace From 2f44640ec4e823c5d97b427562b291fd0e3eb62f Mon Sep 17 00:00:00 2001 From: AnastaZIuk Date: Sun, 3 Nov 2024 20:11:43 +0100 Subject: [PATCH 32/83] bad typo --- common/include/camera/ICameraControl.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/include/camera/ICameraControl.hpp b/common/include/camera/ICameraControl.hpp index ff918faa4..94e612bf0 100644 --- a/common/include/camera/ICameraControl.hpp +++ b/common/include/camera/ICameraControl.hpp @@ -55,16 +55,16 @@ struct CVirtualGimbalEvent }; using manipulation_encode_t = float64_t; - using keys_to_virtual_events_t = std::array; + using keys_to_virtual_events_t = std::array; VirtualEventType type; manipulation_encode_t magnitude; static inline constexpr auto VirtualEventsTypeTable = []() { - std::array output; + std::array output; - for (uint16_t i = 0u; i < EventsCount - 1u; ++i) + for (uint16_t i = 0u; i < EventsCount; ++i) { output[i] = static_cast(i); } From 1946d5b2dab693c54dd16eaaf93cc77b8de2ddf2 Mon Sep 17 00:00:00 2001 From: Przemog1 Date: Mon, 4 Nov 2024 15:48:04 -0800 Subject: [PATCH 33/83] Refactor --- 61_UI/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/61_UI/main.cpp b/61_UI/main.cpp index 5f54e4efc..63bfddbe3 100644 --- a/61_UI/main.cpp +++ b/61_UI/main.cpp @@ -6,6 +6,7 @@ #include "camera/CCubeProjection.hpp" #include "camera/ICameraControl.hpp" #include "nbl/builtin/hlsl/projection/projection.hlsl" +#include "nbl/builtin/hlsl/camera/view_matrix.hlsl" #include "glm/glm/ext/matrix_clip_space.hpp" // TODO: TESTING // FPS Camera, TESTS From ba9fde50f4c3aec7270221e590ed9c86dd4d8184 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 17 Dec 2024 10:35:44 +0700 Subject: [PATCH 34/83] hlsl bxdf test dir --- 66_HLSLBxDFTests/CMakeLists.txt | 28 +++++++++++++++++++++++ 66_HLSLBxDFTests/app_resources/tests.hlsl | 6 +++++ 66_HLSLBxDFTests/main.cpp | 6 +++++ 3 files changed, 40 insertions(+) create mode 100644 66_HLSLBxDFTests/CMakeLists.txt create mode 100644 66_HLSLBxDFTests/app_resources/tests.hlsl create mode 100644 66_HLSLBxDFTests/main.cpp diff --git a/66_HLSLBxDFTests/CMakeLists.txt b/66_HLSLBxDFTests/CMakeLists.txt new file mode 100644 index 000000000..d26a90205 --- /dev/null +++ b/66_HLSLBxDFTests/CMakeLists.txt @@ -0,0 +1,28 @@ +set(NBL_INCLUDE_SEARCH_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}/include" +) + +include(common RESULT_VARIABLE RES) +if(NOT RES) + message(FATAL_ERROR "common.cmake not found. Should be in {repo_root}/cmake directory") +endif() + +nbl_create_executable_project("" "" "${NBL_INCLUDE_SEARCH_DIRECTORIES}" "" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}") + +if(NBL_EMBED_BUILTIN_RESOURCES) + set(_BR_TARGET_ ${EXECUTABLE_NAME}_builtinResourceData) + set(RESOURCE_DIR "app_resources") + + get_filename_component(_SEARCH_DIRECTORIES_ "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/src" ABSOLUTE) + get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/include" ABSOLUTE) + + file(GLOB_RECURSE BUILTIN_RESOURCE_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}" CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}/*") + foreach(RES_FILE ${BUILTIN_RESOURCE_FILES}) + LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "${RES_FILE}") + endforeach() + + ADD_CUSTOM_BUILTIN_RESOURCES(${_BR_TARGET_} RESOURCES_TO_EMBED "${_SEARCH_DIRECTORIES_}" "${RESOURCE_DIR}" "nbl::this_example::builtin" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}") + + LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} ${_BR_TARGET_}) +endif() \ No newline at end of file diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl new file mode 100644 index 000000000..e4b564717 --- /dev/null +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -0,0 +1,6 @@ +#ifndef BXDFTESTS_TESTS_HLSL +#define BXDFTESTS_TESTS_HLSL + + + +#endif \ No newline at end of file diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp new file mode 100644 index 000000000..7be2ef270 --- /dev/null +++ b/66_HLSLBxDFTests/main.cpp @@ -0,0 +1,6 @@ +#include "app_resources/tests.hlsl" + +int main(int argc, char** argv) +{ + return 0; +} \ No newline at end of file From 4f9dc9f2408890e0d2b10951fe3236054019df7b Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 17 Dec 2024 14:15:09 +0700 Subject: [PATCH 35/83] test bxdf compiles --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 32 +++++++++++++++++++++++ 66_HLSLBxDFTests/main.cpp | 9 +++++++ CMakeLists.txt | 1 + 3 files changed, 42 insertions(+) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index e4b564717..d053c5a6f 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -1,6 +1,38 @@ #ifndef BXDFTESTS_TESTS_HLSL #define BXDFTESTS_TESTS_HLSL +#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#include "nbl/builtin/hlsl/random/xoroshiro.hlsl" +#include "nbl/builtin/hlsl/bxdf/common.hlsl" +#include "nbl/builtin/hlsl/bxdf/reflection.hlsl" + +using namespace nbl; +using namespace hlsl; + +using ray_dir_info_t = ray_dir_info::SBasic; +using iso_interaction = surface_interactions::SIsotropic; +using aniso_interaction = surface_interactions::SAnisotropic; +using sample_t = SLightSample; +using quotient_pdf_t = quotient_and_pdf; + +float32_t3 testLambertianBRDF() +{ + ray_dir_info_t V; + V.direction = float32_t3(0.3, 0.4, 0.5); + float32_t3 N = float32_t3(0, 1, 0); + iso_interaction isointer = iso_interaction::create(V, N); + aniso_interaction anisointer = aniso_interaction::create(isointer, float32_t3(0, 0, 1), float32_t3(1, 0, 0)); + sample_t s; + + reflection::SLambertianBxDF lambertian = reflection::SLambertianBxDF::create(); + s = lambertian.generate(anisointer, float32_t2(0.5, 0.0)); + quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); + float32_t3 brdf = float32_t3(lambertian.eval(s, isointer)); + + // get jacobian + + return abs(pdf.value() - brdf); +} #endif \ No newline at end of file diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 7be2ef270..750c59f65 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -1,6 +1,15 @@ +#include +#include + #include "app_resources/tests.hlsl" int main(int argc, char** argv) { + float32_t3 result = testLambertianBRDF(); + + std::cout << result.x << " " + << result.y << " " + << result.z << "\n"; + return 0; } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index a467a8598..daea78e63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,7 @@ if(NBL_BUILD_EXAMPLES) add_subdirectory(62_SchusslerTest EXCLUDE_FROM_ALL) add_subdirectory(0_ImportanceSamplingEnvMaps EXCLUDE_FROM_ALL) #TODO: integrate back into 42 + add_subdirectory(66_HLSLBxDFTests EXCLUDE_FROM_ALL) add_subdirectory(67_RayQueryGeometry EXCLUDE_FROM_ALL) From 209170119c3fb89ee4fe05642b28f904deb75c0f Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 17 Dec 2024 15:01:40 +0700 Subject: [PATCH 36/83] minor namespace changes --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 11 ++++++++--- 66_HLSLBxDFTests/main.cpp | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index d053c5a6f..36d3113b4 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -7,8 +7,10 @@ #include "nbl/builtin/hlsl/bxdf/common.hlsl" #include "nbl/builtin/hlsl/bxdf/reflection.hlsl" -using namespace nbl; -using namespace hlsl; +namespace nbl +{ +namespace hlsl +{ using ray_dir_info_t = ray_dir_info::SBasic; using iso_interaction = surface_interactions::SIsotropic; @@ -16,7 +18,7 @@ using aniso_interaction = surface_interactions::SAnisotropic; using sample_t = SLightSample; using quotient_pdf_t = quotient_and_pdf; -float32_t3 testLambertianBRDF() +inline float32_t3 testLambertianBRDF() { ray_dir_info_t V; V.direction = float32_t3(0.3, 0.4, 0.5); @@ -35,4 +37,7 @@ float32_t3 testLambertianBRDF() return abs(pdf.value() - brdf); } +} +} + #endif \ No newline at end of file diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 750c59f65..e623a21ab 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -1,11 +1,13 @@ #include #include +#include + #include "app_resources/tests.hlsl" int main(int argc, char** argv) { - float32_t3 result = testLambertianBRDF(); + float32_t3 result = nbl::hlsl::testLambertianBRDF(); std::cout << result.x << " " << result.y << " " From 385bcec481b76cf3dc0a904f96adaa886a59ed8f Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 19 Dec 2024 09:09:14 +0700 Subject: [PATCH 37/83] added bsdf test --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 36 ++++++++++++++++++----- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 36d3113b4..2519b259b 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -6,17 +6,20 @@ #include "nbl/builtin/hlsl/random/xoroshiro.hlsl" #include "nbl/builtin/hlsl/bxdf/common.hlsl" #include "nbl/builtin/hlsl/bxdf/reflection.hlsl" +#include "nbl/builtin/hlsl/bxdf/transmission.hlsl" namespace nbl { namespace hlsl { -using ray_dir_info_t = ray_dir_info::SBasic; -using iso_interaction = surface_interactions::SIsotropic; -using aniso_interaction = surface_interactions::SAnisotropic; -using sample_t = SLightSample; -using quotient_pdf_t = quotient_and_pdf; +using ray_dir_info_t = bxdf::ray_dir_info::SBasic; +using iso_interaction = bxdf::surface_interactions::SIsotropic; +using aniso_interaction = bxdf::surface_interactions::SAnisotropic; +using sample_t = bxdf::SLightSample; +using iso_cache = bxdf::SIsotropicMicrofacetCache; +using aniso_cache = bxdf::SAnisotropicMicrofacetCache; +using quotient_pdf_t = bxdf::quotient_and_pdf; inline float32_t3 testLambertianBRDF() { @@ -27,14 +30,33 @@ inline float32_t3 testLambertianBRDF() aniso_interaction anisointer = aniso_interaction::create(isointer, float32_t3(0, 0, 1), float32_t3(1, 0, 0)); sample_t s; - reflection::SLambertianBxDF lambertian = reflection::SLambertianBxDF::create(); + bxdf::reflection::SLambertianBxDF lambertian = bxdf::reflection::SLambertianBxDF::create(); s = lambertian.generate(anisointer, float32_t2(0.5, 0.0)); quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); float32_t3 brdf = float32_t3(lambertian.eval(s, isointer)); // get jacobian - return abs(pdf.value() - brdf); + return abs(pdf.value() - brdf); +} + +inline float32_t3 testLambertianBSDF() +{ + ray_dir_info_t V; + V.direction = float32_t3(0.3, 0.4, 0.5); + float32_t3 N = float32_t3(0, 1, 0); + iso_interaction isointer = iso_interaction::create(V, N); + aniso_interaction anisointer = aniso_interaction::create(isointer, float32_t3(0, 0, 1), float32_t3(1, 0, 0)); + sample_t s; + + bxdf::transmission::SLambertianBxDF lambertian = bxdf::transmission::SLambertianBxDF::create(); + s = lambertian.generate(anisointer, float32_t2(0.5, 0.0)); + quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); + float32_t3 bsdf = float32_t3(lambertian.eval(s, isointer)); + + // get jacobian + + return abs(pdf.value() - bsdf); } } From 9212b655e1bae175913f6b59b8af07b6bb307783 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 20 Dec 2024 11:38:34 +0700 Subject: [PATCH 38/83] fix namespace --- 66_HLSLBxDFTests/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index e623a21ab..232921ec8 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -3,11 +3,13 @@ #include +using namespace nbl::hlsl; + #include "app_resources/tests.hlsl" int main(int argc, char** argv) { - float32_t3 result = nbl::hlsl::testLambertianBRDF(); + float32_t3 result = testLambertianBRDF(); std::cout << result.x << " " << result.y << " " From 32f959d5f98d63e402dbbf2f65366078b67c77cc Mon Sep 17 00:00:00 2001 From: Przemek Date: Fri, 20 Dec 2024 17:05:47 +0100 Subject: [PATCH 39/83] Example 62 fix --- 62_CAD/Hatch.cpp | 2 +- 62_CAD/main.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/62_CAD/Hatch.cpp b/62_CAD/Hatch.cpp index 5c347026e..88de745f8 100644 --- a/62_CAD/Hatch.cpp +++ b/62_CAD/Hatch.cpp @@ -16,7 +16,7 @@ bool Hatch::Segment::isStraightLineConstantMajor() const p1 = originalBezier->P1[major], p2 = originalBezier->P2[major]; //assert(p0 <= p1 && p1 <= p2); (PRECISION ISSUES ARISE ONCE MORE) - return abs(p1 - p0) <= core::exp2(-24.0) && abs(p2 - p0) <= exp(-24); + return abs(p1 - p0) <= core::exp2(-24.0) && abs(p2 - p0) <= hlsl::exp(-24); } std::array Hatch::Segment::intersect(const Segment& other) const diff --git a/62_CAD/main.cpp b/62_CAD/main.cpp index 635001380..475ca5084 100644 --- a/62_CAD/main.cpp +++ b/62_CAD/main.cpp @@ -31,6 +31,8 @@ using namespace video; #include "HatchGlyphBuilder.h" #include "GeoTexture.h" +#include + #include #define BENCHMARK_TILL_FIRST_FRAME @@ -637,6 +639,9 @@ class ComputerAidedDesign final : public examples::SimpleWindowedApplication, pu inline bool onAppInitialized(smart_refctd_ptr&& system) override { + int a = -1; + abs(a); + m_inputSystem = make_smart_refctd_ptr(logger_opt_smart_ptr(smart_refctd_ptr(m_logger))); // Remember to call the base class initialization! From 70b28d826394e5132895f6cbbf95681a7ceb8a2e Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 23 Dec 2024 17:03:56 +0700 Subject: [PATCH 40/83] working? test --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 27 +++++++++++++++-------- 66_HLSLBxDFTests/main.cpp | 12 ++++++++-- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 2519b259b..c368ea577 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -21,26 +21,35 @@ using iso_cache = bxdf::SIsotropicMicrofacetCache; using aniso_cache = bxdf::SAnisotropicMicrofacetCache; using quotient_pdf_t = bxdf::quotient_and_pdf; -inline float32_t3 testLambertianBRDF() +inline float32_t4 testLambertianBRDF() { + const uint32_t2 state = uint32_t2(10u, 42u); + nbl::hlsl::Xoroshiro64Star rng = nbl::hlsl::Xoroshiro64Star::construct(state); + NBL_CONSTEXPR float h = 0.001; + float32_t2 u = float32_t2(rng(), rng()); + ray_dir_info_t V; - V.direction = float32_t3(0.3, 0.4, 0.5); + V.direction = glm::normalize(float32_t3(rng(), rng(), rng())); // TODO: use cpp compat version float32_t3 N = float32_t3(0, 1, 0); iso_interaction isointer = iso_interaction::create(V, N); - aniso_interaction anisointer = aniso_interaction::create(isointer, float32_t3(0, 0, 1), float32_t3(1, 0, 0)); - sample_t s; + aniso_interaction anisointer = aniso_interaction::create(isointer, float32_t3(0, 0, 1), float32_t3(1, 0, 0)); // TODO: random T and cross B + sample_t s, sx, sy; bxdf::reflection::SLambertianBxDF lambertian = bxdf::reflection::SLambertianBxDF::create(); - s = lambertian.generate(anisointer, float32_t2(0.5, 0.0)); + s = lambertian.generate(anisointer, u); + sx = lambertian.generate(anisointer, u + float32_t2(h,0)); + sy = lambertian.generate(anisointer, u + float32_t2(0,h)); quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); float32_t3 brdf = float32_t3(lambertian.eval(s, isointer)); // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); - return abs(pdf.value() - brdf); + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } -inline float32_t3 testLambertianBSDF() +inline float32_t4 testLambertianBSDF() { ray_dir_info_t V; V.direction = float32_t3(0.3, 0.4, 0.5); @@ -50,13 +59,13 @@ inline float32_t3 testLambertianBSDF() sample_t s; bxdf::transmission::SLambertianBxDF lambertian = bxdf::transmission::SLambertianBxDF::create(); - s = lambertian.generate(anisointer, float32_t2(0.5, 0.0)); + s = lambertian.generate(anisointer, float32_t3(0.5, 0.5, 0.0)); quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); float32_t3 bsdf = float32_t3(lambertian.eval(s, isointer)); // get jacobian - return abs(pdf.value() - bsdf); + return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), 0); } } diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 232921ec8..ce7784209 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -9,11 +9,19 @@ using namespace nbl::hlsl; int main(int argc, char** argv) { - float32_t3 result = testLambertianBRDF(); + float32_t4 result = testLambertianBRDF(); std::cout << result.x << " " << result.y << " " - << result.z << "\n"; + << result.z << " " + << result.w << "\n"; + + result = testLambertianBSDF(); + + std::cout << result.x << " " + << result.y << " " + << result.z << " " + << result.w << "\n"; return 0; } \ No newline at end of file From f17709052443c5522ef50956ae391a3b1009fb1c Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 25 Dec 2024 11:33:47 +0700 Subject: [PATCH 41/83] rng test util struct --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 113 ++++++++++++++++++---- 66_HLSLBxDFTests/main.cpp | 24 +++-- 2 files changed, 107 insertions(+), 30 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index c368ea577..584acc948 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -21,24 +21,67 @@ using iso_cache = bxdf::SIsotropicMicrofacetCache; using aniso_cache = bxdf::SAnisotropicMicrofacetCache; using quotient_pdf_t = bxdf::quotient_and_pdf; +inline float rngFloat01(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) +{ + return (float)rng() / numeric_limits::max; +} + +inline float32_t3 rngFloat301(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) +{ + return float32_t3(rngFloat01(rng), rngFloat01(rng), rngFloat01(rng)); +} + + +struct SBxDFTestResources +{ + static SBxDFTestResources create(uint32_t2 seed) + { + SBxDFTestResources retval; + + retval.rng = nbl::hlsl::Xoroshiro64Star::construct(seed); + retval.u = float32_t3(rngFloat01(retval.rng), rngFloat01(retval.rng), 0.0); + + retval.V.direction = nbl::hlsl::normalize(rngFloat301(retval.rng)); + retval.N = nbl::hlsl::normalize(rngFloat301(retval.rng)); + retval.T = nbl::hlsl::normalize(rngFloat301(retval.rng)); + + retval.T = nbl::hlsl::normalize(retval.T - nbl::hlsl::dot(retval.T, retval.N) * retval.N); // gram schmidt + retval.B = nbl::hlsl::cross(retval.N, retval.T); + + retval.alpha.x = rngFloat01(retval.rng); + retval.alpha.y = rngFloat01(retval.rng); + retval.ior = float32_t3x2(1.02, 1.0, // randomize at some point? + 1.3, 2.0, + 1.02, 1.0); + return retval; + } + + float h = 0.001; + + nbl::hlsl::Xoroshiro64Star rng; + ray_dir_info_t V; + float32_t3 N; + float32_t3 T; + float32_t3 B; + + float32_t3 u; + float32_t2 alpha; + float32_t3x2 ior; +}; + inline float32_t4 testLambertianBRDF() { const uint32_t2 state = uint32_t2(10u, 42u); - nbl::hlsl::Xoroshiro64Star rng = nbl::hlsl::Xoroshiro64Star::construct(state); - NBL_CONSTEXPR float h = 0.001; - float32_t2 u = float32_t2(rng(), rng()); + SBxDFTestResources rc = SBxDFTestResources::create(state); - ray_dir_info_t V; - V.direction = glm::normalize(float32_t3(rng(), rng(), rng())); // TODO: use cpp compat version - float32_t3 N = float32_t3(0, 1, 0); - iso_interaction isointer = iso_interaction::create(V, N); - aniso_interaction anisointer = aniso_interaction::create(isointer, float32_t3(0, 0, 1), float32_t3(1, 0, 0)); // TODO: random T and cross B + iso_interaction isointer = iso_interaction::create(rc.V, rc.N); + aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + sample_t s, sx, sy; - bxdf::reflection::SLambertianBxDF lambertian = bxdf::reflection::SLambertianBxDF::create(); - s = lambertian.generate(anisointer, u); - sx = lambertian.generate(anisointer, u + float32_t2(h,0)); - sy = lambertian.generate(anisointer, u + float32_t2(0,h)); + s = lambertian.generate(anisointer, rc.u.xy); + sx = lambertian.generate(anisointer, rc.u.xy + float32_t2(rc.h,0)); + sy = lambertian.generate(anisointer, rc.u.xy + float32_t2(0,rc.h)); quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); float32_t3 brdf = float32_t3(lambertian.eval(s, isointer)); @@ -49,23 +92,51 @@ inline float32_t4 testLambertianBRDF() return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } +inline float32_t4 testBeckmannBRDF() +{ + const uint32_t2 state = uint32_t2(10u, 42u); + SBxDFTestResources rc = SBxDFTestResources::create(state); + + iso_interaction isointer = iso_interaction::create(rc.V, rc.N); + aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + aniso_cache cache; + + sample_t s, sx, sy; + bxdf::reflection::SBeckmannBxDF beckmann = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); + s = beckmann.generate(anisointer, rc.u.xy, cache); + sx = beckmann.generate(anisointer, rc.u.xy + float32_t2(rc.h,0), cache); + sy = beckmann.generate(anisointer, rc.u.xy + float32_t2(0,rc.h), cache); + quotient_pdf_t pdf = beckmann.quotient_and_pdf(s, anisointer, cache); + float32_t3 brdf = float32_t3(beckmann.eval(s, anisointer, cache)); + + // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); +} + inline float32_t4 testLambertianBSDF() { - ray_dir_info_t V; - V.direction = float32_t3(0.3, 0.4, 0.5); - float32_t3 N = float32_t3(0, 1, 0); - iso_interaction isointer = iso_interaction::create(V, N); - aniso_interaction anisointer = aniso_interaction::create(isointer, float32_t3(0, 0, 1), float32_t3(1, 0, 0)); - sample_t s; + const uint32_t2 state = uint32_t2(12u, 69u); + SBxDFTestResources rc = SBxDFTestResources::create(state); + iso_interaction isointer = iso_interaction::create(rc.V, rc.N); + aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + + sample_t s, sx, sy; bxdf::transmission::SLambertianBxDF lambertian = bxdf::transmission::SLambertianBxDF::create(); - s = lambertian.generate(anisointer, float32_t3(0.5, 0.5, 0.0)); + s = lambertian.generate(anisointer, rc.u); + sx = lambertian.generate(anisointer, rc.u + float32_t3(rc.h,0,0)); + sy = lambertian.generate(anisointer, rc.u + float32_t3(0,rc.h,0)); quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); - float32_t3 bsdf = float32_t3(lambertian.eval(s, isointer)); + float32_t3 brdf = float32_t3(lambertian.eval(s, isointer)); // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); - return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), 0); + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } } diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index ce7784209..e46d92e5d 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include @@ -7,21 +8,26 @@ using namespace nbl::hlsl; #include "app_resources/tests.hlsl" +void printFloat4(const float32_t4& result) +{ + std::cout << result.x << " " + << result.y << " " + << result.z << " " + << result.w << "\n"; +} + int main(int argc, char** argv) { + std::cout << std::fixed << std::setprecision(4); + float32_t4 result = testLambertianBRDF(); + printFloat4(result); - std::cout << result.x << " " - << result.y << " " - << result.z << " " - << result.w << "\n"; + result = testBeckmannBRDF(); + printFloat4(result); result = testLambertianBSDF(); - - std::cout << result.x << " " - << result.y << " " - << result.z << " " - << result.w << "\n"; + printFloat4(result); return 0; } \ No newline at end of file From 382c862cd2a491285cb374281c4685789fa3ab89 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 25 Dec 2024 15:44:04 +0700 Subject: [PATCH 42/83] beckmann dielectric test --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 33 +++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 584acc948..160399710 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -50,9 +50,10 @@ struct SBxDFTestResources retval.alpha.x = rngFloat01(retval.rng); retval.alpha.y = rngFloat01(retval.rng); + retval.eta = rngFloat01(retval.rng) + 1.0; retval.ior = float32_t3x2(1.02, 1.0, // randomize at some point? - 1.3, 2.0, - 1.02, 1.0); + 1.3, 2.0, + 1.02, 1.0); return retval; } @@ -66,6 +67,8 @@ struct SBxDFTestResources float32_t3 u; float32_t2 alpha; + float eta; + float eta2; // what is this? float32_t3x2 ior; }; @@ -139,6 +142,32 @@ inline float32_t4 testLambertianBSDF() return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } +inline float32_t4 testBeckmannBSDF() +{ + const uint32_t2 state = uint32_t2(12u, 69u); + SBxDFTestResources rc = SBxDFTestResources::create(state); + + iso_interaction isointer = iso_interaction::create(rc.V, rc.N); + aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + aniso_cache cache; + + sample_t s, sx, sy; + bxdf::transmission::SBeckmannDielectricBxDF beckmann = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); + s = beckmann.generate(anisointer, rc.u, cache); + float32_t3 ux = rc.u + float32_t3(rc.h,0,0); + sx = beckmann.generate(anisointer, ux, cache); + float32_t3 uy = rc.u + float32_t3(0,rc.h,0); + sy = beckmann.generate(anisointer, uy, cache); + quotient_pdf_t pdf = beckmann.quotient_and_pdf(s, anisointer, cache); + float32_t3 brdf = float32_t3(beckmann.eval(s, anisointer, cache)); + + // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); +} + } } From e0bde553745a72d092d497ed9749510d1a21abe0 Mon Sep 17 00:00:00 2001 From: Przemek Date: Sat, 28 Dec 2024 17:04:54 +0100 Subject: [PATCH 43/83] Updated examples --- 62_CAD/Hatch.cpp | 2 +- 62_CAD/main.cpp | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/62_CAD/Hatch.cpp b/62_CAD/Hatch.cpp index 88de745f8..da7728cf2 100644 --- a/62_CAD/Hatch.cpp +++ b/62_CAD/Hatch.cpp @@ -16,7 +16,7 @@ bool Hatch::Segment::isStraightLineConstantMajor() const p1 = originalBezier->P1[major], p2 = originalBezier->P2[major]; //assert(p0 <= p1 && p1 <= p2); (PRECISION ISSUES ARISE ONCE MORE) - return abs(p1 - p0) <= core::exp2(-24.0) && abs(p2 - p0) <= hlsl::exp(-24); + return abs(p1 - p0) <= core::exp2(-24.0) && abs(p2 - p0) <= hlsl::exp(-24.0f); } std::array Hatch::Segment::intersect(const Segment& other) const diff --git a/62_CAD/main.cpp b/62_CAD/main.cpp index 475ca5084..a61205e88 100644 --- a/62_CAD/main.cpp +++ b/62_CAD/main.cpp @@ -639,9 +639,6 @@ class ComputerAidedDesign final : public examples::SimpleWindowedApplication, pu inline bool onAppInitialized(smart_refctd_ptr&& system) override { - int a = -1; - abs(a); - m_inputSystem = make_smart_refctd_ptr(logger_opt_smart_ptr(smart_refctd_ptr(m_logger))); // Remember to call the base class initialization! From 677323b85e9a132ebe00ef2471a8c45ce6bbdb95 Mon Sep 17 00:00:00 2001 From: Przemek Date: Mon, 30 Dec 2024 13:25:28 +0100 Subject: [PATCH 44/83] Fixes --- 62_CAD/main.cpp | 2 +- 62_CAD/shaders/globals.hlsl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/62_CAD/main.cpp b/62_CAD/main.cpp index 82eae90bb..9f052b180 100644 --- a/62_CAD/main.cpp +++ b/62_CAD/main.cpp @@ -68,7 +68,7 @@ constexpr std::array cameraExtents = 600.0, // CASE_8 }; -constexpr ExampleMode mode = ExampleMode::CASE_5; +constexpr ExampleMode mode = ExampleMode::CASE_4; class Camera2D { diff --git a/62_CAD/shaders/globals.hlsl b/62_CAD/shaders/globals.hlsl index af5d36f02..94a24ff06 100644 --- a/62_CAD/shaders/globals.hlsl +++ b/62_CAD/shaders/globals.hlsl @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef __HLSL_VERSION #include From 9de6ae862d082d892e911808fd473647d0c65c0f Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 3 Jan 2025 15:23:21 +0700 Subject: [PATCH 45/83] fix syntax --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 16 ++++++++-------- 66_HLSLBxDFTests/main.cpp | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 160399710..33737cd05 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -90,7 +90,7 @@ inline float32_t4 testLambertianBRDF() // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); + float det = nbl::hlsl::determinant(m); return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } @@ -114,7 +114,7 @@ inline float32_t4 testBeckmannBRDF() // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); + float det = nbl::hlsl::determinant(m); return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } @@ -133,13 +133,13 @@ inline float32_t4 testLambertianBSDF() sx = lambertian.generate(anisointer, rc.u + float32_t3(rc.h,0,0)); sy = lambertian.generate(anisointer, rc.u + float32_t3(0,rc.h,0)); quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); - float32_t3 brdf = float32_t3(lambertian.eval(s, isointer)); + float32_t3 bsdf = float32_t3(lambertian.eval(s, isointer)); // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); + float det = nbl::hlsl::determinant(m); - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } inline float32_t4 testBeckmannBSDF() @@ -159,13 +159,13 @@ inline float32_t4 testBeckmannBSDF() float32_t3 uy = rc.u + float32_t3(0,rc.h,0); sy = beckmann.generate(anisointer, uy, cache); quotient_pdf_t pdf = beckmann.quotient_and_pdf(s, anisointer, cache); - float32_t3 brdf = float32_t3(beckmann.eval(s, anisointer, cache)); + float32_t3 bsdf = float32_t3(beckmann.eval(s, anisointer, cache)); // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); + float det = nbl::hlsl::determinant(m); - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } } diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index e46d92e5d..42f40601d 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -29,5 +29,8 @@ int main(int argc, char** argv) result = testLambertianBSDF(); printFloat4(result); + result = testBeckmannBSDF(); + printFloat4(result); + return 0; } \ No newline at end of file From 6dbc89ac557a0531ca390183e4b251910cc54347 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 6 Jan 2025 11:15:12 +0700 Subject: [PATCH 46/83] more tests (all brdfs) and utils --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 135 ++++++++++++++++++++++ 66_HLSLBxDFTests/main.cpp | 29 ++++- 2 files changed, 161 insertions(+), 3 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 33737cd05..40d56c9e0 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -57,6 +57,15 @@ struct SBxDFTestResources return retval; } + ray_dir_info_t dV(int axis) + { + float32_t3 d = (float32_t3)0.0; + d[axis] += h; + ray_dir_info_t retval; + retval.direction = V.direction + d; + return retval; + } + float h = 0.001; nbl::hlsl::Xoroshiro64Star rng; @@ -95,6 +104,84 @@ inline float32_t4 testLambertianBRDF() return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } +inline float32_t4 testLambertianBRDF2() +{ + const uint32_t2 state = uint32_t2(10u, 42u); + SBxDFTestResources rc = SBxDFTestResources::create(state); + + iso_interaction isointer = iso_interaction::create(rc.V, rc.N); + aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + + iso_interaction isointerx = iso_interaction::create(rc.dV(0), rc.N); + aniso_interaction anisointerx = aniso_interaction::create(isointerx, rc.T, rc.B); + iso_interaction isointery = iso_interaction::create(rc.dV(1), rc.N); + aniso_interaction anisointery = aniso_interaction::create(isointery, rc.T, rc.B); + iso_interaction isointerz = iso_interaction::create(rc.dV(2), rc.N); + aniso_interaction anisointerz = aniso_interaction::create(isointerz, rc.T, rc.B); + + sample_t s, sx, sy, sz; + bxdf::reflection::SLambertianBxDF lambertian = bxdf::reflection::SLambertianBxDF::create(); + s = lambertian.generate(anisointer, rc.u.xy); + sx = lambertian.generate(anisointerx, rc.u.xy); + sy = lambertian.generate(anisointery, rc.u.xy); + sz = lambertian.generate(anisointerz, rc.u.xy); + quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); + float32_t3 brdf = float32_t3(lambertian.eval(s, isointer)); + + // get jacobian + float32_t3x3 m = float32_t3x3(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL, sz.BdotL - s.BdotL, sx.NdotL - s.NdotL, sy.NdotL - s.NdotL, sz.NdotL - s.NdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); +} + +inline float32_t4 testOrenNayarBRDF() +{ + const uint32_t2 state = uint32_t2(10u, 42u); + SBxDFTestResources rc = SBxDFTestResources::create(state); + + iso_interaction isointer = iso_interaction::create(rc.V, rc.N); + aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + + sample_t s, sx, sy; + bxdf::reflection::SOrenNayarBxDF orennayar = bxdf::reflection::SOrenNayarBxDF::create(rc.alpha.x); + s = orennayar.generate(anisointer, rc.u.xy); + sx = orennayar.generate(anisointer, rc.u.xy + float32_t2(rc.h,0)); + sy = orennayar.generate(anisointer, rc.u.xy + float32_t2(0,rc.h)); + quotient_pdf_t pdf = orennayar.quotient_and_pdf(s, isointer); + float32_t3 brdf = float32_t3(orennayar.eval(s, isointer)); + + // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); +} + +// inline float32_t4 testBlinnPhongBRDF() +// { +// const uint32_t2 state = uint32_t2(10u, 42u); +// SBxDFTestResources rc = SBxDFTestResources::create(state); + +// iso_interaction isointer = iso_interaction::create(rc.V, rc.N); +// aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); +// aniso_cache cache; + +// sample_t s, sx, sy; +// bxdf::reflection::SBlinnPhongBxDF blinnphong = bxdf::reflection::SBlinnPhongBxDF::create(rc.alpha,rc.ior); +// s = blinnphong.generate(anisointer, rc.u.xy, cache); +// sx = blinnphong.generate(anisointer, rc.u.xy + float32_t2(rc.h,0), cache); +// sy = blinnphong.generate(anisointer, rc.u.xy + float32_t2(0,rc.h), cache); +// quotient_pdf_t pdf = blinnphong.quotient_and_pdf(s, anisointer, cache); +// float32_t3 brdf = float32_t3(blinnphong.eval(s, anisointer, cache)); + +// // get jacobian +// float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); +// float det = nbl::hlsl::determinant(m); + +// return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); +// } + inline float32_t4 testBeckmannBRDF() { const uint32_t2 state = uint32_t2(10u, 42u); @@ -119,6 +206,54 @@ inline float32_t4 testBeckmannBRDF() return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } +inline float32_t4 testGGXBRDF() // iso ggx +{ + const uint32_t2 state = uint32_t2(10u, 42u); + SBxDFTestResources rc = SBxDFTestResources::create(state); + + iso_interaction isointer = iso_interaction::create(rc.V, rc.N); + aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + aniso_cache cache; + + sample_t s, sx, sy; + bxdf::reflection::SGGXBxDF ggx = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.ior); + s = ggx.generate(anisointer, rc.u.xy, cache); + sx = ggx.generate(anisointer, rc.u.xy + float32_t2(rc.h,0), cache); + sy = ggx.generate(anisointer, rc.u.xy + float32_t2(0,rc.h), cache); + quotient_pdf_t pdf = ggx.quotient_and_pdf(s, anisointer, cache); + float32_t3 brdf = float32_t3(ggx.eval(s, anisointer, cache)); + + // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); +} + +inline float32_t4 testGGXAnisoBRDF() // aniso ggx +{ + const uint32_t2 state = uint32_t2(10u, 42u); + SBxDFTestResources rc = SBxDFTestResources::create(state); + + iso_interaction isointer = iso_interaction::create(rc.V, rc.N); + aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + aniso_cache cache; + + sample_t s, sx, sy; + bxdf::reflection::SGGXBxDF ggx = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); + s = ggx.generate(anisointer, rc.u.xy, cache); + sx = ggx.generate(anisointer, rc.u.xy + float32_t2(rc.h,0), cache); + sy = ggx.generate(anisointer, rc.u.xy + float32_t2(0,rc.h), cache); + quotient_pdf_t pdf = ggx.quotient_and_pdf(s, anisointer, cache); + float32_t3 brdf = float32_t3(ggx.eval(s, anisointer, cache)); + + // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); +} + inline float32_t4 testLambertianBSDF() { const uint32_t2 state = uint32_t2(12u, 69u); diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 42f40601d..1dfa10253 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -8,6 +8,8 @@ using namespace nbl::hlsl; #include "app_resources/tests.hlsl" +#define ASSERT_ZERO(x) assert(all(x < float32_t4(1e-4))); + void printFloat4(const float32_t4& result) { std::cout << result.x << " " @@ -20,17 +22,38 @@ int main(int argc, char** argv) { std::cout << std::fixed << std::setprecision(4); + using bool32_t4 = vector; + + // brdfs + // diffuse float32_t4 result = testLambertianBRDF(); - printFloat4(result); + ASSERT_ZERO(result); + + result = testLambertianBRDF2(); + assert(all(result < float32_t4(1e-4))); + + result = testOrenNayarBRDF(); + assert(all(result < float32_t4(1e-4))); + + // specular + //result = testBlinnPhongBRDF(); + //printFloat4(result); result = testBeckmannBRDF(); + assert(all(result < float32_t4(1e-4))); + + result = testGGXBRDF(); printFloat4(result); - result = testLambertianBSDF(); + result = testGGXAnisoBRDF(); printFloat4(result); + // bxdfs + result = testLambertianBSDF(); + assert(all(result < float32_t4(1e-4))); + result = testBeckmannBSDF(); - printFloat4(result); + assert(all(result < float32_t4(1e-4))); return 0; } \ No newline at end of file From 9c379eb435c9e77921dc2b599767ac28d6e66bf6 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 7 Jan 2025 14:55:09 +0700 Subject: [PATCH 47/83] template tests --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 273 +++++++++++++++------- 66_HLSLBxDFTests/main.cpp | 38 +-- 2 files changed, 215 insertions(+), 96 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 40d56c9e0..ee156426a 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -81,28 +81,150 @@ struct SBxDFTestResources float32_t3x2 ior; }; -inline float32_t4 testLambertianBRDF() +template +struct TestBase { - const uint32_t2 state = uint32_t2(10u, 42u); - SBxDFTestResources rc = SBxDFTestResources::create(state); + void init(uint32_t2 seed) + { + rc = SBxDFTestResources::create(seed); - iso_interaction isointer = iso_interaction::create(rc.V, rc.N); - aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); - - sample_t s, sx, sy; - bxdf::reflection::SLambertianBxDF lambertian = bxdf::reflection::SLambertianBxDF::create(); - s = lambertian.generate(anisointer, rc.u.xy); - sx = lambertian.generate(anisointer, rc.u.xy + float32_t2(rc.h,0)); - sy = lambertian.generate(anisointer, rc.u.xy + float32_t2(0,rc.h)); - quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); - float32_t3 brdf = float32_t3(lambertian.eval(s, isointer)); + isointer = iso_interaction::create(rc.V, rc.N); + anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + } - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); + SBxDFTestResources rc; + BxDF bxdf; - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); -} + iso_interaction isointer; + aniso_interaction anisointer; +}; + +template +struct TestBRDF : TestBase +{ + using base_t = TestBase; + + void initBxDF(SBxDFTestResources _rc) + { + base_t::bxdf = BxDF::create(); // default to lambertian brdf + } +}; + +template<> +struct TestBRDF> : TestBase> +{ + using base_t = TestBase>; + + void initBxDF(SBxDFTestResources _rc) + { + base_t::bxdf = bxdf::reflection::SOrenNayarBxDF::create(_rc.alpha.x); + } +}; + +template<> +struct TestBRDF> : TestBase> +{ + using base_t = TestBase>; + + template + void initBxDF(SBxDFTestResources _rc) + { + if (aniso) + base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); + else + base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,rc.ior); + } +}; + +template<> +struct TestBRDF> : TestBase> +{ + using base_t = TestBase>; + + template + void initBxDF(SBxDFTestResources _rc) + { + if (aniso) + base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); + else + base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.ior); + } +}; + +template +struct TestUOffsetBasicBRDF : TestBRDF +{ + using base_t = TestBase; + using test_t = TestBRDF; + using this_t = TestUOffsetBasicBRDF; + + float32_t4 test() + { + sample_t s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy); + sample_t sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(base_t::rc.h,0)); + sample_t sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(0,base_t::rc.h)); + quotient_pdf_t pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); + float32_t3 brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); + + // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + } + + static float32_t4 run(uint32_t2 seed) + { + this_t t; + t.init(seed); + t.initBxDF(t.rc); + return t.test(); + } +}; + +template +struct TestUOffsetMicrofacetBRDF : TestBRDF +{ + using base_t = TestBase; + using test_t = TestBRDF; + using this_t = TestUOffsetMicrofacetBRDF; + + float32_t4 test() + { + aniso_cache cache, dummy; + + sample_t s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy, cache); + sample_t sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(base_t::rc.h,0), dummy); + sample_t sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(0,base_t::rc.h), dummy); + quotient_pdf_t pdf; + float32_t3 brdf; + if (aniso) + { + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); + } + else + { + iso_cache isocache = (iso_cache)cache; + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); + } + + // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + } + + static float32_t4 run(uint32_t2 seed) + { + this_t t; + t.init(seed); + t.template initBxDF(t.rc); + return t.test(); + } +}; inline float32_t4 testLambertianBRDF2() { @@ -135,29 +257,6 @@ inline float32_t4 testLambertianBRDF2() return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } -inline float32_t4 testOrenNayarBRDF() -{ - const uint32_t2 state = uint32_t2(10u, 42u); - SBxDFTestResources rc = SBxDFTestResources::create(state); - - iso_interaction isointer = iso_interaction::create(rc.V, rc.N); - aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); - - sample_t s, sx, sy; - bxdf::reflection::SOrenNayarBxDF orennayar = bxdf::reflection::SOrenNayarBxDF::create(rc.alpha.x); - s = orennayar.generate(anisointer, rc.u.xy); - sx = orennayar.generate(anisointer, rc.u.xy + float32_t2(rc.h,0)); - sy = orennayar.generate(anisointer, rc.u.xy + float32_t2(0,rc.h)); - quotient_pdf_t pdf = orennayar.quotient_and_pdf(s, isointer); - float32_t3 brdf = float32_t3(orennayar.eval(s, isointer)); - - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); -} - // inline float32_t4 testBlinnPhongBRDF() // { // const uint32_t2 state = uint32_t2(10u, 42u); @@ -182,33 +281,32 @@ inline float32_t4 testOrenNayarBRDF() // return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); // } -inline float32_t4 testBeckmannBRDF() +inline float32_t4 testLambertianBSDF() { - const uint32_t2 state = uint32_t2(10u, 42u); + const uint32_t2 state = uint32_t2(12u, 69u); SBxDFTestResources rc = SBxDFTestResources::create(state); iso_interaction isointer = iso_interaction::create(rc.V, rc.N); aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); - aniso_cache cache; sample_t s, sx, sy; - bxdf::reflection::SBeckmannBxDF beckmann = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); - s = beckmann.generate(anisointer, rc.u.xy, cache); - sx = beckmann.generate(anisointer, rc.u.xy + float32_t2(rc.h,0), cache); - sy = beckmann.generate(anisointer, rc.u.xy + float32_t2(0,rc.h), cache); - quotient_pdf_t pdf = beckmann.quotient_and_pdf(s, anisointer, cache); - float32_t3 brdf = float32_t3(beckmann.eval(s, anisointer, cache)); + bxdf::transmission::SLambertianBxDF lambertian = bxdf::transmission::SLambertianBxDF::create(); + s = lambertian.generate(anisointer, rc.u); + sx = lambertian.generate(anisointer, rc.u + float32_t3(rc.h,0,0)); + sy = lambertian.generate(anisointer, rc.u + float32_t3(0,rc.h,0)); + quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); + float32_t3 bsdf = float32_t3(lambertian.eval(s, isointer)); // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); float det = nbl::hlsl::determinant(m); - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } -inline float32_t4 testGGXBRDF() // iso ggx +inline float32_t4 testBeckmannBSDF() // iso beckmann { - const uint32_t2 state = uint32_t2(10u, 42u); + const uint32_t2 state = uint32_t2(12u, 69u); SBxDFTestResources rc = SBxDFTestResources::create(state); iso_interaction isointer = iso_interaction::create(rc.V, rc.N); @@ -216,23 +314,26 @@ inline float32_t4 testGGXBRDF() // iso ggx aniso_cache cache; sample_t s, sx, sy; - bxdf::reflection::SGGXBxDF ggx = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.ior); - s = ggx.generate(anisointer, rc.u.xy, cache); - sx = ggx.generate(anisointer, rc.u.xy + float32_t2(rc.h,0), cache); - sy = ggx.generate(anisointer, rc.u.xy + float32_t2(0,rc.h), cache); - quotient_pdf_t pdf = ggx.quotient_and_pdf(s, anisointer, cache); - float32_t3 brdf = float32_t3(ggx.eval(s, anisointer, cache)); + bxdf::transmission::SBeckmannDielectricBxDF beckmann = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x); + s = beckmann.generate(anisointer, rc.u, cache); + float32_t3 ux = rc.u + float32_t3(rc.h,0,0); + sx = beckmann.generate(anisointer, ux, cache); + float32_t3 uy = rc.u + float32_t3(0,rc.h,0); + sy = beckmann.generate(anisointer, uy, cache); + iso_cache isocache = (iso_cache)cache; + quotient_pdf_t pdf = beckmann.quotient_and_pdf(s, isointer, isocache); + float32_t3 bsdf = float32_t3(beckmann.eval(s, isointer, isocache)); // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); float det = nbl::hlsl::determinant(m); - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } -inline float32_t4 testGGXAnisoBRDF() // aniso ggx +inline float32_t4 testBeckmannAnisoBSDF() // aniso beckmann { - const uint32_t2 state = uint32_t2(10u, 42u); + const uint32_t2 state = uint32_t2(12u, 69u); SBxDFTestResources rc = SBxDFTestResources::create(state); iso_interaction isointer = iso_interaction::create(rc.V, rc.N); @@ -240,35 +341,41 @@ inline float32_t4 testGGXAnisoBRDF() // aniso ggx aniso_cache cache; sample_t s, sx, sy; - bxdf::reflection::SGGXBxDF ggx = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); - s = ggx.generate(anisointer, rc.u.xy, cache); - sx = ggx.generate(anisointer, rc.u.xy + float32_t2(rc.h,0), cache); - sy = ggx.generate(anisointer, rc.u.xy + float32_t2(0,rc.h), cache); - quotient_pdf_t pdf = ggx.quotient_and_pdf(s, anisointer, cache); - float32_t3 brdf = float32_t3(ggx.eval(s, anisointer, cache)); + bxdf::transmission::SBeckmannDielectricBxDF beckmann = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); + s = beckmann.generate(anisointer, rc.u, cache); + float32_t3 ux = rc.u + float32_t3(rc.h,0,0); + sx = beckmann.generate(anisointer, ux, cache); + float32_t3 uy = rc.u + float32_t3(0,rc.h,0); + sy = beckmann.generate(anisointer, uy, cache); + quotient_pdf_t pdf = beckmann.quotient_and_pdf(s, anisointer, cache); + float32_t3 bsdf = float32_t3(beckmann.eval(s, anisointer, cache)); // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); float det = nbl::hlsl::determinant(m); - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } -inline float32_t4 testLambertianBSDF() +inline float32_t4 testGGXBSDF() // iso ggx { const uint32_t2 state = uint32_t2(12u, 69u); SBxDFTestResources rc = SBxDFTestResources::create(state); iso_interaction isointer = iso_interaction::create(rc.V, rc.N); aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); + aniso_cache cache; sample_t s, sx, sy; - bxdf::transmission::SLambertianBxDF lambertian = bxdf::transmission::SLambertianBxDF::create(); - s = lambertian.generate(anisointer, rc.u); - sx = lambertian.generate(anisointer, rc.u + float32_t3(rc.h,0,0)); - sy = lambertian.generate(anisointer, rc.u + float32_t3(0,rc.h,0)); - quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); - float32_t3 bsdf = float32_t3(lambertian.eval(s, isointer)); + bxdf::transmission::SGGXDielectricBxDF ggx = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x); + s = ggx.generate(anisointer, rc.u, cache); + float32_t3 ux = rc.u + float32_t3(rc.h,0,0); + sx = ggx.generate(anisointer, ux, cache); + float32_t3 uy = rc.u + float32_t3(0,rc.h,0); + sy = ggx.generate(anisointer, uy, cache); + iso_cache isocache = (iso_cache)cache; + quotient_pdf_t pdf = ggx.quotient_and_pdf(s, isointer, isocache); + float32_t3 bsdf = float32_t3(ggx.eval(s, isointer, isocache)); // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); @@ -277,7 +384,7 @@ inline float32_t4 testLambertianBSDF() return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } -inline float32_t4 testBeckmannBSDF() +inline float32_t4 testGGXAnisoBSDF() // aniso ggx { const uint32_t2 state = uint32_t2(12u, 69u); SBxDFTestResources rc = SBxDFTestResources::create(state); @@ -287,14 +394,14 @@ inline float32_t4 testBeckmannBSDF() aniso_cache cache; sample_t s, sx, sy; - bxdf::transmission::SBeckmannDielectricBxDF beckmann = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); - s = beckmann.generate(anisointer, rc.u, cache); + bxdf::transmission::SGGXDielectricBxDF ggx = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); + s = ggx.generate(anisointer, rc.u, cache); float32_t3 ux = rc.u + float32_t3(rc.h,0,0); - sx = beckmann.generate(anisointer, ux, cache); + sx = ggx.generate(anisointer, ux, cache); float32_t3 uy = rc.u + float32_t3(0,rc.h,0); - sy = beckmann.generate(anisointer, uy, cache); - quotient_pdf_t pdf = beckmann.quotient_and_pdf(s, anisointer, cache); - float32_t3 bsdf = float32_t3(beckmann.eval(s, anisointer, cache)); + sy = ggx.generate(anisointer, uy, cache); + quotient_pdf_t pdf = ggx.quotient_and_pdf(s, anisointer, cache); + float32_t3 bsdf = float32_t3(ggx.eval(s, anisointer, cache)); // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 1dfa10253..2c37b99b4 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -26,34 +26,46 @@ int main(int argc, char** argv) // brdfs // diffuse - float32_t4 result = testLambertianBRDF(); + float32_t4 result = testLambertianBRDF2(); ASSERT_ZERO(result); - result = testLambertianBRDF2(); - assert(all(result < float32_t4(1e-4))); + TestUOffsetBasicBRDF>::run(uint32_t2(10u, 42u)); + ASSERT_ZERO(result); - result = testOrenNayarBRDF(); - assert(all(result < float32_t4(1e-4))); + TestUOffsetBasicBRDF>::run(uint32_t2(10u, 42u)); + ASSERT_ZERO(result); // specular //result = testBlinnPhongBRDF(); //printFloat4(result); - result = testBeckmannBRDF(); - assert(all(result < float32_t4(1e-4))); + TestUOffsetMicrofacetBRDF,false>::run(uint32_t2(10u, 42u)); + ASSERT_ZERO(result); - result = testGGXBRDF(); - printFloat4(result); + TestUOffsetMicrofacetBRDF,true>::run(uint32_t2(10u, 42u)); + ASSERT_ZERO(result); - result = testGGXAnisoBRDF(); - printFloat4(result); + TestUOffsetMicrofacetBRDF,false>::run(uint32_t2(10u, 42u)); + ASSERT_ZERO(result); + + TestUOffsetMicrofacetBRDF,true>::run(uint32_t2(10u, 42u)); + ASSERT_ZERO(result); // bxdfs result = testLambertianBSDF(); - assert(all(result < float32_t4(1e-4))); + ASSERT_ZERO(result); result = testBeckmannBSDF(); - assert(all(result < float32_t4(1e-4))); + printFloat4(result); + + result = testBeckmannAnisoBSDF(); + printFloat4(result); + + result = testGGXBSDF(); + printFloat4(result); + + result = testGGXAnisoBSDF(); + printFloat4(result); return 0; } \ No newline at end of file From 5140f852006fce52a92fc1369fc21161882d2bf1 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 7 Jan 2025 16:33:26 +0700 Subject: [PATCH 48/83] all existing tests into templates --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 307 +++++++++++----------- 66_HLSLBxDFTests/main.cpp | 48 ++-- 2 files changed, 172 insertions(+), 183 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index ee156426a..7c5e09900 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -99,6 +99,7 @@ struct TestBase aniso_interaction anisointer; }; + template struct TestBRDF : TestBase { @@ -151,6 +152,81 @@ struct TestBRDF> : } }; + +template +struct TestBSDF : TestBase +{ + using base_t = TestBase; + + void initBxDF(SBxDFTestResources _rc) + { + base_t::bxdf = BxDF::create(); // default to lambertian bsdf + } +}; + +template<> +struct TestBSDF> : TestBase> +{ + using base_t = TestBase>; + + template + void initBxDF(SBxDFTestResources _rc) + { + if (aniso) + base_t::bxdf = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); + else + base_t::bxdf = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x); + } +}; + +template<> +struct TestBSDF> : TestBase> +{ + using base_t = TestBase>; + + template + void initBxDF(SBxDFTestResources _rc) + { + if (aniso) + base_t::bxdf = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); + else + base_t::bxdf = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x); + } +}; + + +template +struct is_basic_brdf : bool_constant< + is_same>::value || + is_same>::value +> {}; + +template +struct is_microfacet_brdf : bool_constant< + is_same>::value || + is_same>::value +> {}; + +template +struct is_basic_bsdf : bool_constant< + is_same>::value +> {}; + +template +struct is_microfacet_bsdf : bool_constant< + is_same>::value || + is_same>::value +> {}; + +template +NBL_CONSTEXPR bool is_basic_brdf_v = is_basic_brdf::value; +template +NBL_CONSTEXPR bool is_microfacet_brdf_v = is_microfacet_bsdf::value; +template +NBL_CONSTEXPR bool is_basic_bsdf_v = is_basic_brdf::value; +template +NBL_CONSTEXPR bool is_microfacet_bsdf_v = is_microfacet_bsdf::value; + template struct TestUOffsetBasicBRDF : TestBRDF { @@ -226,6 +302,84 @@ struct TestUOffsetMicrofacetBRDF : TestBRDF } }; +template +struct TestUOffsetBasicBSDF : TestBSDF +{ + using base_t = TestBase; + using test_t = TestBSDF; + using this_t = TestUOffsetBasicBSDF; + + float32_t4 test() + { + sample_t s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u); + sample_t sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u + float32_t3(base_t::rc.h,0,0)); + sample_t sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u + float32_t3(0,base_t::rc.h,0)); + quotient_pdf_t pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); + float32_t3 brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); + + // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + } + + static float32_t4 run(uint32_t2 seed) + { + this_t t; + t.init(seed); + t.initBxDF(t.rc); + return t.test(); + } +}; + +template +struct TestUOffsetMicrofacetBSDF : TestBSDF +{ + using base_t = TestBase; + using test_t = TestBSDF; + using this_t = TestUOffsetMicrofacetBSDF; + + float32_t4 test() + { + aniso_cache cache, dummy; + + sample_t s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u, cache); + float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); + sample_t sx = base_t::bxdf.generate(base_t::anisointer, ux, dummy); + float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); + sample_t sy = base_t::bxdf.generate(base_t::anisointer, uy, dummy); + quotient_pdf_t pdf; + float32_t3 brdf; + + if (aniso) + { + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); + } + else + { + iso_cache isocache = (iso_cache)cache; + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); + } + + // get jacobian + float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + } + + static float32_t4 run(uint32_t2 seed) + { + this_t t; + t.init(seed); + t.template initBxDF(t.rc); + return t.test(); + } +}; + inline float32_t4 testLambertianBRDF2() { const uint32_t2 state = uint32_t2(10u, 42u); @@ -257,159 +411,6 @@ inline float32_t4 testLambertianBRDF2() return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } -// inline float32_t4 testBlinnPhongBRDF() -// { -// const uint32_t2 state = uint32_t2(10u, 42u); -// SBxDFTestResources rc = SBxDFTestResources::create(state); - -// iso_interaction isointer = iso_interaction::create(rc.V, rc.N); -// aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); -// aniso_cache cache; - -// sample_t s, sx, sy; -// bxdf::reflection::SBlinnPhongBxDF blinnphong = bxdf::reflection::SBlinnPhongBxDF::create(rc.alpha,rc.ior); -// s = blinnphong.generate(anisointer, rc.u.xy, cache); -// sx = blinnphong.generate(anisointer, rc.u.xy + float32_t2(rc.h,0), cache); -// sy = blinnphong.generate(anisointer, rc.u.xy + float32_t2(0,rc.h), cache); -// quotient_pdf_t pdf = blinnphong.quotient_and_pdf(s, anisointer, cache); -// float32_t3 brdf = float32_t3(blinnphong.eval(s, anisointer, cache)); - -// // get jacobian -// float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); -// float det = nbl::hlsl::determinant(m); - -// return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); -// } - -inline float32_t4 testLambertianBSDF() -{ - const uint32_t2 state = uint32_t2(12u, 69u); - SBxDFTestResources rc = SBxDFTestResources::create(state); - - iso_interaction isointer = iso_interaction::create(rc.V, rc.N); - aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); - - sample_t s, sx, sy; - bxdf::transmission::SLambertianBxDF lambertian = bxdf::transmission::SLambertianBxDF::create(); - s = lambertian.generate(anisointer, rc.u); - sx = lambertian.generate(anisointer, rc.u + float32_t3(rc.h,0,0)); - sy = lambertian.generate(anisointer, rc.u + float32_t3(0,rc.h,0)); - quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); - float32_t3 bsdf = float32_t3(lambertian.eval(s, isointer)); - - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); -} - -inline float32_t4 testBeckmannBSDF() // iso beckmann -{ - const uint32_t2 state = uint32_t2(12u, 69u); - SBxDFTestResources rc = SBxDFTestResources::create(state); - - iso_interaction isointer = iso_interaction::create(rc.V, rc.N); - aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); - aniso_cache cache; - - sample_t s, sx, sy; - bxdf::transmission::SBeckmannDielectricBxDF beckmann = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x); - s = beckmann.generate(anisointer, rc.u, cache); - float32_t3 ux = rc.u + float32_t3(rc.h,0,0); - sx = beckmann.generate(anisointer, ux, cache); - float32_t3 uy = rc.u + float32_t3(0,rc.h,0); - sy = beckmann.generate(anisointer, uy, cache); - iso_cache isocache = (iso_cache)cache; - quotient_pdf_t pdf = beckmann.quotient_and_pdf(s, isointer, isocache); - float32_t3 bsdf = float32_t3(beckmann.eval(s, isointer, isocache)); - - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); -} - -inline float32_t4 testBeckmannAnisoBSDF() // aniso beckmann -{ - const uint32_t2 state = uint32_t2(12u, 69u); - SBxDFTestResources rc = SBxDFTestResources::create(state); - - iso_interaction isointer = iso_interaction::create(rc.V, rc.N); - aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); - aniso_cache cache; - - sample_t s, sx, sy; - bxdf::transmission::SBeckmannDielectricBxDF beckmann = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); - s = beckmann.generate(anisointer, rc.u, cache); - float32_t3 ux = rc.u + float32_t3(rc.h,0,0); - sx = beckmann.generate(anisointer, ux, cache); - float32_t3 uy = rc.u + float32_t3(0,rc.h,0); - sy = beckmann.generate(anisointer, uy, cache); - quotient_pdf_t pdf = beckmann.quotient_and_pdf(s, anisointer, cache); - float32_t3 bsdf = float32_t3(beckmann.eval(s, anisointer, cache)); - - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); -} - -inline float32_t4 testGGXBSDF() // iso ggx -{ - const uint32_t2 state = uint32_t2(12u, 69u); - SBxDFTestResources rc = SBxDFTestResources::create(state); - - iso_interaction isointer = iso_interaction::create(rc.V, rc.N); - aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); - aniso_cache cache; - - sample_t s, sx, sy; - bxdf::transmission::SGGXDielectricBxDF ggx = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x); - s = ggx.generate(anisointer, rc.u, cache); - float32_t3 ux = rc.u + float32_t3(rc.h,0,0); - sx = ggx.generate(anisointer, ux, cache); - float32_t3 uy = rc.u + float32_t3(0,rc.h,0); - sy = ggx.generate(anisointer, uy, cache); - iso_cache isocache = (iso_cache)cache; - quotient_pdf_t pdf = ggx.quotient_and_pdf(s, isointer, isocache); - float32_t3 bsdf = float32_t3(ggx.eval(s, isointer, isocache)); - - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); -} - -inline float32_t4 testGGXAnisoBSDF() // aniso ggx -{ - const uint32_t2 state = uint32_t2(12u, 69u); - SBxDFTestResources rc = SBxDFTestResources::create(state); - - iso_interaction isointer = iso_interaction::create(rc.V, rc.N); - aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); - aniso_cache cache; - - sample_t s, sx, sy; - bxdf::transmission::SGGXDielectricBxDF ggx = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); - s = ggx.generate(anisointer, rc.u, cache); - float32_t3 ux = rc.u + float32_t3(rc.h,0,0); - sx = ggx.generate(anisointer, ux, cache); - float32_t3 uy = rc.u + float32_t3(0,rc.h,0); - sy = ggx.generate(anisointer, uy, cache); - quotient_pdf_t pdf = ggx.quotient_and_pdf(s, anisointer, cache); - float32_t3 bsdf = float32_t3(ggx.eval(s, anisointer, cache)); - - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - bsdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); -} - } } diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 2c37b99b4..9f5f73857 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -8,7 +8,7 @@ using namespace nbl::hlsl; #include "app_resources/tests.hlsl" -#define ASSERT_ZERO(x) assert(all(x < float32_t4(1e-4))); +#define ASSERT_ZERO(x) (assert(all((x) < float32_t4(1e-3)))); void printFloat4(const float32_t4& result) { @@ -24,48 +24,36 @@ int main(int argc, char** argv) using bool32_t4 = vector; + const uint32_t2 state = uint32_t2(10u, 42u); // (12u, 69u) + // brdfs // diffuse - float32_t4 result = testLambertianBRDF2(); - ASSERT_ZERO(result); - - TestUOffsetBasicBRDF>::run(uint32_t2(10u, 42u)); - ASSERT_ZERO(result); + ASSERT_ZERO(testLambertianBRDF2()); - TestUOffsetBasicBRDF>::run(uint32_t2(10u, 42u)); - ASSERT_ZERO(result); + ASSERT_ZERO((TestUOffsetBasicBRDF>::run(state))); + ASSERT_ZERO((TestUOffsetBasicBRDF>::run(state))); // specular - //result = testBlinnPhongBRDF(); - //printFloat4(result); - - TestUOffsetMicrofacetBRDF,false>::run(uint32_t2(10u, 42u)); - ASSERT_ZERO(result); + printFloat4(TestUOffsetMicrofacetBRDF,false>::run(state)); - TestUOffsetMicrofacetBRDF,true>::run(uint32_t2(10u, 42u)); - ASSERT_ZERO(result); + ASSERT_ZERO((TestUOffsetMicrofacetBRDF,true>::run(state))); + + printFloat4(TestUOffsetMicrofacetBRDF, false>::run(state)); - TestUOffsetMicrofacetBRDF,false>::run(uint32_t2(10u, 42u)); - ASSERT_ZERO(result); - - TestUOffsetMicrofacetBRDF,true>::run(uint32_t2(10u, 42u)); - ASSERT_ZERO(result); + ASSERT_ZERO((TestUOffsetMicrofacetBRDF,true>::run(state))); // bxdfs - result = testLambertianBSDF(); - ASSERT_ZERO(result); + // diffuse + ASSERT_ZERO((TestUOffsetBasicBSDF>::run(state))); - result = testBeckmannBSDF(); - printFloat4(result); + // specular + printFloat4(TestUOffsetMicrofacetBSDF,false>::run(state)); - result = testBeckmannAnisoBSDF(); - printFloat4(result); + printFloat4(TestUOffsetMicrofacetBSDF,true>::run(state)); // this one's fine - result = testGGXBSDF(); - printFloat4(result); + printFloat4(TestUOffsetMicrofacetBSDF,false>::run(state)); - result = testGGXAnisoBSDF(); - printFloat4(result); + printFloat4(TestUOffsetMicrofacetBSDF,true>::run(state)); return 0; } \ No newline at end of file From fb7b31b2f5f960fb5fd9225f53e29459c684a7df Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 8 Jan 2025 10:43:02 +0700 Subject: [PATCH 49/83] simplify test template and usage --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 200 +++++++--------------- 66_HLSLBxDFTests/main.cpp | 42 ++--- 2 files changed, 73 insertions(+), 169 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 7c5e09900..3d827b53d 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -101,18 +101,18 @@ struct TestBase template -struct TestBRDF : TestBase +struct TestBxDF : TestBase { using base_t = TestBase; void initBxDF(SBxDFTestResources _rc) { - base_t::bxdf = BxDF::create(); // default to lambertian brdf + base_t::bxdf = BxDF::create(); // default to lambertian bxdf } }; template<> -struct TestBRDF> : TestBase> +struct TestBxDF> : TestBase> { using base_t = TestBase>; @@ -123,7 +123,7 @@ struct TestBRDF -struct TestBRDF> : TestBase> +struct TestBxDF> : TestBase> { using base_t = TestBase>; @@ -138,7 +138,7 @@ struct TestBRDF -struct TestBRDF> : TestBase> +struct TestBxDF> : TestBase> { using base_t = TestBase>; @@ -152,20 +152,8 @@ struct TestBRDF> : } }; - -template -struct TestBSDF : TestBase -{ - using base_t = TestBase; - - void initBxDF(SBxDFTestResources _rc) - { - base_t::bxdf = BxDF::create(); // default to lambertian bsdf - } -}; - template<> -struct TestBSDF> : TestBase> +struct TestBxDF> : TestBase> { using base_t = TestBase>; @@ -180,7 +168,7 @@ struct TestBSDF -struct TestBSDF> : TestBase> +struct TestBxDF> : TestBase> { using base_t = TestBase>; @@ -221,147 +209,71 @@ struct is_microfacet_bsdf : bool_constant< template NBL_CONSTEXPR bool is_basic_brdf_v = is_basic_brdf::value; template -NBL_CONSTEXPR bool is_microfacet_brdf_v = is_microfacet_bsdf::value; +NBL_CONSTEXPR bool is_microfacet_brdf_v = is_microfacet_brdf::value; template -NBL_CONSTEXPR bool is_basic_bsdf_v = is_basic_brdf::value; +NBL_CONSTEXPR bool is_basic_bsdf_v = is_basic_bsdf::value; template NBL_CONSTEXPR bool is_microfacet_bsdf_v = is_microfacet_bsdf::value; -template -struct TestUOffsetBasicBRDF : TestBRDF -{ - using base_t = TestBase; - using test_t = TestBRDF; - using this_t = TestUOffsetBasicBRDF; - - float32_t4 test() - { - sample_t s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy); - sample_t sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(base_t::rc.h,0)); - sample_t sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(0,base_t::rc.h)); - quotient_pdf_t pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); - float32_t3 brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); - - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); - } - static float32_t4 run(uint32_t2 seed) - { - this_t t; - t.init(seed); - t.initBxDF(t.rc); - return t.test(); - } -}; - -template -struct TestUOffsetMicrofacetBRDF : TestBRDF +template +struct TestUOffset : TestBxDF { using base_t = TestBase; - using test_t = TestBRDF; - using this_t = TestUOffsetMicrofacetBRDF; + using this_t = TestUOffset; float32_t4 test() { - aniso_cache cache, dummy; - - sample_t s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy, cache); - sample_t sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(base_t::rc.h,0), dummy); - sample_t sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(0,base_t::rc.h), dummy); + sample_t s, sx, sy; quotient_pdf_t pdf; float32_t3 brdf; - if (aniso) + aniso_cache cache, dummy; + + if NBL_CONSTEXPR_FUNC (is_basic_brdf_v) { - pdf = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); + s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy); + sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(base_t::rc.h,0)); + sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(0,base_t::rc.h)); } - else + if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v) { - iso_cache isocache = (iso_cache)cache; - pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); + s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy, cache); + sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(base_t::rc.h,0), dummy); + sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(0,base_t::rc.h), dummy); } - - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); - } - - static float32_t4 run(uint32_t2 seed) - { - this_t t; - t.init(seed); - t.template initBxDF(t.rc); - return t.test(); - } -}; - -template -struct TestUOffsetBasicBSDF : TestBSDF -{ - using base_t = TestBase; - using test_t = TestBSDF; - using this_t = TestUOffsetBasicBSDF; - - float32_t4 test() - { - sample_t s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u); - sample_t sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u + float32_t3(base_t::rc.h,0,0)); - sample_t sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u + float32_t3(0,base_t::rc.h,0)); - quotient_pdf_t pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); - float32_t3 brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); - - // get jacobian - float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); - } - - static float32_t4 run(uint32_t2 seed) - { - this_t t; - t.init(seed); - t.initBxDF(t.rc); - return t.test(); - } -}; - -template -struct TestUOffsetMicrofacetBSDF : TestBSDF -{ - using base_t = TestBase; - using test_t = TestBSDF; - using this_t = TestUOffsetMicrofacetBSDF; - - float32_t4 test() - { - aniso_cache cache, dummy; - - sample_t s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u, cache); - float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); - sample_t sx = base_t::bxdf.generate(base_t::anisointer, ux, dummy); - float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); - sample_t sy = base_t::bxdf.generate(base_t::anisointer, uy, dummy); - quotient_pdf_t pdf; - float32_t3 brdf; - - if (aniso) + if NBL_CONSTEXPR_FUNC (is_basic_bsdf_v) { - pdf = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); + s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u); + sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u + float32_t3(base_t::rc.h,0,0)); + sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u + float32_t3(0,base_t::rc.h,0)); } - else + if NBL_CONSTEXPR_FUNC (is_microfacet_bsdf_v) { - iso_cache isocache = (iso_cache)cache; - pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); + s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u, cache); + float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); + sx = base_t::bxdf.generate(base_t::anisointer, ux, dummy); + float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); + sy = base_t::bxdf.generate(base_t::anisointer, uy, dummy); + } + + if NBL_CONSTEXPR_FUNC (is_basic_brdf_v || is_basic_bsdf_v) + { + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); + } + if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v || is_microfacet_bsdf_v) + { + if NBL_CONSTEXPR_FUNC (aniso) + { + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); + } + else + { + iso_cache isocache = (iso_cache)cache; + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); + } } // get jacobian @@ -375,11 +287,15 @@ struct TestUOffsetMicrofacetBSDF : TestBSDF { this_t t; t.init(seed); - t.template initBxDF(t.rc); + if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v || is_microfacet_bsdf_v) + t.template initBxDF(t.rc); + else + t.initBxDF(t.rc); return t.test(); } }; + inline float32_t4 testLambertianBRDF2() { const uint32_t2 state = uint32_t2(10u, 42u); diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 9f5f73857..03b4ba52c 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -26,34 +26,22 @@ int main(int argc, char** argv) const uint32_t2 state = uint32_t2(10u, 42u); // (12u, 69u) - // brdfs - // diffuse + // test u offset, 2 axis + ASSERT_ZERO((TestUOffset>::run(state))); + ASSERT_ZERO((TestUOffset>::run(state))); + printFloat4(TestUOffset,false>::run(state)); + ASSERT_ZERO((TestUOffset,true>::run(state))); + printFloat4(TestUOffset,false>::run(state)); + ASSERT_ZERO((TestUOffset,true>::run(state))); + + ASSERT_ZERO((TestUOffset>::run(state))); + printFloat4(TestUOffset,false>::run(state)); + ASSERT_ZERO((TestUOffset,true>::run(state))); + printFloat4(TestUOffset,false>::run(state)); + printFloat4(TestUOffset,true>::run(state)); + + // test v offset, 3 axis ASSERT_ZERO(testLambertianBRDF2()); - ASSERT_ZERO((TestUOffsetBasicBRDF>::run(state))); - ASSERT_ZERO((TestUOffsetBasicBRDF>::run(state))); - - // specular - printFloat4(TestUOffsetMicrofacetBRDF,false>::run(state)); - - ASSERT_ZERO((TestUOffsetMicrofacetBRDF,true>::run(state))); - - printFloat4(TestUOffsetMicrofacetBRDF, false>::run(state)); - - ASSERT_ZERO((TestUOffsetMicrofacetBRDF,true>::run(state))); - - // bxdfs - // diffuse - ASSERT_ZERO((TestUOffsetBasicBSDF>::run(state))); - - // specular - printFloat4(TestUOffsetMicrofacetBSDF,false>::run(state)); - - printFloat4(TestUOffsetMicrofacetBSDF,true>::run(state)); // this one's fine - - printFloat4(TestUOffsetMicrofacetBSDF,false>::run(state)); - - printFloat4(TestUOffsetMicrofacetBSDF,true>::run(state)); - return 0; } \ No newline at end of file From 3c415fd9c638672945b66fabc79567fd1b934c55 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 8 Jan 2025 14:31:44 +0700 Subject: [PATCH 50/83] diff v test --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 121 ++++++++++++++++------ 66_HLSLBxDFTests/main.cpp | 15 ++- 2 files changed, 103 insertions(+), 33 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 3d827b53d..1f42b5372 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -50,7 +50,7 @@ struct SBxDFTestResources retval.alpha.x = rngFloat01(retval.rng); retval.alpha.y = rngFloat01(retval.rng); - retval.eta = rngFloat01(retval.rng) + 1.0; + retval.eta = 1.3;// rngFloat01(retval.rng) + 1.0; retval.ior = float32_t3x2(1.02, 1.0, // randomize at some point? 1.3, 2.0, 1.02, 1.0); @@ -77,7 +77,6 @@ struct SBxDFTestResources float32_t3 u; float32_t2 alpha; float eta; - float eta2; // what is this? float32_t3x2 ior; }; @@ -296,36 +295,96 @@ struct TestUOffset : TestBxDF }; -inline float32_t4 testLambertianBRDF2() +template +struct TestVOffset : TestBxDF { - const uint32_t2 state = uint32_t2(10u, 42u); - SBxDFTestResources rc = SBxDFTestResources::create(state); - - iso_interaction isointer = iso_interaction::create(rc.V, rc.N); - aniso_interaction anisointer = aniso_interaction::create(isointer, rc.T, rc.B); - - iso_interaction isointerx = iso_interaction::create(rc.dV(0), rc.N); - aniso_interaction anisointerx = aniso_interaction::create(isointerx, rc.T, rc.B); - iso_interaction isointery = iso_interaction::create(rc.dV(1), rc.N); - aniso_interaction anisointery = aniso_interaction::create(isointery, rc.T, rc.B); - iso_interaction isointerz = iso_interaction::create(rc.dV(2), rc.N); - aniso_interaction anisointerz = aniso_interaction::create(isointerz, rc.T, rc.B); - - sample_t s, sx, sy, sz; - bxdf::reflection::SLambertianBxDF lambertian = bxdf::reflection::SLambertianBxDF::create(); - s = lambertian.generate(anisointer, rc.u.xy); - sx = lambertian.generate(anisointerx, rc.u.xy); - sy = lambertian.generate(anisointery, rc.u.xy); - sz = lambertian.generate(anisointerz, rc.u.xy); - quotient_pdf_t pdf = lambertian.quotient_and_pdf(s, isointer); - float32_t3 brdf = float32_t3(lambertian.eval(s, isointer)); - - // get jacobian - float32_t3x3 m = float32_t3x3(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL, sz.BdotL - s.BdotL, sx.NdotL - s.NdotL, sy.NdotL - s.NdotL, sz.NdotL - s.NdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); -} + using base_t = TestBase; + using this_t = TestVOffset; + + float32_t4 test() + { + sample_t s, sx, sy, sz; + quotient_pdf_t pdf; + float32_t3 brdf; + aniso_cache cache, dummy; + + iso_interaction isointerx = iso_interaction::create(base_t::rc.dV(0), base_t::rc.N); + aniso_interaction anisointerx = aniso_interaction::create(isointerx, base_t::rc.T, base_t::rc.B); + iso_interaction isointery = iso_interaction::create(base_t::rc.dV(1), base_t::rc.N); + aniso_interaction anisointery = aniso_interaction::create(isointery, base_t::rc.T, base_t::rc.B); + iso_interaction isointerz = iso_interaction::create(base_t::rc.dV(2), base_t::rc.N); + aniso_interaction anisointerz = aniso_interaction::create(isointerz, base_t::rc.T, base_t::rc.B); + + if NBL_CONSTEXPR_FUNC (is_basic_brdf_v) + { + s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy); + sx = base_t::bxdf.generate(anisointerx, base_t::rc.u.xy); + sy = base_t::bxdf.generate(anisointery, base_t::rc.u.xy); + sz = base_t::bxdf.generate(anisointerz, base_t::rc.u.xy); + } + if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v) + { + s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy, cache); + sx = base_t::bxdf.generate(anisointerx, base_t::rc.u.xy, dummy); + sy = base_t::bxdf.generate(anisointery, base_t::rc.u.xy, dummy); + sz = base_t::bxdf.generate(anisointerz, base_t::rc.u.xy, dummy); + } + if NBL_CONSTEXPR_FUNC (is_basic_bsdf_v) + { + s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u); + sx = base_t::bxdf.generate(anisointerx, base_t::rc.u); + sy = base_t::bxdf.generate(anisointery, base_t::rc.u); + sz = base_t::bxdf.generate(anisointerz, base_t::rc.u); + } + if NBL_CONSTEXPR_FUNC (is_microfacet_bsdf_v) + { + s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u, cache); + float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); + sx = base_t::bxdf.generate(anisointerx, ux, dummy); + float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); + sy = base_t::bxdf.generate(anisointery, uy, dummy); + float32_t3 uz = base_t::rc.u + float32_t3(0,0,base_t::rc.h); + sz = base_t::bxdf.generate(anisointerz, uz, dummy); + } + + if NBL_CONSTEXPR_FUNC (is_basic_brdf_v || is_basic_bsdf_v) + { + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); + } + if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v || is_microfacet_bsdf_v) + { + if NBL_CONSTEXPR_FUNC (aniso) + { + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); + } + else + { + iso_cache isocache = (iso_cache)cache; + pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); + brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); + } + } + + // get jacobian + float32_t3x3 m = float32_t3x3(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL, sz.BdotL - s.BdotL, sx.NdotL - s.NdotL, sy.NdotL - s.NdotL, sz.NdotL - s.NdotL); + float det = nbl::hlsl::determinant(m); + + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + } + + static float32_t4 run(uint32_t2 seed) + { + this_t t; + t.init(seed); + if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v || is_microfacet_bsdf_v) + t.template initBxDF(t.rc); + else + t.initBxDF(t.rc); + return t.test(); + } +}; } } diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 03b4ba52c..1b2d2aaa2 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -24,7 +24,7 @@ int main(int argc, char** argv) using bool32_t4 = vector; - const uint32_t2 state = uint32_t2(10u, 42u); // (12u, 69u) + const uint32_t2 state = uint32_t2(12u, 69u); // (12u, 69u) // test u offset, 2 axis ASSERT_ZERO((TestUOffset>::run(state))); @@ -41,7 +41,18 @@ int main(int argc, char** argv) printFloat4(TestUOffset,true>::run(state)); // test v offset, 3 axis - ASSERT_ZERO(testLambertianBRDF2()); + ASSERT_ZERO((TestVOffset>::run(state))); + ASSERT_ZERO((TestVOffset>::run(state))); + printFloat4(TestVOffset, false>::run(state)); + ASSERT_ZERO((TestVOffset, true>::run(state))); + printFloat4(TestVOffset, false>::run(state)); + ASSERT_ZERO((TestVOffset, true>::run(state))); + + ASSERT_ZERO((TestVOffset>::run(state))); + printFloat4(TestVOffset, false>::run(state)); + ASSERT_ZERO((TestVOffset, true>::run(state))); + printFloat4(TestVOffset, false>::run(state)); + printFloat4(TestVOffset, true>::run(state)); return 0; } \ No newline at end of file From 3524449cd16e3909b67a5dac7d6cbab296bddb68 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 8 Jan 2025 15:13:41 +0700 Subject: [PATCH 51/83] test metadata struct for more info --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 71 +++++++++++++++++++++-- 66_HLSLBxDFTests/main.cpp | 33 ++++++----- 2 files changed, 84 insertions(+), 20 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 1f42b5372..d67b0234c 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -80,6 +80,15 @@ struct SBxDFTestResources float32_t3x2 ior; }; +struct STestMeta +{ + float32_t4 result; +#ifndef __HLSL_VERSION + std::string bxdfName; + std::string testName; +#endif +}; + template struct TestBase { @@ -96,6 +105,8 @@ struct TestBase iso_interaction isointer; aniso_interaction anisointer; + + STestMeta meta; }; @@ -107,6 +118,9 @@ struct TestBxDF : TestBase void initBxDF(SBxDFTestResources _rc) { base_t::bxdf = BxDF::create(); // default to lambertian bxdf +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "LambertianBxDF"; +#endif } }; @@ -118,6 +132,9 @@ struct TestBxDF::create(_rc.alpha.x); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "OrenNayarBRDF"; +#endif } }; @@ -130,9 +147,19 @@ struct TestBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "BeckmannBRDF Aniso"; +#endif + } else + { base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,rc.ior); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "BeckmannBRDF"; +#endif + } } }; @@ -145,9 +172,19 @@ struct TestBxDF> : void initBxDF(SBxDFTestResources _rc) { if (aniso) + { base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "GGXBRDF Aniso"; +#endif + } else + { base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.ior); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "GGXBRDF"; +#endif + } } }; @@ -160,9 +197,19 @@ struct TestBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "BeckmannBSDF Aniso"; +#endif + } else + { base_t::bxdf = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "BeckmannBSDF"; +#endif + } } }; @@ -175,9 +222,19 @@ struct TestBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "GGXBSDF Aniso"; +#endif + } else + { base_t::bxdf = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "GGXBSDF"; +#endif + } } }; @@ -282,7 +339,7 @@ struct TestUOffset : TestBxDF return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } - static float32_t4 run(uint32_t2 seed) + static STestMeta run(uint32_t2 seed) { this_t t; t.init(seed); @@ -290,7 +347,10 @@ struct TestUOffset : TestBxDF t.template initBxDF(t.rc); else t.initBxDF(t.rc); - return t.test(); + + t.meta.result = t.test(); + t.meta.testName = "u offset"; + return t.meta; } }; @@ -374,7 +434,7 @@ struct TestVOffset : TestBxDF return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); } - static float32_t4 run(uint32_t2 seed) + static STestMeta run(uint32_t2 seed) { this_t t; t.init(seed); @@ -382,7 +442,10 @@ struct TestVOffset : TestBxDF t.template initBxDF(t.rc); else t.initBxDF(t.rc); - return t.test(); + + t.meta.result = t.test(); + t.meta.testName = "V offset"; + return t.meta; } }; diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 1b2d2aaa2..6e43d64ab 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -8,14 +8,15 @@ using namespace nbl::hlsl; #include "app_resources/tests.hlsl" -#define ASSERT_ZERO(x) (assert(all((x) < float32_t4(1e-3)))); +#define ASSERT_ZERO(x) (assert(all((x.result) < float32_t4(1e-3)))); -void printFloat4(const float32_t4& result) +void printResult(const STestMeta& m) { - std::cout << result.x << " " - << result.y << " " - << result.z << " " - << result.w << "\n"; + std::cout << m.testName << " " << m.bxdfName << "\t" + << m.result.x << " " + << m.result.y << " " + << m.result.z << " " + << m.result.w << "\n"; } int main(int argc, char** argv) @@ -29,30 +30,30 @@ int main(int argc, char** argv) // test u offset, 2 axis ASSERT_ZERO((TestUOffset>::run(state))); ASSERT_ZERO((TestUOffset>::run(state))); - printFloat4(TestUOffset,false>::run(state)); + printResult(TestUOffset,false>::run(state)); ASSERT_ZERO((TestUOffset,true>::run(state))); - printFloat4(TestUOffset,false>::run(state)); + printResult(TestUOffset,false>::run(state)); ASSERT_ZERO((TestUOffset,true>::run(state))); ASSERT_ZERO((TestUOffset>::run(state))); - printFloat4(TestUOffset,false>::run(state)); + printResult(TestUOffset,false>::run(state)); ASSERT_ZERO((TestUOffset,true>::run(state))); - printFloat4(TestUOffset,false>::run(state)); - printFloat4(TestUOffset,true>::run(state)); + printResult(TestUOffset,false>::run(state)); + printResult(TestUOffset,true>::run(state)); // test v offset, 3 axis ASSERT_ZERO((TestVOffset>::run(state))); ASSERT_ZERO((TestVOffset>::run(state))); - printFloat4(TestVOffset, false>::run(state)); + printResult(TestVOffset, false>::run(state)); ASSERT_ZERO((TestVOffset, true>::run(state))); - printFloat4(TestVOffset, false>::run(state)); + printResult(TestVOffset, false>::run(state)); ASSERT_ZERO((TestVOffset, true>::run(state))); ASSERT_ZERO((TestVOffset>::run(state))); - printFloat4(TestVOffset, false>::run(state)); + printResult(TestVOffset, false>::run(state)); ASSERT_ZERO((TestVOffset, true>::run(state))); - printFloat4(TestVOffset, false>::run(state)); - printFloat4(TestVOffset, true>::run(state)); + printResult(TestVOffset, false>::run(state)); + printResult(TestVOffset, true>::run(state)); return 0; } \ No newline at end of file From ef188ba1d3dc5b98bb4f97a8c41de68f469c5653 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 8 Jan 2025 16:25:42 +0700 Subject: [PATCH 52/83] smooth dielectric bsdf tests --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 52 ++++++++++++++++++++--- 66_HLSLBxDFTests/main.cpp | 4 ++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index d67b0234c..6da405904 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -54,6 +54,8 @@ struct SBxDFTestResources retval.ior = float32_t3x2(1.02, 1.0, // randomize at some point? 1.3, 2.0, 1.02, 1.0); + retval.eta2 = float32_t3(1.02, 1.3, 1.02); // TODO: check correctness? + retval.luma_coeff = float32_t3(0.2126, 0.7152, 0.0722); // luma coefficients for Rec. 709 return retval; } @@ -78,6 +80,9 @@ struct SBxDFTestResources float32_t2 alpha; float eta; float32_t3x2 ior; + + float32_t3 eta2; // what is this? + float32_t3 luma_coeff; }; struct STestMeta @@ -188,6 +193,34 @@ struct TestBxDF> : } }; +template<> +struct TestBxDF> : TestBase> +{ + using base_t = TestBase>; + + void initBxDF(SBxDFTestResources _rc) + { + base_t::bxdf = bxdf::transmission::SSmoothDielectricBxDF::create(rc.eta); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "SmoothDielectricBSDF"; +#endif + } +}; + +template<> +struct TestBxDF> : TestBase> +{ + using base_t = TestBase>; + + void initBxDF(SBxDFTestResources _rc) + { + base_t::bxdf = bxdf::transmission::SSmoothDielectricBxDF::create(rc.eta2,rc.luma_coeff); +#ifndef __HLSL_VERSION + base_t::meta.bxdfName = "ThinSmoothDielectricBSDF"; +#endif + } +}; + template<> struct TestBxDF> : TestBase> { @@ -253,7 +286,9 @@ struct is_microfacet_brdf : bool_constant< template struct is_basic_bsdf : bool_constant< - is_same>::value + is_same>::value || + is_same>::value || + is_same>::value > {}; template @@ -300,8 +335,10 @@ struct TestUOffset : TestBxDF if NBL_CONSTEXPR_FUNC (is_basic_bsdf_v) { s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u); - sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u + float32_t3(base_t::rc.h,0,0)); - sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u + float32_t3(0,base_t::rc.h,0)); + float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); + sx = base_t::bxdf.generate(base_t::anisointer, ux); + float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); + sy = base_t::bxdf.generate(base_t::anisointer, uy); } if NBL_CONSTEXPR_FUNC (is_microfacet_bsdf_v) { @@ -392,9 +429,12 @@ struct TestVOffset : TestBxDF if NBL_CONSTEXPR_FUNC (is_basic_bsdf_v) { s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u); - sx = base_t::bxdf.generate(anisointerx, base_t::rc.u); - sy = base_t::bxdf.generate(anisointery, base_t::rc.u); - sz = base_t::bxdf.generate(anisointerz, base_t::rc.u); + float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); + sx = base_t::bxdf.generate(anisointerx, ux); + float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); + sy = base_t::bxdf.generate(anisointery, uy); + float32_t3 uz = base_t::rc.u + float32_t3(0,0,base_t::rc.h); + sz = base_t::bxdf.generate(anisointerz, uz); } if NBL_CONSTEXPR_FUNC (is_microfacet_bsdf_v) { diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 6e43d64ab..e78212ac5 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -36,6 +36,8 @@ int main(int argc, char** argv) ASSERT_ZERO((TestUOffset,true>::run(state))); ASSERT_ZERO((TestUOffset>::run(state))); + printResult(TestUOffset>::run(state)); + printResult(TestUOffset>::run(state)); printResult(TestUOffset,false>::run(state)); ASSERT_ZERO((TestUOffset,true>::run(state))); printResult(TestUOffset,false>::run(state)); @@ -50,6 +52,8 @@ int main(int argc, char** argv) ASSERT_ZERO((TestVOffset, true>::run(state))); ASSERT_ZERO((TestVOffset>::run(state))); + printResult(TestVOffset>::run(state)); + printResult(TestVOffset>::run(state)); printResult(TestVOffset, false>::run(state)); ASSERT_ZERO((TestVOffset, true>::run(state))); printResult(TestVOffset, false>::run(state)); From 17b253c0fa0650caf283ba0040a27f7e8e88221b Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 9 Jan 2025 14:59:58 +0700 Subject: [PATCH 53/83] improve rng function --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 53 +++++++++++++++++++---- 66_HLSLBxDFTests/main.cpp | 28 ++++++------ 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 6da405904..194e25a91 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -21,6 +21,9 @@ using iso_cache = bxdf::SIsotropicMicrofacetCache; using aniso_cache = bxdf::SAnisotropicMicrofacetCache; using quotient_pdf_t = bxdf::quotient_and_pdf; +namespace impl +{ + inline float rngFloat01(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) { return (float)rng() / numeric_limits::max; @@ -31,6 +34,38 @@ inline float32_t3 rngFloat301(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) return float32_t3(rngFloat01(rng), rngFloat01(rng), rngFloat01(rng)); } +template +struct RNGUniformDist; + +template<> +struct RNGUniformDist +{ + static float32_t __call(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) + { + return rngFloat01(rng); + } +}; + +template +struct RNGUniformDist> +{ + static vector __call(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) + { + vector retval; + for (int i = 0; i < rank::value; i++) + retval[i] = rngFloat01(rng); + return retval; + } +}; + +} + +template +T rngUniformDist(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) +{ + return impl::RNGUniformDist::__call(rng); +} + struct SBxDFTestResources { @@ -39,17 +74,17 @@ struct SBxDFTestResources SBxDFTestResources retval; retval.rng = nbl::hlsl::Xoroshiro64Star::construct(seed); - retval.u = float32_t3(rngFloat01(retval.rng), rngFloat01(retval.rng), 0.0); + retval.u = float32_t3(rngUniformDist(retval.rng), 0.0); - retval.V.direction = nbl::hlsl::normalize(rngFloat301(retval.rng)); - retval.N = nbl::hlsl::normalize(rngFloat301(retval.rng)); - retval.T = nbl::hlsl::normalize(rngFloat301(retval.rng)); - - retval.T = nbl::hlsl::normalize(retval.T - nbl::hlsl::dot(retval.T, retval.N) * retval.N); // gram schmidt - retval.B = nbl::hlsl::cross(retval.N, retval.T); + retval.V.direction = nbl::hlsl::normalize(projected_hemisphere_generate(rngUniformDist(retval.rng))); + retval.N = nbl::hlsl::normalize(projected_hemisphere_generate(rngUniformDist(retval.rng))); + + float32_t2x3 tb = math::frisvad(retval.N); + retval.T = tb[0]; + retval.B = tb[1]; - retval.alpha.x = rngFloat01(retval.rng); - retval.alpha.y = rngFloat01(retval.rng); + retval.alpha.x = rngUniformDist(retval.rng); + retval.alpha.y = rngUniformDist(retval.rng); retval.eta = 1.3;// rngFloat01(retval.rng) + 1.0; retval.ior = float32_t3x2(1.02, 1.0, // randomize at some point? 1.3, 2.0, diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index e78212ac5..7275dfcf3 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -44,20 +44,20 @@ int main(int argc, char** argv) printResult(TestUOffset,true>::run(state)); // test v offset, 3 axis - ASSERT_ZERO((TestVOffset>::run(state))); - ASSERT_ZERO((TestVOffset>::run(state))); - printResult(TestVOffset, false>::run(state)); - ASSERT_ZERO((TestVOffset, true>::run(state))); - printResult(TestVOffset, false>::run(state)); - ASSERT_ZERO((TestVOffset, true>::run(state))); - - ASSERT_ZERO((TestVOffset>::run(state))); - printResult(TestVOffset>::run(state)); - printResult(TestVOffset>::run(state)); - printResult(TestVOffset, false>::run(state)); - ASSERT_ZERO((TestVOffset, true>::run(state))); - printResult(TestVOffset, false>::run(state)); - printResult(TestVOffset, true>::run(state)); + //ASSERT_ZERO((TestVOffset>::run(state))); + //ASSERT_ZERO((TestVOffset>::run(state))); + //printResult(TestVOffset, false>::run(state)); + //ASSERT_ZERO((TestVOffset, true>::run(state))); + //printResult(TestVOffset, false>::run(state)); + //ASSERT_ZERO((TestVOffset, true>::run(state))); + + //ASSERT_ZERO((TestVOffset>::run(state))); + //printResult(TestVOffset>::run(state)); + //printResult(TestVOffset>::run(state)); + //printResult(TestVOffset, false>::run(state)); + //ASSERT_ZERO((TestVOffset, true>::run(state))); + //printResult(TestVOffset, false>::run(state)); + //printResult(TestVOffset, true>::run(state)); return 0; } \ No newline at end of file From 59d14c30adb640509623b72001a232ada2d6b16f Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 9 Jan 2025 16:20:03 +0700 Subject: [PATCH 54/83] fix bugs in rng --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 102 +--------------------- 66_HLSLBxDFTests/main.cpp | 34 ++------ 2 files changed, 11 insertions(+), 125 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 194e25a91..3ccb18761 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -46,13 +46,13 @@ struct RNGUniformDist } }; -template +template struct RNGUniformDist> { static vector __call(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) { vector retval; - for (int i = 0; i < rank::value; i++) + for (int i = 0; i < N; i++) retval[i] = rngFloat01(rng); return retval; } @@ -426,104 +426,6 @@ struct TestUOffset : TestBxDF } }; - -template -struct TestVOffset : TestBxDF -{ - using base_t = TestBase; - using this_t = TestVOffset; - - float32_t4 test() - { - sample_t s, sx, sy, sz; - quotient_pdf_t pdf; - float32_t3 brdf; - aniso_cache cache, dummy; - - iso_interaction isointerx = iso_interaction::create(base_t::rc.dV(0), base_t::rc.N); - aniso_interaction anisointerx = aniso_interaction::create(isointerx, base_t::rc.T, base_t::rc.B); - iso_interaction isointery = iso_interaction::create(base_t::rc.dV(1), base_t::rc.N); - aniso_interaction anisointery = aniso_interaction::create(isointery, base_t::rc.T, base_t::rc.B); - iso_interaction isointerz = iso_interaction::create(base_t::rc.dV(2), base_t::rc.N); - aniso_interaction anisointerz = aniso_interaction::create(isointerz, base_t::rc.T, base_t::rc.B); - - if NBL_CONSTEXPR_FUNC (is_basic_brdf_v) - { - s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy); - sx = base_t::bxdf.generate(anisointerx, base_t::rc.u.xy); - sy = base_t::bxdf.generate(anisointery, base_t::rc.u.xy); - sz = base_t::bxdf.generate(anisointerz, base_t::rc.u.xy); - } - if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v) - { - s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy, cache); - sx = base_t::bxdf.generate(anisointerx, base_t::rc.u.xy, dummy); - sy = base_t::bxdf.generate(anisointery, base_t::rc.u.xy, dummy); - sz = base_t::bxdf.generate(anisointerz, base_t::rc.u.xy, dummy); - } - if NBL_CONSTEXPR_FUNC (is_basic_bsdf_v) - { - s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u); - float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); - sx = base_t::bxdf.generate(anisointerx, ux); - float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); - sy = base_t::bxdf.generate(anisointery, uy); - float32_t3 uz = base_t::rc.u + float32_t3(0,0,base_t::rc.h); - sz = base_t::bxdf.generate(anisointerz, uz); - } - if NBL_CONSTEXPR_FUNC (is_microfacet_bsdf_v) - { - s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u, cache); - float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); - sx = base_t::bxdf.generate(anisointerx, ux, dummy); - float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); - sy = base_t::bxdf.generate(anisointery, uy, dummy); - float32_t3 uz = base_t::rc.u + float32_t3(0,0,base_t::rc.h); - sz = base_t::bxdf.generate(anisointerz, uz, dummy); - } - - if NBL_CONSTEXPR_FUNC (is_basic_brdf_v || is_basic_bsdf_v) - { - pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); - } - if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v || is_microfacet_bsdf_v) - { - if NBL_CONSTEXPR_FUNC (aniso) - { - pdf = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); - } - else - { - iso_cache isocache = (iso_cache)cache; - pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); - } - } - - // get jacobian - float32_t3x3 m = float32_t3x3(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL, sz.BdotL - s.BdotL, sx.NdotL - s.NdotL, sy.NdotL - s.NdotL, sz.NdotL - s.NdotL); - float det = nbl::hlsl::determinant(m); - - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); - } - - static STestMeta run(uint32_t2 seed) - { - this_t t; - t.init(seed); - if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v || is_microfacet_bsdf_v) - t.template initBxDF(t.rc); - else - t.initBxDF(t.rc); - - t.meta.result = t.test(); - t.meta.testName = "V offset"; - return t.meta; - } -}; - } } diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 7275dfcf3..eff279244 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -25,39 +25,23 @@ int main(int argc, char** argv) using bool32_t4 = vector; - const uint32_t2 state = uint32_t2(12u, 69u); // (12u, 69u) + const uint32_t2 state = uint32_t2(10u, 42u); // (12u, 69u) // test u offset, 2 axis - ASSERT_ZERO((TestUOffset>::run(state))); - ASSERT_ZERO((TestUOffset>::run(state))); + printResult((TestUOffset>::run(state))); + printResult((TestUOffset>::run(state))); printResult(TestUOffset,false>::run(state)); - ASSERT_ZERO((TestUOffset,true>::run(state))); + printResult((TestUOffset,true>::run(state))); printResult(TestUOffset,false>::run(state)); - ASSERT_ZERO((TestUOffset,true>::run(state))); + printResult((TestUOffset,true>::run(state))); - ASSERT_ZERO((TestUOffset>::run(state))); - printResult(TestUOffset>::run(state)); - printResult(TestUOffset>::run(state)); + printResult((TestUOffset>::run(state))); + //printResult(TestUOffset>::run(state)); + //printResult(TestUOffset>::run(state)); printResult(TestUOffset,false>::run(state)); - ASSERT_ZERO((TestUOffset,true>::run(state))); + printResult((TestUOffset,true>::run(state))); printResult(TestUOffset,false>::run(state)); printResult(TestUOffset,true>::run(state)); - // test v offset, 3 axis - //ASSERT_ZERO((TestVOffset>::run(state))); - //ASSERT_ZERO((TestVOffset>::run(state))); - //printResult(TestVOffset, false>::run(state)); - //ASSERT_ZERO((TestVOffset, true>::run(state))); - //printResult(TestVOffset, false>::run(state)); - //ASSERT_ZERO((TestVOffset, true>::run(state))); - - //ASSERT_ZERO((TestVOffset>::run(state))); - //printResult(TestVOffset>::run(state)); - //printResult(TestVOffset>::run(state)); - //printResult(TestVOffset, false>::run(state)); - //ASSERT_ZERO((TestVOffset, true>::run(state))); - //printResult(TestVOffset, false>::run(state)); - //printResult(TestVOffset, true>::run(state)); - return 0; } \ No newline at end of file From fac1ed1a08858bfdcf362f034a5c0d9a5dd4431b Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 10 Jan 2025 11:47:04 +0700 Subject: [PATCH 55/83] fix tests, use uniform sampling --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 3ccb18761..121a30309 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -4,6 +4,7 @@ #include "nbl/builtin/hlsl/cpp_compat.hlsl" #include "nbl/builtin/hlsl/random/xoroshiro.hlsl" +#include "nbl/builtin/hlsl/sampling/uniform.hlsl" #include "nbl/builtin/hlsl/bxdf/common.hlsl" #include "nbl/builtin/hlsl/bxdf/reflection.hlsl" #include "nbl/builtin/hlsl/bxdf/transmission.hlsl" @@ -29,11 +30,6 @@ inline float rngFloat01(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) return (float)rng() / numeric_limits::max; } -inline float32_t3 rngFloat301(NBL_REF_ARG(nbl::hlsl::Xoroshiro64Star) rng) -{ - return float32_t3(rngFloat01(rng), rngFloat01(rng), rngFloat01(rng)); -} - template struct RNGUniformDist; @@ -80,8 +76,19 @@ struct SBxDFTestResources retval.N = nbl::hlsl::normalize(projected_hemisphere_generate(rngUniformDist(retval.rng))); float32_t2x3 tb = math::frisvad(retval.N); +#ifndef __HLSL_VERSION + core::quaternion rot; + float angle = 2 * numbers::pi * rngUniformDist(retval.rng); + core::vectorSIMDf N = core::vectorSIMDf(retval.N.x, retval.N.y, retval.N.z); + rot.toAngleAxis(angle, N); + core::vectorSIMDf tmp = rot.transformVect(core::vectorSIMDf(tb[0].x, tb[0].y, tb[0].z)); + retval.T = float32_t3(tmp[0],tmp[1],tmp[2]); + tmp = rot.transformVect(core::vectorSIMDf(tb[1].x, tb[1].y, tb[1].z)); + retval.B = float32_t3(tmp[0],tmp[1],tmp[2]); +#else retval.T = tb[0]; retval.B = tb[1]; +#endif retval.alpha.x = rngUniformDist(retval.rng); retval.alpha.y = rngUniformDist(retval.rng); From 1ecd0c0489f93a410e56e97c04c0010fe2318a64 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 10 Jan 2025 12:01:13 +0700 Subject: [PATCH 56/83] use new sampling --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 121a30309..486a4115d 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -72,8 +72,8 @@ struct SBxDFTestResources retval.rng = nbl::hlsl::Xoroshiro64Star::construct(seed); retval.u = float32_t3(rngUniformDist(retval.rng), 0.0); - retval.V.direction = nbl::hlsl::normalize(projected_hemisphere_generate(rngUniformDist(retval.rng))); - retval.N = nbl::hlsl::normalize(projected_hemisphere_generate(rngUniformDist(retval.rng))); + retval.V.direction = nbl::hlsl::normalize(uniform_sphere_generate(rngUniformDist(retval.rng))); + retval.N = nbl::hlsl::normalize(uniform_sphere_generate(rngUniformDist(retval.rng))); float32_t2x3 tb = math::frisvad(retval.N); #ifndef __HLSL_VERSION From c9831413357b1616b58ba5f601668cb3b9eee8d3 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 10 Jan 2025 15:35:58 +0700 Subject: [PATCH 57/83] hash to uint2 seed --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 51 +++++++++++------------ 66_HLSLBxDFTests/main.cpp | 2 +- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 486a4115d..ea715a07e 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -22,6 +22,18 @@ using iso_cache = bxdf::SIsotropicMicrofacetCache; using aniso_cache = bxdf::SAnisotropicMicrofacetCache; using quotient_pdf_t = bxdf::quotient_and_pdf; +uint32_t pcg_hash(uint32_t v) +{ + uint32_t state = v * 747796405u + 2891336453u; + uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +uint32_t2 pcg2d_hash(uint32_t v) +{ + return uint32_t2(pcg_hash(v), pcg_hash(v+1)); +} + namespace impl { @@ -68,7 +80,6 @@ struct SBxDFTestResources static SBxDFTestResources create(uint32_t2 seed) { SBxDFTestResources retval; - retval.rng = nbl::hlsl::Xoroshiro64Star::construct(seed); retval.u = float32_t3(rngUniformDist(retval.rng), 0.0); @@ -92,24 +103,12 @@ struct SBxDFTestResources retval.alpha.x = rngUniformDist(retval.rng); retval.alpha.y = rngUniformDist(retval.rng); - retval.eta = 1.3;// rngFloat01(retval.rng) + 1.0; - retval.ior = float32_t3x2(1.02, 1.0, // randomize at some point? - 1.3, 2.0, - 1.02, 1.0); - retval.eta2 = float32_t3(1.02, 1.3, 1.02); // TODO: check correctness? + retval.eta = 1.3; + retval.ior = float32_t2(1.3, 2.0); retval.luma_coeff = float32_t3(0.2126, 0.7152, 0.0722); // luma coefficients for Rec. 709 return retval; } - ray_dir_info_t dV(int axis) - { - float32_t3 d = (float32_t3)0.0; - d[axis] += h; - ray_dir_info_t retval; - retval.direction = V.direction + d; - return retval; - } - float h = 0.001; nbl::hlsl::Xoroshiro64Star rng; @@ -121,9 +120,7 @@ struct SBxDFTestResources float32_t3 u; float32_t2 alpha; float eta; - float32_t3x2 ior; - - float32_t3 eta2; // what is this? + float32_t2 ior; float32_t3 luma_coeff; }; @@ -195,14 +192,14 @@ struct TestBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); + base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,rc.alpha.y,float32_t3x2(rc.ior,rc.ior,rc.ior)); #ifndef __HLSL_VERSION base_t::meta.bxdfName = "BeckmannBRDF Aniso"; #endif } else { - base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,rc.ior); + base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,float32_t3x2(rc.ior,rc.ior,rc.ior)); #ifndef __HLSL_VERSION base_t::meta.bxdfName = "BeckmannBRDF"; #endif @@ -220,14 +217,14 @@ struct TestBxDF> : { if (aniso) { - base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.alpha.y,rc.ior); + base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.alpha.y,float32_t3x2(rc.ior,rc.ior,rc.ior)); #ifndef __HLSL_VERSION base_t::meta.bxdfName = "GGXBRDF Aniso"; #endif } else { - base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.ior); + base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,float32_t3x2(rc.ior,rc.ior,rc.ior)); #ifndef __HLSL_VERSION base_t::meta.bxdfName = "GGXBRDF"; #endif @@ -256,7 +253,7 @@ struct TestBxDF::create(rc.eta2,rc.luma_coeff); + base_t::bxdf = bxdf::transmission::SSmoothDielectricBxDF::create(float32_t3(rc.eta * rc.eta),rc.luma_coeff); #ifndef __HLSL_VERSION base_t::meta.bxdfName = "ThinSmoothDielectricBSDF"; #endif @@ -415,13 +412,15 @@ struct TestUOffset : TestBxDF float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); float det = nbl::hlsl::determinant(m); - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL) * 0.5); + return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL)); } - static STestMeta run(uint32_t2 seed) + static STestMeta run(uint32_t seed) { + uint32_t2 state = pcg2d_hash(seed); + this_t t; - t.init(seed); + t.init(state); if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v || is_microfacet_bsdf_v) t.template initBxDF(t.rc); else diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index eff279244..1f47b947f 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -25,7 +25,7 @@ int main(int argc, char** argv) using bool32_t4 = vector; - const uint32_t2 state = uint32_t2(10u, 42u); // (12u, 69u) + const uint32_t state = 69u; // test u offset, 2 axis printResult((TestUOffset>::run(state))); From c02c9f0d17af287f417a2ec1ab18e9cab4ec126f Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 10 Jan 2025 16:27:25 +0700 Subject: [PATCH 58/83] use glm quaternions instead --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index ea715a07e..27aebd7b8 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -9,6 +9,10 @@ #include "nbl/builtin/hlsl/bxdf/reflection.hlsl" #include "nbl/builtin/hlsl/bxdf/transmission.hlsl" +#ifndef __HLSL_VERSION +#include +#endif + namespace nbl { namespace hlsl @@ -88,14 +92,10 @@ struct SBxDFTestResources float32_t2x3 tb = math::frisvad(retval.N); #ifndef __HLSL_VERSION - core::quaternion rot; - float angle = 2 * numbers::pi * rngUniformDist(retval.rng); - core::vectorSIMDf N = core::vectorSIMDf(retval.N.x, retval.N.y, retval.N.z); - rot.toAngleAxis(angle, N); - core::vectorSIMDf tmp = rot.transformVect(core::vectorSIMDf(tb[0].x, tb[0].y, tb[0].z)); - retval.T = float32_t3(tmp[0],tmp[1],tmp[2]); - tmp = rot.transformVect(core::vectorSIMDf(tb[1].x, tb[1].y, tb[1].z)); - retval.B = float32_t3(tmp[0],tmp[1],tmp[2]); + const float angle = 2 * numbers::pi * rngUniformDist(retval.rng); + glm::quat rot = glm::angleAxis(angle, retval.N); + retval.T = rot * tb[0]; + retval.B = rot * tb[1]; #else retval.T = tb[0]; retval.B = tb[1]; From 0c3d657ae810fd908455730cdba6b16332cab0b7 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 13 Jan 2025 12:03:20 +0700 Subject: [PATCH 59/83] callbacks on detect error --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 106 +++++++++------------- 66_HLSLBxDFTests/main.cpp | 83 ++++++++++++----- 2 files changed, 103 insertions(+), 86 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 27aebd7b8..d1780f85d 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -26,6 +26,8 @@ using iso_cache = bxdf::SIsotropicMicrofacetCache; using aniso_cache = bxdf::SAnisotropicMicrofacetCache; using quotient_pdf_t = bxdf::quotient_and_pdf; +using bool32_t3 = vector; + uint32_t pcg_hash(uint32_t v) { uint32_t state = v * 747796405u + 2891336453u; @@ -124,13 +126,19 @@ struct SBxDFTestResources float32_t3 luma_coeff; }; -struct STestMeta +enum ErrorType : uint32_t { - float32_t4 result; -#ifndef __HLSL_VERSION - std::string bxdfName; - std::string testName; -#endif + NEGATIVE_VAL = 0, // pdf/quotient/eval < 0 + PDF_ZERO, // pdf = 0 + QUOTIENT_INF, // quotient -> inf + JACOBIAN, + PDF_EVAL_DIFF, + RECIPROCITY +}; + +struct FailureCallback +{ + void __call(ErrorType error, NBL_CONST_REF_ARG(SBxDFTestResources) failedFor, NBL_CONST_REF_ARG(sample_t) failedAt) {} }; template @@ -149,8 +157,6 @@ struct TestBase iso_interaction isointer; aniso_interaction anisointer; - - STestMeta meta; }; @@ -162,9 +168,6 @@ struct TestBxDF : TestBase void initBxDF(SBxDFTestResources _rc) { base_t::bxdf = BxDF::create(); // default to lambertian bxdf -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "LambertianBxDF"; -#endif } }; @@ -176,9 +179,6 @@ struct TestBxDF::create(_rc.alpha.x); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "OrenNayarBRDF"; -#endif } }; @@ -193,16 +193,10 @@ struct TestBxDF::create(rc.alpha.x,rc.alpha.y,float32_t3x2(rc.ior,rc.ior,rc.ior)); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "BeckmannBRDF Aniso"; -#endif } else { base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,float32_t3x2(rc.ior,rc.ior,rc.ior)); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "BeckmannBRDF"; -#endif } } }; @@ -218,16 +212,10 @@ struct TestBxDF> : if (aniso) { base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.alpha.y,float32_t3x2(rc.ior,rc.ior,rc.ior)); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "GGXBRDF Aniso"; -#endif } else { base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,float32_t3x2(rc.ior,rc.ior,rc.ior)); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "GGXBRDF"; -#endif } } }; @@ -240,9 +228,6 @@ struct TestBxDF::create(rc.eta); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "SmoothDielectricBSDF"; -#endif } }; @@ -254,9 +239,6 @@ struct TestBxDF::create(float32_t3(rc.eta * rc.eta),rc.luma_coeff); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "ThinSmoothDielectricBSDF"; -#endif } }; @@ -271,16 +253,10 @@ struct TestBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "BeckmannBSDF Aniso"; -#endif } else { base_t::bxdf = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "BeckmannBSDF"; -#endif } } }; @@ -296,16 +272,10 @@ struct TestBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "GGXBSDF Aniso"; -#endif } else { base_t::bxdf = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x); -#ifndef __HLSL_VERSION - base_t::meta.bxdfName = "GGXBSDF"; -#endif } } }; @@ -352,70 +322,83 @@ struct TestUOffset : TestBxDF using base_t = TestBase; using this_t = TestUOffset; - float32_t4 test() + bool test(NBL_CONST_REF_ARG(FailureCallback) cb) { sample_t s, sx, sy; quotient_pdf_t pdf; - float32_t3 brdf; + float32_t3 bsdf; aniso_cache cache, dummy; + float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); + float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); + if NBL_CONSTEXPR_FUNC (is_basic_brdf_v) { s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy); - sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(base_t::rc.h,0)); - sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(0,base_t::rc.h)); + sx = base_t::bxdf.generate(base_t::anisointer, ux.xy); + sy = base_t::bxdf.generate(base_t::anisointer, uy.xy); } if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v) { s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy, cache); - sx = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(base_t::rc.h,0), dummy); - sy = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u.xy + float32_t2(0,base_t::rc.h), dummy); + sx = base_t::bxdf.generate(base_t::anisointer, ux.xy, dummy); + sy = base_t::bxdf.generate(base_t::anisointer, uy.xy, dummy); } if NBL_CONSTEXPR_FUNC (is_basic_bsdf_v) { s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u); - float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); sx = base_t::bxdf.generate(base_t::anisointer, ux); - float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); sy = base_t::bxdf.generate(base_t::anisointer, uy); } if NBL_CONSTEXPR_FUNC (is_microfacet_bsdf_v) { s = base_t::bxdf.generate(base_t::anisointer, base_t::rc.u, cache); - float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); sx = base_t::bxdf.generate(base_t::anisointer, ux, dummy); - float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); sy = base_t::bxdf.generate(base_t::anisointer, uy, dummy); } if NBL_CONSTEXPR_FUNC (is_basic_brdf_v || is_basic_bsdf_v) { pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); + bsdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer)); } if NBL_CONSTEXPR_FUNC (is_microfacet_brdf_v || is_microfacet_bsdf_v) { if NBL_CONSTEXPR_FUNC (aniso) { pdf = base_t::bxdf.quotient_and_pdf(s, base_t::anisointer, cache); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); + bsdf = float32_t3(base_t::bxdf.eval(s, base_t::anisointer, cache)); } else { iso_cache isocache = (iso_cache)cache; pdf = base_t::bxdf.quotient_and_pdf(s, base_t::isointer, isocache); - brdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); + bsdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); } } + if (nbl::hlsl::abs(pdf.pdf) < 1e-3) + { + cb::__call(PDF_ZERO, base_t::rc, s); + return false; + } + // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); float det = nbl::hlsl::determinant(m); - return float32_t4(nbl::hlsl::abs(pdf.value() - brdf), nbl::hlsl::abs(det*pdf.pdf/s.NdotL)); + bool jacobian_test = nbl::hlsl::abs(det*pdf.pdf/s.NdotL) < 1e-3; + if (!jacobian_test) + cb::__call(JACOBIAN, base_t::rc, s); + + bool diff_test = nbl::hlsl::abs(pdf.value() - bsdf) < 1e-3; + if (!diff_test) + cb::__call(PDF_EVAL_DIFF, base_t::rc, s); + + return true; } - static STestMeta run(uint32_t seed) + static void run(uint32_t seed, NBL_CONST_REF_ARG(FailureCallback) cb) { uint32_t2 state = pcg2d_hash(seed); @@ -425,10 +408,7 @@ struct TestUOffset : TestBxDF t.template initBxDF(t.rc); else t.initBxDF(t.rc); - - t.meta.result = t.test(); - t.meta.testName = "u offset"; - return t.meta; + t.test(cb); } }; diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 1f47b947f..acde50b21 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -10,38 +10,75 @@ using namespace nbl::hlsl; #define ASSERT_ZERO(x) (assert(all((x.result) < float32_t4(1e-3)))); -void printResult(const STestMeta& m) +//void printResult(const STestMeta& m) +//{ +// std::cout << m.testName << " " << m.bxdfName << "\t" +// << m.result.x << " " +// << m.result.y << " " +// << m.result.z << " " +// << m.result.w << "\n"; +//} + +struct PrintFailureCallback : FailureCallback { - std::cout << m.testName << " " << m.bxdfName << "\t" - << m.result.x << " " - << m.result.y << " " - << m.result.z << " " - << m.result.w << "\n"; -} + void __call(ErrorType error, NBL_CONST_REF_ARG(SBxDFTestResources) failedFor, NBL_CONST_REF_ARG(sample_t) failedAt) + { + switch (error) + { + case NEGATIVE_VAL: + fprintf(stderr, "pdf/quotient/eval < 0\n"); + break; + case PDF_ZERO: + fprintf(stderr, "pdf = 0\n"); + break; + case QUOTIENT_INF: + fprintf(stderr, "quotient -> inf\n"); + break; + case JACOBIAN: + fprintf(stderr, "failed the jacobian * pdf test\n"); + break; + case PDF_EVAL_DIFF: + fprintf(stderr, "quotient * pdf - eval not 0\n"); + break; + case RECIPROCITY: + fprintf(stderr, "failed the reprocity test\n"); + break; + default: + fprintf(stderr, "unknown error\n"); + } + + for (volatile bool repeat = true; IsDebuggerPresent() && repeat; ) + { + repeat = false; + __debugbreak(); + //failedFor.test(failedAt); + } + } +}; int main(int argc, char** argv) { std::cout << std::fixed << std::setprecision(4); - using bool32_t4 = vector; - const uint32_t state = 69u; + PrintFailureCallback cb; + // test u offset, 2 axis - printResult((TestUOffset>::run(state))); - printResult((TestUOffset>::run(state))); - printResult(TestUOffset,false>::run(state)); - printResult((TestUOffset,true>::run(state))); - printResult(TestUOffset,false>::run(state)); - printResult((TestUOffset,true>::run(state))); - - printResult((TestUOffset>::run(state))); - //printResult(TestUOffset>::run(state)); - //printResult(TestUOffset>::run(state)); - printResult(TestUOffset,false>::run(state)); - printResult((TestUOffset,true>::run(state))); - printResult(TestUOffset,false>::run(state)); - printResult(TestUOffset,true>::run(state)); + TestUOffset>::run(state, cb); + TestUOffset>::run(state, cb); + TestUOffset,false>::run(state, cb); + TestUOffset,true>::run(state, cb); + TestUOffset,false>::run(state, cb); + TestUOffset,true>::run(state, cb); + + TestUOffset>::run(state, cb); + //TestUOffset>::run(state); + //TestUOffset>::run(state); + TestUOffset,false>::run(state, cb); + TestUOffset,true>::run(state, cb); + TestUOffset,false>::run(state, cb); + TestUOffset,true>::run(state, cb); return 0; } \ No newline at end of file From 01d479934d53ed3637bee4b756a9faaa97fe1f7d Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 13 Jan 2025 15:09:44 +0700 Subject: [PATCH 60/83] fix callback usage bugs --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 23 ++++++++++++++++------- 66_HLSLBxDFTests/main.cpp | 15 ++------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index d1780f85d..6bada8d87 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -138,7 +138,7 @@ enum ErrorType : uint32_t struct FailureCallback { - void __call(ErrorType error, NBL_CONST_REF_ARG(SBxDFTestResources) failedFor, NBL_CONST_REF_ARG(sample_t) failedAt) {} + virtual void __call(ErrorType error, NBL_CONST_REF_ARG(SBxDFTestResources) failedFor, NBL_CONST_REF_ARG(sample_t) failedAt) NBL_CONST_MEMBER_FUNC {} }; template @@ -377,23 +377,32 @@ struct TestUOffset : TestBxDF } } - if (nbl::hlsl::abs(pdf.pdf) < 1e-3) + if (nbl::hlsl::abs(pdf.pdf) < 1e-3) // something generated cannot have 0 probability of getting generated { - cb::__call(PDF_ZERO, base_t::rc, s); + cb.__call(PDF_ZERO, base_t::rc, s); return false; } + if (!all(pdf.quotient < (float32_t3)numeric_limits::infinity)) // importance sampler's job to prevent inf + { + cb.__call(QUOTIENT_INF, base_t::rc, s); + return false; + } + + if (all(nbl::hlsl::abs(bsdf) < (float32_t3)1e-3) || all(pdf.quotient < (float32_t3)1e-3)) + return true; // produces an "impossible" sample + // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); float det = nbl::hlsl::determinant(m); bool jacobian_test = nbl::hlsl::abs(det*pdf.pdf/s.NdotL) < 1e-3; if (!jacobian_test) - cb::__call(JACOBIAN, base_t::rc, s); + cb.__call(JACOBIAN, base_t::rc, s); - bool diff_test = nbl::hlsl::abs(pdf.value() - bsdf) < 1e-3; - if (!diff_test) - cb::__call(PDF_EVAL_DIFF, base_t::rc, s); + bool32_t3 diff_test = nbl::hlsl::abs(pdf.value() - bsdf) < (float32_t3)1e-3; + if (!all(diff_test)) + cb.__call(PDF_EVAL_DIFF, base_t::rc, s); return true; } diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index acde50b21..3cf7f926d 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -8,20 +8,9 @@ using namespace nbl::hlsl; #include "app_resources/tests.hlsl" -#define ASSERT_ZERO(x) (assert(all((x.result) < float32_t4(1e-3)))); - -//void printResult(const STestMeta& m) -//{ -// std::cout << m.testName << " " << m.bxdfName << "\t" -// << m.result.x << " " -// << m.result.y << " " -// << m.result.z << " " -// << m.result.w << "\n"; -//} - struct PrintFailureCallback : FailureCallback { - void __call(ErrorType error, NBL_CONST_REF_ARG(SBxDFTestResources) failedFor, NBL_CONST_REF_ARG(sample_t) failedAt) + void __call(ErrorType error, NBL_CONST_REF_ARG(SBxDFTestResources) failedFor, NBL_CONST_REF_ARG(sample_t) failedAt) NBL_CONST_MEMBER_FUNC override { switch (error) { @@ -51,7 +40,7 @@ struct PrintFailureCallback : FailureCallback { repeat = false; __debugbreak(); - //failedFor.test(failedAt); + //failedFor.test(failedAt); // TODO: repeat test case } } }; From 887c3a0130dcc8b158abd27821e09b86d19aa2a8 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 13 Jan 2025 16:53:16 +0700 Subject: [PATCH 61/83] changed ior, spectral_type usage in bxdf --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 69 ++++++++++++----------- 66_HLSLBxDFTests/main.cpp | 26 ++++----- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 6bada8d87..572c2809a 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -25,6 +25,7 @@ using sample_t = bxdf::SLightSample; using iso_cache = bxdf::SIsotropicMicrofacetCache; using aniso_cache = bxdf::SAnisotropicMicrofacetCache; using quotient_pdf_t = bxdf::quotient_and_pdf; +using spectral_t = vector; using bool32_t3 = vector; @@ -172,110 +173,110 @@ struct TestBxDF : TestBase }; template<> -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBase> { - using base_t = TestBase>; + using base_t = TestBase>; void initBxDF(SBxDFTestResources _rc) { - base_t::bxdf = bxdf::reflection::SOrenNayarBxDF::create(_rc.alpha.x); + base_t::bxdf = bxdf::reflection::SOrenNayarBxDF::create(_rc.alpha.x); } }; template<> -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBase> { - using base_t = TestBase>; + using base_t = TestBase>; template void initBxDF(SBxDFTestResources _rc) { if (aniso) { - base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,rc.alpha.y,float32_t3x2(rc.ior,rc.ior,rc.ior)); + base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,rc.alpha.y,(float32_t3)(rc.ior.x),(float32_t3)(rc.ior.y)); } else { - base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,float32_t3x2(rc.ior,rc.ior,rc.ior)); + base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,(float32_t3)(rc.ior.x),(float32_t3)(rc.ior.y)); } } }; template<> -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBase> { - using base_t = TestBase>; + using base_t = TestBase>; template void initBxDF(SBxDFTestResources _rc) { if (aniso) { - base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.alpha.y,float32_t3x2(rc.ior,rc.ior,rc.ior)); + base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,rc.alpha.y,(float32_t3)(rc.ior.x),(float32_t3)(rc.ior.y)); } else { - base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,float32_t3x2(rc.ior,rc.ior,rc.ior)); + base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,(float32_t3)(rc.ior.x),(float32_t3)(rc.ior.y)); } } }; template<> -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBase> { - using base_t = TestBase>; + using base_t = TestBase>; void initBxDF(SBxDFTestResources _rc) { - base_t::bxdf = bxdf::transmission::SSmoothDielectricBxDF::create(rc.eta); + base_t::bxdf = bxdf::transmission::SSmoothDielectricBxDF::create(rc.eta); } }; template<> -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBase> { - using base_t = TestBase>; + using base_t = TestBase>; void initBxDF(SBxDFTestResources _rc) { - base_t::bxdf = bxdf::transmission::SSmoothDielectricBxDF::create(float32_t3(rc.eta * rc.eta),rc.luma_coeff); + base_t::bxdf = bxdf::transmission::SSmoothDielectricBxDF::create(float32_t3(rc.eta * rc.eta),rc.luma_coeff); } }; template<> -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBase> { - using base_t = TestBase>; + using base_t = TestBase>; template void initBxDF(SBxDFTestResources _rc) { if (aniso) { - base_t::bxdf = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); + base_t::bxdf = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); } else { - base_t::bxdf = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x); + base_t::bxdf = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x); } } }; template<> -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBase> { - using base_t = TestBase>; + using base_t = TestBase>; template void initBxDF(SBxDFTestResources _rc) { if (aniso) { - base_t::bxdf = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); + base_t::bxdf = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); } else { - base_t::bxdf = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x); + base_t::bxdf = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x); } } }; @@ -283,27 +284,27 @@ struct TestBxDF struct is_basic_brdf : bool_constant< - is_same>::value || - is_same>::value + is_same>::value || + is_same>::value > {}; template struct is_microfacet_brdf : bool_constant< - is_same>::value || - is_same>::value + is_same>::value || + is_same>::value > {}; template struct is_basic_bsdf : bool_constant< - is_same>::value || - is_same>::value || - is_same>::value + is_same>::value || + is_same>::value || + is_same>::value > {}; template struct is_microfacet_bsdf : bool_constant< - is_same>::value || - is_same>::value + is_same>::value || + is_same>::value > {}; template diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index 3cf7f926d..b5b6d574b 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -54,20 +54,20 @@ int main(int argc, char** argv) PrintFailureCallback cb; // test u offset, 2 axis - TestUOffset>::run(state, cb); - TestUOffset>::run(state, cb); - TestUOffset,false>::run(state, cb); - TestUOffset,true>::run(state, cb); - TestUOffset,false>::run(state, cb); - TestUOffset,true>::run(state, cb); + TestUOffset>::run(state, cb); + TestUOffset>::run(state, cb); + TestUOffset,false>::run(state, cb); + TestUOffset,true>::run(state, cb); + TestUOffset,false>::run(state, cb); + TestUOffset,true>::run(state, cb); - TestUOffset>::run(state, cb); - //TestUOffset>::run(state); - //TestUOffset>::run(state); - TestUOffset,false>::run(state, cb); - TestUOffset,true>::run(state, cb); - TestUOffset,false>::run(state, cb); - TestUOffset,true>::run(state, cb); + TestUOffset>::run(state, cb); + //TestUOffset>::run(state); + //TestUOffset>::run(state); + TestUOffset,false>::run(state, cb); + TestUOffset,true>::run(state, cb); + TestUOffset,false>::run(state, cb); + TestUOffset,true>::run(state, cb); return 0; } \ No newline at end of file From 9ab4e8e4126dbde0266cba4f32578be5d4d8a966 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 14 Jan 2025 10:55:02 +0700 Subject: [PATCH 62/83] use new pcg hlsl --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 572c2809a..f8761d8b0 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -4,6 +4,7 @@ #include "nbl/builtin/hlsl/cpp_compat.hlsl" #include "nbl/builtin/hlsl/random/xoroshiro.hlsl" +#include "nbl/builtin/hlsl/random/pcg.hlsl" #include "nbl/builtin/hlsl/sampling/uniform.hlsl" #include "nbl/builtin/hlsl/bxdf/common.hlsl" #include "nbl/builtin/hlsl/bxdf/reflection.hlsl" @@ -29,17 +30,17 @@ using spectral_t = vector; using bool32_t3 = vector; -uint32_t pcg_hash(uint32_t v) -{ - uint32_t state = v * 747796405u + 2891336453u; - uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; - return (word >> 22u) ^ word; -} +// uint32_t pcg_hash(uint32_t v) +// { +// uint32_t state = v * 747796405u + 2891336453u; +// uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; +// return (word >> 22u) ^ word; +// } -uint32_t2 pcg2d_hash(uint32_t v) -{ - return uint32_t2(pcg_hash(v), pcg_hash(v+1)); -} +// uint32_t2 pcg2d_hash(uint32_t v) +// { +// return uint32_t2(pcg_hash(v), pcg_hash(v+1)); +// } namespace impl { @@ -410,7 +411,7 @@ struct TestUOffset : TestBxDF static void run(uint32_t seed, NBL_CONST_REF_ARG(FailureCallback) cb) { - uint32_t2 state = pcg2d_hash(seed); + uint32_t2 state = pcg32x2(seed); this_t t; t.init(state); From c8859c0c0439ca32de92aabc4a5c164c1d7e0df8 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 14 Jan 2025 15:39:07 +0700 Subject: [PATCH 63/83] callback reruns bxdf compute --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 110 ++++++++++++---------- 66_HLSLBxDFTests/main.cpp | 4 +- 2 files changed, 62 insertions(+), 52 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index f8761d8b0..41c480074 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -113,7 +113,8 @@ struct SBxDFTestResources return retval; } - float h = 0.001; + // epsilon + float eps = 1e-2; nbl::hlsl::Xoroshiro64Star rng; ray_dir_info_t V; @@ -130,7 +131,8 @@ struct SBxDFTestResources enum ErrorType : uint32_t { - NEGATIVE_VAL = 0, // pdf/quotient/eval < 0 + NOERR = 0, + NEGATIVE_VAL, // pdf/quotient/eval < 0 PDF_ZERO, // pdf = 0 QUOTIENT_INF, // quotient -> inf JACOBIAN, @@ -138,12 +140,6 @@ enum ErrorType : uint32_t RECIPROCITY }; -struct FailureCallback -{ - virtual void __call(ErrorType error, NBL_CONST_REF_ARG(SBxDFTestResources) failedFor, NBL_CONST_REF_ARG(sample_t) failedAt) NBL_CONST_MEMBER_FUNC {} -}; - -template struct TestBase { void init(uint32_t2 seed) @@ -154,18 +150,29 @@ struct TestBase anisointer = aniso_interaction::create(isointer, rc.T, rc.B); } + virtual void compute() {} + SBxDFTestResources rc; - BxDF bxdf; iso_interaction isointer; aniso_interaction anisointer; }; +struct FailureCallback +{ + virtual void __call(ErrorType error, NBL_REF_ARG(TestBase) failedFor) {} +}; + +template +struct TestBxDFBase : TestBase +{ + BxDF bxdf; +}; template -struct TestBxDF : TestBase +struct TestBxDF : TestBxDFBase { - using base_t = TestBase; + using base_t = TestBxDFBase; void initBxDF(SBxDFTestResources _rc) { @@ -174,9 +181,9 @@ struct TestBxDF : TestBase }; template<> -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBxDFBase> { - using base_t = TestBase>; + using base_t = TestBxDFBase>; void initBxDF(SBxDFTestResources _rc) { @@ -185,9 +192,9 @@ struct TestBxDF -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBxDFBase> { - using base_t = TestBase>; + using base_t = TestBxDFBase>; template void initBxDF(SBxDFTestResources _rc) @@ -204,9 +211,9 @@ struct TestBxDF -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBxDFBase> { - using base_t = TestBase>; + using base_t = TestBxDFBase>; template void initBxDF(SBxDFTestResources _rc) @@ -223,9 +230,9 @@ struct TestBxDF -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBxDFBase> { - using base_t = TestBase>; + using base_t = TestBxDFBase>; void initBxDF(SBxDFTestResources _rc) { @@ -234,9 +241,9 @@ struct TestBxDF -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBxDFBase> { - using base_t = TestBase>; + using base_t = TestBxDFBase>; void initBxDF(SBxDFTestResources _rc) { @@ -245,9 +252,9 @@ struct TestBxDF -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBxDFBase> { - using base_t = TestBase>; + using base_t = TestBxDFBase>; template void initBxDF(SBxDFTestResources _rc) @@ -264,9 +271,9 @@ struct TestBxDF -struct TestBxDF> : TestBase> +struct TestBxDF> : TestBxDFBase> { - using base_t = TestBase>; + using base_t = TestBxDFBase>; template void initBxDF(SBxDFTestResources _rc) @@ -321,18 +328,15 @@ NBL_CONSTEXPR bool is_microfacet_bsdf_v = is_microfacet_bsdf::value; template struct TestUOffset : TestBxDF { - using base_t = TestBase; + using base_t = TestBxDFBase; using this_t = TestUOffset; - bool test(NBL_CONST_REF_ARG(FailureCallback) cb) + void compute() override { - sample_t s, sx, sy; - quotient_pdf_t pdf; - float32_t3 bsdf; aniso_cache cache, dummy; - float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.h,0,0); - float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.h,0); + float32_t3 ux = base_t::rc.u + float32_t3(base_t::rc.eps,0,0); + float32_t3 uy = base_t::rc.u + float32_t3(0,base_t::rc.eps,0); if NBL_CONSTEXPR_FUNC (is_basic_brdf_v) { @@ -378,38 +382,37 @@ struct TestUOffset : TestBxDF bsdf = float32_t3(base_t::bxdf.eval(s, base_t::isointer, isocache)); } } + } - if (nbl::hlsl::abs(pdf.pdf) < 1e-3) // something generated cannot have 0 probability of getting generated - { - cb.__call(PDF_ZERO, base_t::rc, s); - return false; - } + ErrorType test() + { + compute(); + + if (nbl::hlsl::abs(pdf.pdf) < base_t::rc.eps) // something generated cannot have 0 probability of getting generated + return PDF_ZERO; if (!all(pdf.quotient < (float32_t3)numeric_limits::infinity)) // importance sampler's job to prevent inf - { - cb.__call(QUOTIENT_INF, base_t::rc, s); - return false; - } + return QUOTIENT_INF; - if (all(nbl::hlsl::abs(bsdf) < (float32_t3)1e-3) || all(pdf.quotient < (float32_t3)1e-3)) - return true; // produces an "impossible" sample + if (all(nbl::hlsl::abs(bsdf) < (float32_t3)base_t::rc.eps) || all(pdf.quotient < (float32_t3)base_t::rc.eps)) + return NOERR; // produces an "impossible" sample // get jacobian float32_t2x2 m = float32_t2x2(sx.TdotL - s.TdotL, sy.TdotL - s.TdotL, sx.BdotL - s.BdotL, sy.BdotL - s.BdotL); float det = nbl::hlsl::determinant(m); - bool jacobian_test = nbl::hlsl::abs(det*pdf.pdf/s.NdotL) < 1e-3; + bool jacobian_test = nbl::hlsl::abs(det*pdf.pdf/s.NdotL) < base_t::rc.eps; if (!jacobian_test) - cb.__call(JACOBIAN, base_t::rc, s); + return JACOBIAN; - bool32_t3 diff_test = nbl::hlsl::abs(pdf.value() - bsdf) < (float32_t3)1e-3; + bool32_t3 diff_test = nbl::hlsl::max(pdf.value() / bsdf, bsdf / pdf.value()) <= (float32_t3)(1 + base_t::rc.eps); if (!all(diff_test)) - cb.__call(PDF_EVAL_DIFF, base_t::rc, s); + return PDF_EVAL_DIFF; - return true; + return NOERR; } - static void run(uint32_t seed, NBL_CONST_REF_ARG(FailureCallback) cb) + static void run(uint32_t seed, NBL_REF_ARG(FailureCallback) cb) { uint32_t2 state = pcg32x2(seed); @@ -419,8 +422,15 @@ struct TestUOffset : TestBxDF t.template initBxDF(t.rc); else t.initBxDF(t.rc); - t.test(cb); + + ErrorType e = t.test(); + if (e != NOERR) + cb.__call(e, t); } + + sample_t s, sx, sy; + quotient_pdf_t pdf; + float32_t3 bsdf; }; } diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index b5b6d574b..d5792e107 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -10,7 +10,7 @@ using namespace nbl::hlsl; struct PrintFailureCallback : FailureCallback { - void __call(ErrorType error, NBL_CONST_REF_ARG(SBxDFTestResources) failedFor, NBL_CONST_REF_ARG(sample_t) failedAt) NBL_CONST_MEMBER_FUNC override + void __call(ErrorType error, NBL_REF_ARG(TestBase) failedFor) override { switch (error) { @@ -40,7 +40,7 @@ struct PrintFailureCallback : FailureCallback { repeat = false; __debugbreak(); - //failedFor.test(failedAt); // TODO: repeat test case + failedFor.compute(); } } }; From 414f9611333d447bcd340ad4408495f3bdd365a9 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 14 Jan 2025 16:13:11 +0700 Subject: [PATCH 64/83] added bxdf names for debugging --- 66_HLSLBxDFTests/app_resources/tests.hlsl | 42 ++++++++++++++++++++++- 66_HLSLBxDFTests/main.cpp | 14 ++++---- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/66_HLSLBxDFTests/app_resources/tests.hlsl b/66_HLSLBxDFTests/app_resources/tests.hlsl index 41c480074..256ed3ce9 100644 --- a/66_HLSLBxDFTests/app_resources/tests.hlsl +++ b/66_HLSLBxDFTests/app_resources/tests.hlsl @@ -114,7 +114,7 @@ struct SBxDFTestResources } // epsilon - float eps = 1e-2; + float eps = 1e-3; nbl::hlsl::Xoroshiro64Star rng; ray_dir_info_t V; @@ -156,6 +156,10 @@ struct TestBase iso_interaction isointer; aniso_interaction anisointer; + +#ifndef __HLSL_VERSION + std::string name = "base"; +#endif }; struct FailureCallback @@ -177,6 +181,9 @@ struct TestBxDF : TestBxDFBase void initBxDF(SBxDFTestResources _rc) { base_t::bxdf = BxDF::create(); // default to lambertian bxdf +#ifndef __HLSL_VERSION + base_t::name = "Lambertian BxDF"; +#endif } }; @@ -188,6 +195,9 @@ struct TestBxDF::create(_rc.alpha.x); +#ifndef __HLSL_VERSION + base_t::name = "OrenNayar BRDF"; +#endif } }; @@ -202,10 +212,16 @@ struct TestBxDF::create(rc.alpha.x,rc.alpha.y,(float32_t3)(rc.ior.x),(float32_t3)(rc.ior.y)); +#ifndef __HLSL_VERSION + base_t::name = "Beckmann Aniso BRDF"; +#endif } else { base_t::bxdf = bxdf::reflection::SBeckmannBxDF::create(rc.alpha.x,(float32_t3)(rc.ior.x),(float32_t3)(rc.ior.y)); +#ifndef __HLSL_VERSION + base_t::name = "Beckmann BRDF"; +#endif } } }; @@ -221,10 +237,16 @@ struct TestBxDF::create(rc.alpha.x,rc.alpha.y,(float32_t3)(rc.ior.x),(float32_t3)(rc.ior.y)); +#ifndef __HLSL_VERSION + base_t::name = "GGX Aniso BRDF"; +#endif } else { base_t::bxdf = bxdf::reflection::SGGXBxDF::create(rc.alpha.x,(float32_t3)(rc.ior.x),(float32_t3)(rc.ior.y)); +#ifndef __HLSL_VERSION + base_t::name = "GGX BRDF"; +#endif } } }; @@ -237,6 +259,9 @@ struct TestBxDF::create(rc.eta); +#ifndef __HLSL_VERSION + base_t::name = "Smooth dielectric BSDF"; +#endif } }; @@ -248,6 +273,9 @@ struct TestBxDF::create(float32_t3(rc.eta * rc.eta),rc.luma_coeff); +#ifndef __HLSL_VERSION + base_t::name = "Thin smooth dielectric BSDF"; +#endif } }; @@ -262,10 +290,16 @@ struct TestBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); +#ifndef __HLSL_VERSION + base_t::name = "Beckmann Dielectric Aniso BSDF"; +#endif } else { base_t::bxdf = bxdf::transmission::SBeckmannDielectricBxDF::create(rc.eta,rc.alpha.x); +#ifndef __HLSL_VERSION + base_t::name = "Beckmann Dielectric BSDF"; +#endif } } }; @@ -281,10 +315,16 @@ struct TestBxDF::create(rc.eta,rc.alpha.x,rc.alpha.y); +#ifndef __HLSL_VERSION + base_t::name = "GGX Dielectric Aniso BSDF"; +#endif } else { base_t::bxdf = bxdf::transmission::SGGXDielectricBxDF::create(rc.eta,rc.alpha.x); +#ifndef __HLSL_VERSION + base_t::name = "GGX Dielectric BSDF"; +#endif } } }; diff --git a/66_HLSLBxDFTests/main.cpp b/66_HLSLBxDFTests/main.cpp index d5792e107..f91ed5f02 100644 --- a/66_HLSLBxDFTests/main.cpp +++ b/66_HLSLBxDFTests/main.cpp @@ -15,25 +15,25 @@ struct PrintFailureCallback : FailureCallback switch (error) { case NEGATIVE_VAL: - fprintf(stderr, "pdf/quotient/eval < 0\n"); + fprintf(stderr, "%s pdf/quotient/eval < 0\n", failedFor.name.c_str()); break; case PDF_ZERO: - fprintf(stderr, "pdf = 0\n"); + fprintf(stderr, "%s pdf = 0\n", failedFor.name.c_str()); break; case QUOTIENT_INF: - fprintf(stderr, "quotient -> inf\n"); + fprintf(stderr, "%s quotient -> inf\n", failedFor.name.c_str()); break; case JACOBIAN: - fprintf(stderr, "failed the jacobian * pdf test\n"); + fprintf(stderr, "%s failed the jacobian * pdf test\n", failedFor.name.c_str()); break; case PDF_EVAL_DIFF: - fprintf(stderr, "quotient * pdf - eval not 0\n"); + fprintf(stderr, "%s quotient * pdf - eval not 0\n", failedFor.name.c_str()); break; case RECIPROCITY: - fprintf(stderr, "failed the reprocity test\n"); + fprintf(stderr, "%s failed the reprocity test\n", failedFor.name.c_str()); break; default: - fprintf(stderr, "unknown error\n"); + fprintf(stderr, "%s unknown error\n", failedFor.name.c_str()); } for (volatile bool repeat = true; IsDebuggerPresent() && repeat; ) From fe23efcf9aa1038915cac18a5b93554cc7e198c2 Mon Sep 17 00:00:00 2001 From: Przemek Date: Tue, 14 Jan 2025 14:46:55 +0100 Subject: [PATCH 65/83] Saving work --- 62_CAD/main.cpp | 106 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/62_CAD/main.cpp b/62_CAD/main.cpp index 9f052b180..ea98f397e 100644 --- a/62_CAD/main.cpp +++ b/62_CAD/main.cpp @@ -33,6 +33,11 @@ using namespace video; #include +//TODO: remove +#include +#include +#include + #include #define BENCHMARK_TILL_FIRST_FRAME @@ -639,6 +644,107 @@ class ComputerAidedDesign final : public examples::SimpleWindowedApplication, pu inline bool onAppInitialized(smart_refctd_ptr&& system) override { + { + using ef64 = hlsl::emulated_float64_t; + using NormalVec = hlsl::vector; + using EmulatedVec = hlsl::emulated_vector_t3; + using NormalMatrix = hlsl::matrix; + using EmulatedMatrix = hlsl::emulated_matrix_t3x3; + + auto createNormalVec = [](float x, float y, float z) -> NormalVec + { + NormalVec output; + output.x = x; + output.y = y; + output.z = z; + + return output; + }; + auto createEmulatedVec = [](float x, float y, float z) -> EmulatedVec + { + EmulatedVec output; + output.x = hlsl::emulated_float64_t::create(x); + output.y = hlsl::emulated_float64_t::create(y); + output.z = hlsl::emulated_float64_t::create(z); + + return output; + }; + + auto createNormalMat = [](float a0, float a1, float a2, float b0, float b1, float b2, float c0, float c1, float c2) -> NormalMatrix + { + NormalMatrix output; + output[0][0] = a0; + output[0][1] = a1; + output[0][2] = a2; + + output[1][0] = b0; + output[1][1] = b1; + output[1][2] = b2; + + output[2][0] = c0; + output[2][1] = c1; + output[2][2] = c2; + + return output; + }; + + auto createEmulatedMat = [](float a0, float a1, float a2, float b0, float b1, float b2, float c0, float c1, float c2) -> EmulatedMatrix + { + EmulatedMatrix output; + output.rows[0].x = ef64::create(a0); + output.rows[0].y = ef64::create(a1); + output.rows[0].z = ef64::create(a2); + + output.rows[1].x = ef64::create(b0); + output.rows[1].y = ef64::create(b1); + output.rows[1].z = ef64::create(b2); + + output.rows[2].x = ef64::create(c0); + output.rows[2].y = ef64::create(c1); + output.rows[2].z = ef64::create(c2); + + return output; + }; + + { + /*NormalVec a = createNormalVec(1, 2, 3); + NormalVec b = createNormalVec(4, 5, 6); + + auto c = hlsl::findMSB(a); + __debugbreak();*/ + } + + { + /*EmulatedVec a = createEmulatedVec(1, 2, 3); + EmulatedVec b = createEmulatedVec(4, 5, 6); + + auto c = hlsl::findMSB(a); + __debugbreak();*/ + } + + { + /*NormalMatrix a = createNormalMat(1, 2, 3, 4, 5, 6, 7, 8, 9); + + hlsl::matrix_traits asdf; + + auto c = hlsl::determinant(a); + __debugbreak();*/ + } + + { + /*auto a = createEmulatedMat(1, 2, 3, 4, 5, 6, 7, 8, 9); + auto b = createEmulatedMat(10, 11, 12, 13, 14, 15, 16, 17, 18); + + auto c = nbl::hlsl::mul(a, b); + + NormalVec r0 = nbl::hlsl::_static_cast(c.rows[0]); + NormalVec r1 = nbl::hlsl::_static_cast(c.rows[1]); + NormalVec r2 = nbl::hlsl::_static_cast(c.rows[2]); + + __debugbreak();*/ + } + } + m_inputSystem = make_smart_refctd_ptr(logger_opt_smart_ptr(smart_refctd_ptr(m_logger))); // Remember to call the base class initialization! From 55362eb1da0c3dbfea48a9887efad5b3f995bf5c Mon Sep 17 00:00:00 2001 From: Przemek Date: Wed, 15 Jan 2025 13:25:55 +0100 Subject: [PATCH 66/83] Saving work --- 62_CAD/shaders/main_pipeline/vertex_shader.hlsl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/62_CAD/shaders/main_pipeline/vertex_shader.hlsl b/62_CAD/shaders/main_pipeline/vertex_shader.hlsl index 50d056eae..8651d7c2a 100644 --- a/62_CAD/shaders/main_pipeline/vertex_shader.hlsl +++ b/62_CAD/shaders/main_pipeline/vertex_shader.hlsl @@ -87,8 +87,11 @@ void dilateHatch(out float2 outOffsetVec, out float2 outUV, const float2 PSInput main(uint vertexID : SV_VertexID) { + float a = 0.0f; + float b = hlsl::cos(a); + const uint vertexIdx = vertexID & 0x3u; - const uint objectID = vertexID >> 2; + const uint objectID = (vertexID >> 2) * a; DrawObject drawObj = drawObjects[objectID]; From 138bd7fde9c47fdb7b9922c859433fd30c8ce77c Mon Sep 17 00:00:00 2001 From: Przemek Date: Sat, 18 Jan 2025 11:38:37 +0100 Subject: [PATCH 67/83] Adjustments --- 62_CAD/main.cpp | 101 ------------------------------------ 62_CAD/shaders/globals.hlsl | 10 ++-- 2 files changed, 5 insertions(+), 106 deletions(-) diff --git a/62_CAD/main.cpp b/62_CAD/main.cpp index ea98f397e..3a57355b4 100644 --- a/62_CAD/main.cpp +++ b/62_CAD/main.cpp @@ -644,107 +644,6 @@ class ComputerAidedDesign final : public examples::SimpleWindowedApplication, pu inline bool onAppInitialized(smart_refctd_ptr&& system) override { - { - using ef64 = hlsl::emulated_float64_t; - using NormalVec = hlsl::vector; - using EmulatedVec = hlsl::emulated_vector_t3; - using NormalMatrix = hlsl::matrix; - using EmulatedMatrix = hlsl::emulated_matrix_t3x3; - - auto createNormalVec = [](float x, float y, float z) -> NormalVec - { - NormalVec output; - output.x = x; - output.y = y; - output.z = z; - - return output; - }; - auto createEmulatedVec = [](float x, float y, float z) -> EmulatedVec - { - EmulatedVec output; - output.x = hlsl::emulated_float64_t::create(x); - output.y = hlsl::emulated_float64_t::create(y); - output.z = hlsl::emulated_float64_t::create(z); - - return output; - }; - - auto createNormalMat = [](float a0, float a1, float a2, float b0, float b1, float b2, float c0, float c1, float c2) -> NormalMatrix - { - NormalMatrix output; - output[0][0] = a0; - output[0][1] = a1; - output[0][2] = a2; - - output[1][0] = b0; - output[1][1] = b1; - output[1][2] = b2; - - output[2][0] = c0; - output[2][1] = c1; - output[2][2] = c2; - - return output; - }; - - auto createEmulatedMat = [](float a0, float a1, float a2, float b0, float b1, float b2, float c0, float c1, float c2) -> EmulatedMatrix - { - EmulatedMatrix output; - output.rows[0].x = ef64::create(a0); - output.rows[0].y = ef64::create(a1); - output.rows[0].z = ef64::create(a2); - - output.rows[1].x = ef64::create(b0); - output.rows[1].y = ef64::create(b1); - output.rows[1].z = ef64::create(b2); - - output.rows[2].x = ef64::create(c0); - output.rows[2].y = ef64::create(c1); - output.rows[2].z = ef64::create(c2); - - return output; - }; - - { - /*NormalVec a = createNormalVec(1, 2, 3); - NormalVec b = createNormalVec(4, 5, 6); - - auto c = hlsl::findMSB(a); - __debugbreak();*/ - } - - { - /*EmulatedVec a = createEmulatedVec(1, 2, 3); - EmulatedVec b = createEmulatedVec(4, 5, 6); - - auto c = hlsl::findMSB(a); - __debugbreak();*/ - } - - { - /*NormalMatrix a = createNormalMat(1, 2, 3, 4, 5, 6, 7, 8, 9); - - hlsl::matrix_traits asdf; - - auto c = hlsl::determinant(a); - __debugbreak();*/ - } - - { - /*auto a = createEmulatedMat(1, 2, 3, 4, 5, 6, 7, 8, 9); - auto b = createEmulatedMat(10, 11, 12, 13, 14, 15, 16, 17, 18); - - auto c = nbl::hlsl::mul(a, b); - - NormalVec r0 = nbl::hlsl::_static_cast(c.rows[0]); - NormalVec r1 = nbl::hlsl::_static_cast(c.rows[1]); - NormalVec r2 = nbl::hlsl::_static_cast(c.rows[2]); - - __debugbreak();*/ - } - } - m_inputSystem = make_smart_refctd_ptr(logger_opt_smart_ptr(smart_refctd_ptr(m_logger))); // Remember to call the base class initialization! diff --git a/62_CAD/shaders/globals.hlsl b/62_CAD/shaders/globals.hlsl index 94a24ff06..b96393866 100644 --- a/62_CAD/shaders/globals.hlsl +++ b/62_CAD/shaders/globals.hlsl @@ -172,8 +172,8 @@ struct GlyphInfo void packMinUV_TextureID(float32_t2 minUV, uint16_t textureId) { minUV_textureID_packed = textureId; - uint32_t uPacked = (uint32_t)(clamp(minUV.x, 0.0f, 1.0f) * 255.0f); - uint32_t vPacked = (uint32_t)(clamp(minUV.y, 0.0f, 1.0f) * 255.0f); + uint32_t uPacked = (uint32_t)(nbl::hlsl::clamp(minUV.x, 0.0f, 1.0f) * 255.0f); + uint32_t vPacked = (uint32_t)(nbl::hlsl::clamp(minUV.y, 0.0f, 1.0f) * 255.0f); minUV_textureID_packed = nbl::hlsl::glsl::bitfieldInsert(minUV_textureID_packed, uPacked, 16, 8); minUV_textureID_packed = nbl::hlsl::glsl::bitfieldInsert(minUV_textureID_packed, vPacked, 24, 8); } @@ -203,9 +203,9 @@ struct ImageObjectInfo static uint32_t packR11G11B10_UNORM(float32_t3 color) { // Scale and convert to integers - uint32_t r = (uint32_t)(clamp(color.r, 0.0f, 1.0f) * 2047.0f + 0.5f); // 11 bits -> 2^11 - 1 = 2047 - uint32_t g = (uint32_t)(clamp(color.g, 0.0f, 1.0f) * 2047.0f + 0.5f); // 11 bits -> 2^11 - 1 = 2047 - uint32_t b = (uint32_t)(clamp(color.b, 0.0f, 1.0f) * 1023.0f + 0.5f); // 10 bits -> 2^10 - 1 = 1023 + uint32_t r = (uint32_t)(nbl::hlsl::clamp(color.r, 0.0f, 1.0f) * 2047.0f + 0.5f); // 11 bits -> 2^11 - 1 = 2047 + uint32_t g = (uint32_t)(nbl::hlsl::clamp(color.g, 0.0f, 1.0f) * 2047.0f + 0.5f); // 11 bits -> 2^11 - 1 = 2047 + uint32_t b = (uint32_t)(nbl::hlsl::clamp(color.b, 0.0f, 1.0f) * 1023.0f + 0.5f); // 10 bits -> 2^10 - 1 = 1023 // Insert each component into the correct position uint32_t packed = r; // R: bits 0-10 From ae6e57006dbcbc26d03e8889467bce441f35e045 Mon Sep 17 00:00:00 2001 From: Przemek Date: Tue, 21 Jan 2025 20:13:44 +0100 Subject: [PATCH 68/83] Removed test code --- 62_CAD/shaders/main_pipeline/vertex_shader.hlsl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/62_CAD/shaders/main_pipeline/vertex_shader.hlsl b/62_CAD/shaders/main_pipeline/vertex_shader.hlsl index 8651d7c2a..50d056eae 100644 --- a/62_CAD/shaders/main_pipeline/vertex_shader.hlsl +++ b/62_CAD/shaders/main_pipeline/vertex_shader.hlsl @@ -87,11 +87,8 @@ void dilateHatch(out float2 outOffsetVec, out float2 outUV, const float2 PSInput main(uint vertexID : SV_VertexID) { - float a = 0.0f; - float b = hlsl::cos(a); - const uint vertexIdx = vertexID & 0x3u; - const uint objectID = (vertexID >> 2) * a; + const uint objectID = vertexID >> 2; DrawObject drawObj = drawObjects[objectID]; From 806b87947e7bdf1a44bd0542a2bcc89b12b31c7f Mon Sep 17 00:00:00 2001 From: Przemek Date: Wed, 22 Jan 2025 13:13:14 +0100 Subject: [PATCH 69/83] Removed `bitreverse.hlsl` references --- 28_FFTBloom/app_resources/fft_convolve_ifft.hlsl | 1 - 28_FFTBloom/app_resources/kernel_fft_second_axis.hlsl | 1 - 2 files changed, 2 deletions(-) diff --git a/28_FFTBloom/app_resources/fft_convolve_ifft.hlsl b/28_FFTBloom/app_resources/fft_convolve_ifft.hlsl index a43bcd4ba..b5abb48af 100644 --- a/28_FFTBloom/app_resources/fft_convolve_ifft.hlsl +++ b/28_FFTBloom/app_resources/fft_convolve_ifft.hlsl @@ -1,5 +1,4 @@ #include "fft_mirror_common.hlsl" -#include "nbl/builtin/hlsl/bitreverse.hlsl" [[vk::binding(3, 0)]] Texture2DArray kernelChannels; [[vk::binding(1, 0)]] SamplerState samplerState; diff --git a/28_FFTBloom/app_resources/kernel_fft_second_axis.hlsl b/28_FFTBloom/app_resources/kernel_fft_second_axis.hlsl index 9ffe71b31..d2ee2c8d1 100644 --- a/28_FFTBloom/app_resources/kernel_fft_second_axis.hlsl +++ b/28_FFTBloom/app_resources/kernel_fft_second_axis.hlsl @@ -1,6 +1,5 @@ #include "fft_mirror_common.hlsl" #include "nbl/builtin/hlsl/colorspace/encodeCIEXYZ.hlsl" -#include "nbl/builtin/hlsl/bitreverse.hlsl" [[vk::binding(2, 0)]] RWTexture2DArray kernelChannels; From daccef9201c48a1d4970406f73f3cc1ecfb1e046 Mon Sep 17 00:00:00 2001 From: Przemek Date: Wed, 22 Jan 2025 18:56:19 +0100 Subject: [PATCH 70/83] Implemented C++ side tgmath tests --- 22_CppCompat/app_resources/common.hlsl | 115 ++++++++++++++++- 22_CppCompat/main.cpp | 163 ++++++++++++++++++++++++- 2 files changed, 269 insertions(+), 9 deletions(-) diff --git a/22_CppCompat/app_resources/common.hlsl b/22_CppCompat/app_resources/common.hlsl index ca43b5afd..9336bc4bb 100644 --- a/22_CppCompat/app_resources/common.hlsl +++ b/22_CppCompat/app_resources/common.hlsl @@ -25,11 +25,118 @@ #include -#define DISABLE_TGMATH_TESTS -#ifndef DISABLE_TGMATH_TESTS -#include -#endif #include #include #include + +#include +#include + +// tmath.hlsl and intrinsics.hlsl tests + +using namespace nbl::hlsl; +struct TgmathIntputTestValues +{ + float floor; + float lerpX; + float lerpY; + float lerpA; + float isnan; + float isinf; + float powX; + float powY; + float exp; + float exp2; + float log; + float absF; + int absI; + float sqrt; + float sin; + float cos; + float acos; + + float32_t3 floorVec; + float32_t3 lerpXVec; + float32_t3 lerpYVec; + float32_t3 lerpAVec; + float32_t3 isnanVec; + float32_t3 isinfVec; + float32_t3 powXVec; + float32_t3 powYVec; + float32_t3 expVec; + float32_t3 exp2Vec; + float32_t3 logVec; + float32_t3 absFVec; + int32_t3 absIVec; + float32_t3 sqrtVec; + float32_t3 sinVec; + float32_t3 cosVec; + float32_t3 acosVec; +}; + +struct TgmathTestValues +{ + float floor; + float lerp; + int isnan; + int isinf; + float pow; + float exp; + float exp2; + float log; + float absF; + int absI; + float sqrt; + float sin; + float cos; + float acos; + + float32_t3 floorVec; + float32_t3 lerpVec; + int32_t3 isnanVec; + int32_t3 isinfVec; + float32_t3 powVec; + float32_t3 expVec; + float32_t3 exp2Vec; + float32_t3 logVec; + float32_t3 absFVec; + int32_t3 absIVec; + float32_t3 sqrtVec; + float32_t3 cosVec; + float32_t3 sinVec; + float32_t3 acosVec; + + void fillTestValues(NBL_CONST_REF_ARG(TgmathIntputTestValues) input) + { + floor = nbl::hlsl::floor(input.floor); + lerp = nbl::hlsl::lerp(input.lerpX, input.lerpY, input.lerpA); + isnan = nbl::hlsl::isnan(input.isnan); + isinf = nbl::hlsl::isinf(input.isinf); + pow = nbl::hlsl::pow(input.powX, input.powY); + exp = nbl::hlsl::exp(input.exp); + exp2 = nbl::hlsl::exp2(input.exp2); + log = nbl::hlsl::log(input.log); + absF = nbl::hlsl::abs(input.absF); + absI = nbl::hlsl::abs(input.absI); + sqrt = nbl::hlsl::sqrt(input.sqrt); + sin = nbl::hlsl::sin(input.sin); + cos = nbl::hlsl::cos(input.cos); + acos = nbl::hlsl::acos(input.acos); + + floorVec = nbl::hlsl::floor(input.floorVec); + lerpVec = nbl::hlsl::lerp(input.lerpXVec, input.lerpYVec, input.lerpAVec); + isnanVec = nbl::hlsl::isnan(input.isnanVec); + isinfVec = nbl::hlsl::isinf(input.isinfVec); + powVec = nbl::hlsl::pow(input.powXVec, input.powYVec); + expVec = nbl::hlsl::exp(input.expVec); + exp2Vec = nbl::hlsl::exp2(input.exp2Vec); + logVec = nbl::hlsl::log(input.logVec); + absFVec = nbl::hlsl::abs(input.absFVec); + absIVec = nbl::hlsl::abs(input.absIVec); + sqrtVec = nbl::hlsl::sqrt(input.sqrtVec); + sinVec = nbl::hlsl::sin(input.sinVec); + cosVec = nbl::hlsl::cos(input.cosVec); + acosVec = nbl::hlsl::acos(input.acosVec); + } +}; diff --git a/22_CppCompat/main.cpp b/22_CppCompat/main.cpp index 0959c9bd3..22d48bbb7 100644 --- a/22_CppCompat/main.cpp +++ b/22_CppCompat/main.cpp @@ -51,6 +51,10 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa bool onAppInitialized(smart_refctd_ptr&& system) override { + TgmathTester tgmathTester; + tgmathTester.performTest(); + std::cout << "tgmath.hlsl tests done.\n\n"; + // Remember to call the base class initialization! if (!device_base_t::onAppInitialized(smart_refctd_ptr(system))) return false; @@ -60,7 +64,6 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa m_queue = m_device->getQueue(0, 0); m_commandPool = m_device->createCommandPool(m_queue->getFamilyIndex(), IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT); m_commandPool->createCommandBuffers(IGPUCommandPool::BUFFER_LEVEL::PRIMARY, { &m_cmdbuf,1 }, smart_refctd_ptr(m_logger)); - smart_refctd_ptr shader; { @@ -211,7 +214,6 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa constexpr auto StartedValue = 0; smart_refctd_ptr progress = m_device->createSemaphore(StartedValue); - m_cmdbuf->reset(IGPUCommandBuffer::RESET_FLAGS::RELEASE_RESOURCES_BIT); m_cmdbuf->begin(IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT); @@ -366,6 +368,157 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa constexpr static inline uint64_t MaxIterations = 200; bool m_keepRunning = true; + +#define VERIFY_TEST_VALUE(MEMBER_NAME)\ +if (expectedTestValues.MEMBER_NAME != testValues.MEMBER_NAME)\ +{\ + std::cout << "nbl::hlsl::" #MEMBER_NAME << " produced incorrect output! test value: " << testValues.MEMBER_NAME << " expected value: " << expectedTestValues.MEMBER_NAME << std::endl;\ + _NBL_DEBUG_BREAK_IF(true);\ +} + +#define VERIFY_TEST_VECTOR_VALUE(MEMBER_NAME)\ +if (memcmp(&expectedTestValues.MEMBER_NAME, &testValues.MEMBER_NAME, sizeof(decltype(testValues.MEMBER_NAME))) != 0)\ +{\ + std::cout << "nbl::hlsl::" #MEMBER_NAME << " produced incorrect output! test value: " <<\ + testValues.MEMBER_NAME.x << ' ' << testValues.MEMBER_NAME.y << ' ' << testValues.MEMBER_NAME.z <<\ + " expected value: " << expectedTestValues.MEMBER_NAME.x << ' ' << expectedTestValues.MEMBER_NAME.y << ' ' << expectedTestValues.MEMBER_NAME.z << std::endl;\ + _NBL_DEBUG_BREAK_IF(true);\ +} + + class TgmathTester + { + public: + void performTest() + { + std::random_device rd; + std::mt19937 mt(rd()); + + std::uniform_real_distribution realDistributionNeg(-50.0f, -1.0f); + std::uniform_real_distribution realDistributionPos(1.0f, 50.0f); + std::uniform_real_distribution realDistributionZeroToOne(0.0f, 1.0f); + std::uniform_real_distribution realDistribution(-100.0f, 100.0f); + std::uniform_int_distribution intDistribution(-100, 100); + std::uniform_int_distribution coinFlipDistribution(0, 1); + + // Set input thest values that will be used in both CPU and GPU tests + TgmathIntputTestValues commonTestValues; + commonTestValues.floor = realDistribution(mt); + commonTestValues.lerpX = realDistributionNeg(mt); + commonTestValues.lerpY = realDistributionPos(mt); + commonTestValues.lerpA = realDistributionZeroToOne(mt); + commonTestValues.isnan = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::quiet_NaN(); + commonTestValues.isinf = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::infinity(); + commonTestValues.powX = realDistribution(mt); + commonTestValues.powY = realDistribution(mt); + commonTestValues.exp = realDistribution(mt); + commonTestValues.exp2 = realDistribution(mt); + commonTestValues.log = realDistribution(mt); + commonTestValues.absF = realDistribution(mt); + commonTestValues.absI = intDistribution(mt); + commonTestValues.sqrt = realDistribution(mt); + commonTestValues.sin = realDistribution(mt); + commonTestValues.cos = realDistribution(mt); + commonTestValues.acos = realDistribution(mt); + + commonTestValues.floorVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.lerpXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + commonTestValues.lerpYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + commonTestValues.lerpAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); + commonTestValues.isnanVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.isinfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.powXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.powYVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.expVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.exp2Vec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.logVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.absFVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.absIVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); + commonTestValues.sqrtVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.sinVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.cosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestValues.acosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + + // use std library functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values + TgmathTestValues expectedTestValues; + expectedTestValues.floor = std::floor(commonTestValues.floor); + expectedTestValues.lerp = std::lerp(commonTestValues.lerpX, commonTestValues.lerpY, commonTestValues.lerpA); + expectedTestValues.isnan = std::isnan(commonTestValues.isnan); + expectedTestValues.isinf = std::isinf(commonTestValues.isinf); + expectedTestValues.pow = std::pow(commonTestValues.powX, commonTestValues.powY); + expectedTestValues.exp = std::exp(commonTestValues.exp); + expectedTestValues.exp2 = std::exp2(commonTestValues.exp2); + expectedTestValues.log = std::log(commonTestValues.log); + expectedTestValues.absF = std::abs(commonTestValues.absF); + expectedTestValues.absI = std::abs(commonTestValues.absI); + expectedTestValues.sqrt = std::sqrt(commonTestValues.sqrt); + expectedTestValues.sin = std::sin(commonTestValues.sin); + expectedTestValues.cos = std::cos(commonTestValues.cos); + expectedTestValues.acos = std::acos(commonTestValues.acos); + + expectedTestValues.floorVec = float32_t3(std::floor(commonTestValues.floorVec.x), std::floor(commonTestValues.floorVec.y), std::floor(commonTestValues.floorVec.z)); + + expectedTestValues.lerpVec.x = std::lerp(commonTestValues.lerpXVec.x, commonTestValues.lerpYVec.x, commonTestValues.lerpAVec.x); + expectedTestValues.lerpVec.y = std::lerp(commonTestValues.lerpXVec.y, commonTestValues.lerpYVec.y, commonTestValues.lerpAVec.y); + expectedTestValues.lerpVec.z = std::lerp(commonTestValues.lerpXVec.z, commonTestValues.lerpYVec.z, commonTestValues.lerpAVec.z); + + expectedTestValues.isnanVec = float32_t3(std::isnan(commonTestValues.isnanVec.x), std::isnan(commonTestValues.isnanVec.y), std::isnan(commonTestValues.isnanVec.z)); + expectedTestValues.isinfVec = float32_t3(std::isinf(commonTestValues.isinfVec.x), std::isinf(commonTestValues.isinfVec.y), std::isinf(commonTestValues.isinfVec.z)); + + expectedTestValues.powVec.x = std::pow(commonTestValues.powXVec.x, commonTestValues.powYVec.x); + expectedTestValues.powVec.y = std::pow(commonTestValues.powXVec.y, commonTestValues.powYVec.y); + expectedTestValues.powVec.z = std::pow(commonTestValues.powXVec.z, commonTestValues.powYVec.z); + + expectedTestValues.expVec = float32_t3(std::exp(commonTestValues.expVec.x), std::exp(commonTestValues.expVec.y), std::exp(commonTestValues.expVec.z)); + expectedTestValues.exp2Vec = float32_t3(std::exp2(commonTestValues.exp2Vec.x), std::exp2(commonTestValues.exp2Vec.y), std::exp2(commonTestValues.exp2Vec.z)); + expectedTestValues.logVec = float32_t3(std::log(commonTestValues.logVec.x), std::log(commonTestValues.logVec.y), std::log(commonTestValues.logVec.z)); + expectedTestValues.absFVec = float32_t3(std::abs(commonTestValues.absFVec.x), std::abs(commonTestValues.absFVec.y), std::abs(commonTestValues.absFVec.z)); + expectedTestValues.absIVec = float32_t3(std::abs(commonTestValues.absIVec.x), std::abs(commonTestValues.absIVec.y), std::abs(commonTestValues.absIVec.z)); + expectedTestValues.sqrtVec = float32_t3(std::sqrt(commonTestValues.sqrtVec.x), std::sqrt(commonTestValues.sqrtVec.y), std::sqrt(commonTestValues.sqrtVec.z)); + expectedTestValues.cosVec = float32_t3(std::cos(commonTestValues.cosVec.x), std::cos(commonTestValues.cosVec.y), std::cos(commonTestValues.cosVec.z)); + expectedTestValues.sinVec = float32_t3(std::sin(commonTestValues.sinVec.x), std::sin(commonTestValues.sinVec.y), std::sin(commonTestValues.sinVec.z)); + expectedTestValues.acosVec = float32_t3(std::acos(commonTestValues.acosVec.x), std::acos(commonTestValues.acosVec.y), std::acos(commonTestValues.acosVec.z)); + + // perform C++ test of functions from tgmath.hlsl + TgmathTestValues cpuTestValues; + cpuTestValues.fillTestValues(commonTestValues); + + verifyTestValues(expectedTestValues, cpuTestValues); + } + + private: + void verifyTestValues(NBL_CONST_REF_ARG(TgmathTestValues) expectedTestValues, NBL_CONST_REF_ARG(TgmathTestValues) testValues) + { + VERIFY_TEST_VALUE(floor); + VERIFY_TEST_VALUE(lerp); + VERIFY_TEST_VALUE(isnan); + VERIFY_TEST_VALUE(isinf); + VERIFY_TEST_VALUE(pow); + VERIFY_TEST_VALUE(exp); + VERIFY_TEST_VALUE(exp2); + VERIFY_TEST_VALUE(log); + VERIFY_TEST_VALUE(absF); + VERIFY_TEST_VALUE(absI); + VERIFY_TEST_VALUE(sqrt); + VERIFY_TEST_VALUE(sin); + VERIFY_TEST_VALUE(cos); + VERIFY_TEST_VALUE(acos); + + VERIFY_TEST_VECTOR_VALUE(floorVec); + VERIFY_TEST_VECTOR_VALUE(lerpVec); + VERIFY_TEST_VECTOR_VALUE(isnanVec); + VERIFY_TEST_VECTOR_VALUE(isinfVec); + VERIFY_TEST_VECTOR_VALUE(powVec); + VERIFY_TEST_VECTOR_VALUE(expVec); + VERIFY_TEST_VECTOR_VALUE(exp2Vec); + VERIFY_TEST_VECTOR_VALUE(logVec); + VERIFY_TEST_VECTOR_VALUE(absFVec); + VERIFY_TEST_VECTOR_VALUE(absIVec); + VERIFY_TEST_VECTOR_VALUE(sqrtVec); + VERIFY_TEST_VECTOR_VALUE(cosVec); + VERIFY_TEST_VECTOR_VALUE(sinVec); + VERIFY_TEST_VECTOR_VALUE(acosVec); + } + }; }; template @@ -562,7 +715,7 @@ void cpu_tests() auto zero = cross(x,x); auto lenX2 = dot(x,x); //auto z_inv = inverse(z); //busted return type conversion - auto mid = lerp(x,x,0.5f); + auto mid = nbl::hlsl::lerp(x,x,0.5f); //auto w = transpose(y); //also busted @@ -761,8 +914,8 @@ void cpu_tests() TEST_CMATH(fdim, 2, type) \ - TEST_CMATH_FOR_TYPE(float32_t) - TEST_CMATH_FOR_TYPE(float64_t) + //TEST_CMATH_FOR_TYPE(float32_t) + //TEST_CMATH_FOR_TYPE(float64_t) #endif std::cout << "cpu tests done\n"; } From bc4cbbe2e613ffbc11df05db35ca0659acddd97a Mon Sep 17 00:00:00 2001 From: Przemek Date: Sat, 25 Jan 2025 15:03:38 +0100 Subject: [PATCH 71/83] Implemented HLSL side tgmath tests --- 22_CppCompat/Testers.h | 441 ++++++++++++++++++ 22_CppCompat/app_resources/common.hlsl | 9 +- .../app_resources/tgmathTest.comp.hlsl | 16 + 22_CppCompat/main.cpp | 172 +------ 4 files changed, 480 insertions(+), 158 deletions(-) create mode 100644 22_CppCompat/Testers.h create mode 100644 22_CppCompat/app_resources/tgmathTest.comp.hlsl diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h new file mode 100644 index 000000000..b3cda6441 --- /dev/null +++ b/22_CppCompat/Testers.h @@ -0,0 +1,441 @@ +#ifndef _NBL_EXAMPLES_TESTS_22_CPP_COMPAT_TESTERS_INCLUDED_ +#define _NBL_EXAMPLES_TESTS_22_CPP_COMPAT_TESTERS_INCLUDED_ + +#include +#include "app_resources/common.hlsl" +#include "nbl/application_templates/MonoDeviceApplication.hpp" +#include "nbl/application_templates/MonoAssetManagerAndBuiltinResourceApplication.hpp" + +using namespace nbl; + +static constexpr float MaxAllowedError = 0.001f; +#define VERIFY_TEST_VALUE(MEMBER_NAME)\ +if (std::abs(expectedTestValues.MEMBER_NAME - testValues.MEMBER_NAME) > MaxAllowedError)\ +{\ + std::cout << "nbl::hlsl::" #MEMBER_NAME << " produced incorrect output! test value: " << testValues.MEMBER_NAME << " expected value: " << expectedTestValues.MEMBER_NAME << std::endl;\ + assert(false);\ +} + +#define VERIFY_TEST_VECTOR_VALUE(MEMBER_NAME)\ +if (memcmp(&expectedTestValues.MEMBER_NAME, &testValues.MEMBER_NAME, sizeof(decltype(testValues.MEMBER_NAME))) != 0)\ +{\ + std::cout << "nbl::hlsl::" #MEMBER_NAME << " produced incorrect output! test value: " <<\ + testValues.MEMBER_NAME.x << ' ' << testValues.MEMBER_NAME.y << ' ' << testValues.MEMBER_NAME.z <<\ + " expected value: " << expectedTestValues.MEMBER_NAME.x << ' ' << expectedTestValues.MEMBER_NAME.y << ' ' << expectedTestValues.MEMBER_NAME.z << std::endl;\ + assert(false);\ +} + +class ITester +{ +public: + virtual ~ITester() + { + m_outputBufferAllocation.memory->unmap(); + }; + + struct PipelineSetupData + { + core::smart_refctd_ptr device; + core::smart_refctd_ptr api; + core::smart_refctd_ptr assetMgr; + core::smart_refctd_ptr logger; + video::IPhysicalDevice* physicalDevice; + uint32_t computeFamilyIndex; + }; + + template + void setupPipeline(const PipelineSetupData& pipleineSetupData) + { + // setting up pipeline in the constructor + m_device = core::smart_refctd_ptr(pipleineSetupData.device); + m_physicalDevice = pipleineSetupData.physicalDevice; + m_api = core::smart_refctd_ptr(pipleineSetupData.api); + m_assetMgr = core::smart_refctd_ptr(pipleineSetupData.assetMgr); + m_logger = core::smart_refctd_ptr(pipleineSetupData.logger); + m_queueFamily = pipleineSetupData.computeFamilyIndex; + m_semaphoreCounter = 0; + m_semaphore = m_device->createSemaphore(0); + m_cmdpool = m_device->createCommandPool(m_queueFamily, video::IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT); + if (!m_cmdpool->createCommandBuffers(video::IGPUCommandPool::BUFFER_LEVEL::PRIMARY, 1u, &m_cmdbuf)) + ;//TODO: app.logFail("Failed to create Command Buffers!\n"); + + // Load shaders, set up pipeline + core::smart_refctd_ptr shader; + { + asset::IAssetLoader::SAssetLoadParams lp = {}; + lp.logger = m_logger.get(); + lp.workingDirectory = ""; // virtual root + // this time we load a shader directly from a file + auto assetBundle = m_assetMgr->getAsset("app_resources/tgmathTest.comp.hlsl", lp); + const auto assets = assetBundle.getContents(); + if (assets.empty()) + { + ;//TODO: app.logFail("Could not load shader!"); + assert(0); + } + + // It would be super weird if loading a shader from a file produced more than 1 asset + assert(assets.size() == 1); + core::smart_refctd_ptr source = asset::IAsset::castDown(assets[0]); + + auto* compilerSet = m_assetMgr->getCompilerSet(); + + asset::IShaderCompiler::SCompilerOptions options = {}; + options.stage = source->getStage(); + options.targetSpirvVersion = m_device->getPhysicalDevice()->getLimits().spirvVersion; + options.spirvOptimizer = nullptr; + options.debugInfoFlags |= asset::IShaderCompiler::E_DEBUG_INFO_FLAGS::EDIF_SOURCE_BIT; + options.preprocessorOptions.sourceIdentifier = source->getFilepathHint(); + options.preprocessorOptions.logger = m_logger.get(); + options.preprocessorOptions.includeFinder = compilerSet->getShaderCompiler(source->getContentType())->getDefaultIncludeFinder(); + + auto spirv = compilerSet->compileToSPIRV(source.get(), options); + + video::ILogicalDevice::SShaderCreationParameters params{}; + params.cpushader = spirv.get(); + shader = m_device->createShader(params); + } + + if (!shader) + ;//TODO: app.logFail("Failed to create a GPU Shader, seems the Driver doesn't like the SPIR-V we're feeding it!\n"); + + video::IGPUDescriptorSetLayout::SBinding bindings[2] = { + { + .binding = 0, + .type = asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER, + .createFlags = video::IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE, + .stageFlags = ShaderStage::ESS_COMPUTE, + .count = 1 + }, + { + .binding = 1, + .type = asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER, + .createFlags = video::IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_NONE, + .stageFlags = ShaderStage::ESS_COMPUTE, + .count = 1 + } + }; + + core::smart_refctd_ptr dsLayout = m_device->createDescriptorSetLayout(bindings); + if (!dsLayout) + ;//TODO: app.logFail("Failed to create a Descriptor Layout!\n"); + + m_pplnLayout = m_device->createPipelineLayout({}, core::smart_refctd_ptr(dsLayout)); + if (!m_pplnLayout) + ;//TODO: app.logFail("Failed to create a Pipeline Layout!\n"); + + { + video::IGPUComputePipeline::SCreationParams params = {}; + params.layout = m_pplnLayout.get(); + params.shader.entryPoint = "main"; + params.shader.shader = shader.get(); + if (!m_device->createComputePipelines(nullptr, { ¶ms,1 }, &m_pipeline)) + ;//TODO: app.logFail("Failed to create pipelines (compile & link shaders)!\n"); + } + + // Allocate memory of the input buffer + { + constexpr size_t BufferSize = sizeof(TgmathIntputTestValues); + + video::IGPUBuffer::SCreationParams params = {}; + params.size = BufferSize; + params.usage = video::IGPUBuffer::EUF_STORAGE_BUFFER_BIT; + core::smart_refctd_ptr inputBuff = m_device->createBuffer(std::move(params)); + if (!inputBuff) + ;//TODO: app.logFail("Failed to create a GPU Buffer of size %d!\n", params.size); + + inputBuff->setObjectDebugName("emulated_float64_t output buffer"); + + video::IDeviceMemoryBacked::SDeviceMemoryRequirements reqs = inputBuff->getMemoryReqs(); + reqs.memoryTypeBits &= m_physicalDevice->getHostVisibleMemoryTypeBits(); + + m_inputBufferAllocation = m_device->allocate(reqs, inputBuff.get(), video::IDeviceMemoryAllocation::EMAF_NONE); + if (!m_inputBufferAllocation.isValid()) + ;//TODO: app.logFail("Failed to allocate Device Memory compatible with our GPU Buffer!\n"); + + assert(inputBuff->getBoundMemory().memory == m_inputBufferAllocation.memory.get()); + core::smart_refctd_ptr pool = m_device->createDescriptorPoolForDSLayouts(video::IDescriptorPool::ECF_NONE, { &dsLayout.get(),1 }); + + m_ds = pool->createDescriptorSet(core::smart_refctd_ptr(dsLayout)); + { + video::IGPUDescriptorSet::SDescriptorInfo info[1]; + info[0].desc = core::smart_refctd_ptr(inputBuff); + info[0].info.buffer = { .offset = 0,.size = BufferSize }; + video::IGPUDescriptorSet::SWriteDescriptorSet writes[1] = { + {.dstSet = m_ds.get(),.binding = 0,.arrayElement = 0,.count = 1,.info = info} + }; + m_device->updateDescriptorSets(writes, {}); + } + } + + // Allocate memory of the output buffer + { + constexpr size_t BufferSize = sizeof(OutputStruct); + + video::IGPUBuffer::SCreationParams params = {}; + params.size = BufferSize; + params.usage = video::IGPUBuffer::EUF_STORAGE_BUFFER_BIT; + core::smart_refctd_ptr outputBuff = m_device->createBuffer(std::move(params)); + if (!outputBuff) + ;//TODO: app.logFail("Failed to create a GPU Buffer of size %d!\n", params.size); + + outputBuff->setObjectDebugName("emulated_float64_t output buffer"); + + video::IDeviceMemoryBacked::SDeviceMemoryRequirements reqs = outputBuff->getMemoryReqs(); + reqs.memoryTypeBits &= m_physicalDevice->getHostVisibleMemoryTypeBits(); + + m_outputBufferAllocation = m_device->allocate(reqs, outputBuff.get(), video::IDeviceMemoryAllocation::EMAF_NONE); + if (!m_outputBufferAllocation.isValid()) + ;//TODO: app.logFail("Failed to allocate Device Memory compatible with our GPU Buffer!\n"); + + assert(outputBuff->getBoundMemory().memory == m_outputBufferAllocation.memory.get()); + core::smart_refctd_ptr pool = m_device->createDescriptorPoolForDSLayouts(video::IDescriptorPool::ECF_NONE, { &dsLayout.get(),1 }); + + { + video::IGPUDescriptorSet::SDescriptorInfo info[1]; + info[0].desc = core::smart_refctd_ptr(outputBuff); + info[0].info.buffer = { .offset = 0,.size = BufferSize }; + video::IGPUDescriptorSet::SWriteDescriptorSet writes[1] = { + {.dstSet = m_ds.get(),.binding = 1,.arrayElement = 0,.count = 1,.info = info} + }; + m_device->updateDescriptorSets(writes, {}); + } + } + + if (!m_outputBufferAllocation.memory->map({ 0ull,m_outputBufferAllocation.memory->getAllocationSize() }, video::IDeviceMemoryAllocation::EMCAF_READ)) + ;//TODO: app.logFail("Failed to map the Device Memory!\n"); + + // if the mapping is not coherent the range needs to be invalidated to pull in new data for the CPU's caches + const video::ILogicalDevice::MappedMemoryRange memoryRange(m_outputBufferAllocation.memory.get(), 0ull, m_outputBufferAllocation.memory->getAllocationSize()); + if (!m_outputBufferAllocation.memory->getMemoryPropertyFlags().hasFlags(video::IDeviceMemoryAllocation::EMPF_HOST_COHERENT_BIT)) + m_device->invalidateMappedMemoryRanges(1, &memoryRange); + + assert(memoryRange.valid() && memoryRange.length >= sizeof(OutputStruct)); + + m_queue = m_device->getQueue(m_queueFamily, 0); + } + +protected: + uint32_t m_queueFamily; + core::smart_refctd_ptr m_device; + core::smart_refctd_ptr m_api; + video::IPhysicalDevice* m_physicalDevice; + core::smart_refctd_ptr m_assetMgr; + core::smart_refctd_ptr m_logger; + video::IDeviceMemoryAllocator::SAllocation m_inputBufferAllocation = {}; + video::IDeviceMemoryAllocator::SAllocation m_outputBufferAllocation = {}; + core::smart_refctd_ptr m_cmdbuf = nullptr; + core::smart_refctd_ptr m_cmdpool = nullptr; + core::smart_refctd_ptr m_ds = nullptr; + core::smart_refctd_ptr m_pplnLayout = nullptr; + core::smart_refctd_ptr m_pipeline; + core::smart_refctd_ptr m_semaphore; + video::IQueue* m_queue; + uint64_t m_semaphoreCounter; + + template + OutputStruct dispatch(const InputStruct& input) + { + // Update input buffer + if (!m_inputBufferAllocation.memory->map({ 0ull,m_inputBufferAllocation.memory->getAllocationSize() }, video::IDeviceMemoryAllocation::EMCAF_READ)) + __debugbreak();//TODO: app.logFail("Failed to map the Device Memory!\n"); + + const video::ILogicalDevice::MappedMemoryRange memoryRange(m_inputBufferAllocation.memory.get(), 0ull, m_inputBufferAllocation.memory->getAllocationSize()); + if (!m_inputBufferAllocation.memory->getMemoryPropertyFlags().hasFlags(video::IDeviceMemoryAllocation::EMPF_HOST_COHERENT_BIT)) + m_device->invalidateMappedMemoryRanges(1, &memoryRange); + + std::memcpy(static_cast(m_inputBufferAllocation.memory->getMappedPointer()), &input, sizeof(InputStruct)); + + m_inputBufferAllocation.memory->unmap(); + + // record command buffer + m_cmdbuf->reset(video::IGPUCommandBuffer::RESET_FLAGS::NONE); + m_cmdbuf->begin(video::IGPUCommandBuffer::USAGE::NONE); + m_cmdbuf->beginDebugMarker("test", core::vector4df_SIMD(0, 1, 0, 1)); + m_cmdbuf->bindComputePipeline(m_pipeline.get()); + m_cmdbuf->bindDescriptorSets(nbl::asset::EPBP_COMPUTE, m_pplnLayout.get(), 0, 1, &m_ds.get()); + m_cmdbuf->dispatch(16, 1, 1); + m_cmdbuf->endDebugMarker(); + m_cmdbuf->end(); + + video::IQueue::SSubmitInfo submitInfos[1] = {}; + const video::IQueue::SSubmitInfo::SCommandBufferInfo cmdbufs[] = { {.cmdbuf = m_cmdbuf.get()} }; + submitInfos[0].commandBuffers = cmdbufs; + const video::IQueue::SSubmitInfo::SSemaphoreInfo signals[] = { {.semaphore = m_semaphore.get(), .value = ++m_semaphoreCounter, .stageMask = asset::PIPELINE_STAGE_FLAGS::COMPUTE_SHADER_BIT} }; + submitInfos[0].signalSemaphores = signals; + + m_api->startCapture(); + m_queue->submit(submitInfos); + m_api->endCapture(); + + m_device->waitIdle(); + OutputStruct output; + std::memcpy(&output, static_cast(m_outputBufferAllocation.memory->getMappedPointer()), sizeof(OutputStruct)); + m_device->waitIdle(); + + return output; + } +}; + +class CTgmathTester final : public ITester +{ +public: + void performTests() + { + std::random_device rd; + std::mt19937 mt(rd()); + + std::uniform_real_distribution realDistributionNeg(-50.0f, -1.0f); + std::uniform_real_distribution realDistributionPos(1.0f, 50.0f); + std::uniform_real_distribution realDistributionZeroToOne(0.0f, 1.0f); + std::uniform_real_distribution realDistribution(-100.0f, 100.0f); + std::uniform_int_distribution intDistribution(-100, 100); + std::uniform_int_distribution coinFlipDistribution(0, 1); + + // Set input thest values that will be used in both CPU and GPU tests + TgmathIntputTestValues commonTestInputValues; + commonTestInputValues.floor = realDistribution(mt); + commonTestInputValues.lerpX = realDistributionNeg(mt); + commonTestInputValues.lerpY = realDistributionPos(mt); + commonTestInputValues.lerpA = realDistributionZeroToOne(mt); + commonTestInputValues.isnan = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::quiet_NaN(); + commonTestInputValues.isinf = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::infinity(); + commonTestInputValues.powX = realDistribution(mt); + commonTestInputValues.powY = realDistribution(mt); + commonTestInputValues.exp = realDistribution(mt); + commonTestInputValues.exp2 = realDistribution(mt); + commonTestInputValues.log = realDistribution(mt); + commonTestInputValues.absF = realDistribution(mt); + commonTestInputValues.absI = intDistribution(mt); + commonTestInputValues.sqrt = realDistribution(mt); + commonTestInputValues.sin = realDistribution(mt); + commonTestInputValues.cos = realDistribution(mt); + commonTestInputValues.acos = realDistribution(mt); + + commonTestInputValues.floorVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.lerpXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + commonTestInputValues.lerpYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + commonTestInputValues.lerpAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); + commonTestInputValues.isnanVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.isinfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.powXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.powYVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.expVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.exp2Vec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.logVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.absFVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.absIVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); + commonTestInputValues.sqrtVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.sinVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.cosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.acosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + + // use std library functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values + TgmathTestValues expectedTestValues; + expectedTestValues.floor = std::floor(commonTestInputValues.floor); + expectedTestValues.lerp = std::lerp(commonTestInputValues.lerpX, commonTestInputValues.lerpY, commonTestInputValues.lerpA); + expectedTestValues.isnan = std::isnan(commonTestInputValues.isnan); + expectedTestValues.isinf = std::isinf(commonTestInputValues.isinf); + expectedTestValues.pow = std::pow(commonTestInputValues.powX, commonTestInputValues.powY); + expectedTestValues.exp = std::exp(commonTestInputValues.exp); + expectedTestValues.exp2 = std::exp2(commonTestInputValues.exp2); + expectedTestValues.log = std::log(commonTestInputValues.log); + expectedTestValues.absF = std::abs(commonTestInputValues.absF); + expectedTestValues.absI = std::abs(commonTestInputValues.absI); + expectedTestValues.sqrt = std::sqrt(commonTestInputValues.sqrt); + expectedTestValues.sin = std::sin(commonTestInputValues.sin); + expectedTestValues.cos = std::cos(commonTestInputValues.cos); + expectedTestValues.acos = std::acos(commonTestInputValues.acos); + + expectedTestValues.floorVec = float32_t3(std::floor(commonTestInputValues.floorVec.x), std::floor(commonTestInputValues.floorVec.y), std::floor(commonTestInputValues.floorVec.z)); + + expectedTestValues.lerpVec.x = std::lerp(commonTestInputValues.lerpXVec.x, commonTestInputValues.lerpYVec.x, commonTestInputValues.lerpAVec.x); + expectedTestValues.lerpVec.y = std::lerp(commonTestInputValues.lerpXVec.y, commonTestInputValues.lerpYVec.y, commonTestInputValues.lerpAVec.y); + expectedTestValues.lerpVec.z = std::lerp(commonTestInputValues.lerpXVec.z, commonTestInputValues.lerpYVec.z, commonTestInputValues.lerpAVec.z); + + expectedTestValues.isnanVec = float32_t3(std::isnan(commonTestInputValues.isnanVec.x), std::isnan(commonTestInputValues.isnanVec.y), std::isnan(commonTestInputValues.isnanVec.z)); + expectedTestValues.isinfVec = float32_t3(std::isinf(commonTestInputValues.isinfVec.x), std::isinf(commonTestInputValues.isinfVec.y), std::isinf(commonTestInputValues.isinfVec.z)); + + expectedTestValues.powVec.x = std::pow(commonTestInputValues.powXVec.x, commonTestInputValues.powYVec.x); + expectedTestValues.powVec.y = std::pow(commonTestInputValues.powXVec.y, commonTestInputValues.powYVec.y); + expectedTestValues.powVec.z = std::pow(commonTestInputValues.powXVec.z, commonTestInputValues.powYVec.z); + + expectedTestValues.expVec = float32_t3(std::exp(commonTestInputValues.expVec.x), std::exp(commonTestInputValues.expVec.y), std::exp(commonTestInputValues.expVec.z)); + expectedTestValues.exp2Vec = float32_t3(std::exp2(commonTestInputValues.exp2Vec.x), std::exp2(commonTestInputValues.exp2Vec.y), std::exp2(commonTestInputValues.exp2Vec.z)); + expectedTestValues.logVec = float32_t3(std::log(commonTestInputValues.logVec.x), std::log(commonTestInputValues.logVec.y), std::log(commonTestInputValues.logVec.z)); + expectedTestValues.absFVec = float32_t3(std::abs(commonTestInputValues.absFVec.x), std::abs(commonTestInputValues.absFVec.y), std::abs(commonTestInputValues.absFVec.z)); + expectedTestValues.absIVec = float32_t3(std::abs(commonTestInputValues.absIVec.x), std::abs(commonTestInputValues.absIVec.y), std::abs(commonTestInputValues.absIVec.z)); + expectedTestValues.sqrtVec = float32_t3(std::sqrt(commonTestInputValues.sqrtVec.x), std::sqrt(commonTestInputValues.sqrtVec.y), std::sqrt(commonTestInputValues.sqrtVec.z)); + expectedTestValues.cosVec = float32_t3(std::cos(commonTestInputValues.cosVec.x), std::cos(commonTestInputValues.cosVec.y), std::cos(commonTestInputValues.cosVec.z)); + expectedTestValues.sinVec = float32_t3(std::sin(commonTestInputValues.sinVec.x), std::sin(commonTestInputValues.sinVec.y), std::sin(commonTestInputValues.sinVec.z)); + expectedTestValues.acosVec = float32_t3(std::acos(commonTestInputValues.acosVec.x), std::acos(commonTestInputValues.acosVec.y), std::acos(commonTestInputValues.acosVec.z)); + + // perform C++ side test of functions from tgmath.hlsl + performCpuTests(commonTestInputValues, expectedTestValues); + performGpuTests(commonTestInputValues, expectedTestValues); + } + +private: + inline static constexpr int Iterations = 1u; + + void performCpuTests(const TgmathIntputTestValues& commonTestInputValues, const TgmathTestValues& expectedTestValues) + { + TgmathTestValues cpuTestValues; + for (int i = 0; i < Iterations; ++i) + { + cpuTestValues.fillTestValues(commonTestInputValues); + m_logger->log("CPU TESTS:", system::ILogger::ELL_PERFORMANCE); + verifyTestValues(expectedTestValues, cpuTestValues); + } + } + + void performGpuTests(const TgmathIntputTestValues& commonTestInputValues, const TgmathTestValues& expectedTestValues) + { + TgmathTestValues gpuTestValues; + for (int i = 0; i < Iterations; ++i) + { + gpuTestValues = dispatch(commonTestInputValues); + m_logger->log("GPU TESTS:", system::ILogger::ELL_PERFORMANCE); + verifyTestValues(expectedTestValues, gpuTestValues); + __debugbreak(); + } + } + + void verifyTestValues(const TgmathTestValues& expectedTestValues, const TgmathTestValues& testValues) + { + VERIFY_TEST_VALUE(floor); + VERIFY_TEST_VALUE(lerp); + VERIFY_TEST_VALUE(isnan); + VERIFY_TEST_VALUE(isinf); + VERIFY_TEST_VALUE(pow); + VERIFY_TEST_VALUE(exp); + VERIFY_TEST_VALUE(exp2); + VERIFY_TEST_VALUE(log); + VERIFY_TEST_VALUE(absF); + VERIFY_TEST_VALUE(absI); + VERIFY_TEST_VALUE(sqrt); + VERIFY_TEST_VALUE(sin); + VERIFY_TEST_VALUE(cos); + VERIFY_TEST_VALUE(acos); + + VERIFY_TEST_VECTOR_VALUE(floorVec); + VERIFY_TEST_VECTOR_VALUE(lerpVec); + VERIFY_TEST_VECTOR_VALUE(isnanVec); + VERIFY_TEST_VECTOR_VALUE(isinfVec); + VERIFY_TEST_VECTOR_VALUE(powVec); + VERIFY_TEST_VECTOR_VALUE(expVec); + VERIFY_TEST_VECTOR_VALUE(exp2Vec); + VERIFY_TEST_VECTOR_VALUE(logVec); + VERIFY_TEST_VECTOR_VALUE(absFVec); + VERIFY_TEST_VECTOR_VALUE(absIVec); + VERIFY_TEST_VECTOR_VALUE(sqrtVec); + VERIFY_TEST_VECTOR_VALUE(cosVec); + VERIFY_TEST_VECTOR_VALUE(sinVec); + VERIFY_TEST_VECTOR_VALUE(acosVec); + } +}; + +#undef VERIFY_TEST_VALUE +#undef VERIFY_TEST_VECTOR_VALUE + +#endif \ No newline at end of file diff --git a/22_CppCompat/app_resources/common.hlsl b/22_CppCompat/app_resources/common.hlsl index 9336bc4bb..d88752730 100644 --- a/22_CppCompat/app_resources/common.hlsl +++ b/22_CppCompat/app_resources/common.hlsl @@ -2,6 +2,9 @@ //// This file is part of the "Nabla Engine". //// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_EXAMPLES_TESTS_22_CPP_COMPAT_COMMON_INCLUDED_ +#define _NBL_EXAMPLES_TESTS_22_CPP_COMPAT_COMMON_INCLUDED_ + // because DXC doesn't properly support `_Static_assert` #define STATIC_ASSERT(...) { nbl::hlsl::conditional<__VA_ARGS__, int, void>::type a = 0; } @@ -126,8 +129,8 @@ struct TgmathTestValues floorVec = nbl::hlsl::floor(input.floorVec); lerpVec = nbl::hlsl::lerp(input.lerpXVec, input.lerpYVec, input.lerpAVec); - isnanVec = nbl::hlsl::isnan(input.isnanVec); - isinfVec = nbl::hlsl::isinf(input.isinfVec); + //isnanVec = nbl::hlsl::isnan(input.isnanVec); + //isinfVec = nbl::hlsl::isinf(input.isinfVec); powVec = nbl::hlsl::pow(input.powXVec, input.powYVec); expVec = nbl::hlsl::exp(input.expVec); exp2Vec = nbl::hlsl::exp2(input.exp2Vec); @@ -140,3 +143,5 @@ struct TgmathTestValues acosVec = nbl::hlsl::acos(input.acosVec); } }; + +#endif \ No newline at end of file diff --git a/22_CppCompat/app_resources/tgmathTest.comp.hlsl b/22_CppCompat/app_resources/tgmathTest.comp.hlsl new file mode 100644 index 000000000..d4652ce49 --- /dev/null +++ b/22_CppCompat/app_resources/tgmathTest.comp.hlsl @@ -0,0 +1,16 @@ +//// Copyright (C) 2023-2024 - DevSH Graphics Programming Sp. z O.O. +//// This file is part of the "Nabla Engine". +//// For conditions of distribution and use, see copyright notice in nabla.h +#pragma shader_stage(compute) + +#include "common.hlsl" + +[[vk::binding(0, 0)]] RWStructuredBuffer inputTestValues; +[[vk::binding(1, 0)]] RWStructuredBuffer outputTestValues; + +[numthreads(16, 1, 1)] +void main(uint3 invocationID : SV_DispatchThreadID) +{ + if(invocationID.x == 0) + outputTestValues[0].fillTestValues(inputTestValues[0]); +} diff --git a/22_CppCompat/main.cpp b/22_CppCompat/main.cpp index 22d48bbb7..06a0b07e8 100644 --- a/22_CppCompat/main.cpp +++ b/22_CppCompat/main.cpp @@ -10,6 +10,7 @@ #include "nbl/application_templates/MonoAssetManagerAndBuiltinResourceApplication.hpp" #include "app_resources/common.hlsl" +#include "Testers.h" using namespace nbl::core; @@ -51,16 +52,26 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa bool onAppInitialized(smart_refctd_ptr&& system) override { - TgmathTester tgmathTester; - tgmathTester.performTest(); - std::cout << "tgmath.hlsl tests done.\n\n"; - // Remember to call the base class initialization! if (!device_base_t::onAppInitialized(smart_refctd_ptr(system))) return false; if (!asset_base_t::onAppInitialized(std::move(system))) return false; - + + CTgmathTester tgmathTester; + + ITester::PipelineSetupData pplnSetupData; + pplnSetupData.device = m_device; + pplnSetupData.api = m_api; + pplnSetupData.assetMgr = m_assetMgr; + pplnSetupData.logger = m_logger; + pplnSetupData.physicalDevice = m_physicalDevice; + pplnSetupData.computeFamilyIndex = getComputeQueue()->getFamilyIndex(); + + tgmathTester.setupPipeline(pplnSetupData); + tgmathTester.performTests(); + std::cout << "tgmath.hlsl tests done.\n\n"; + m_queue = m_device->getQueue(0, 0); m_commandPool = m_device->createCommandPool(m_queue->getFamilyIndex(), IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT); m_commandPool->createCommandBuffers(IGPUCommandPool::BUFFER_LEVEL::PRIMARY, { &m_cmdbuf,1 }, smart_refctd_ptr(m_logger)); @@ -368,157 +379,6 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa constexpr static inline uint64_t MaxIterations = 200; bool m_keepRunning = true; - -#define VERIFY_TEST_VALUE(MEMBER_NAME)\ -if (expectedTestValues.MEMBER_NAME != testValues.MEMBER_NAME)\ -{\ - std::cout << "nbl::hlsl::" #MEMBER_NAME << " produced incorrect output! test value: " << testValues.MEMBER_NAME << " expected value: " << expectedTestValues.MEMBER_NAME << std::endl;\ - _NBL_DEBUG_BREAK_IF(true);\ -} - -#define VERIFY_TEST_VECTOR_VALUE(MEMBER_NAME)\ -if (memcmp(&expectedTestValues.MEMBER_NAME, &testValues.MEMBER_NAME, sizeof(decltype(testValues.MEMBER_NAME))) != 0)\ -{\ - std::cout << "nbl::hlsl::" #MEMBER_NAME << " produced incorrect output! test value: " <<\ - testValues.MEMBER_NAME.x << ' ' << testValues.MEMBER_NAME.y << ' ' << testValues.MEMBER_NAME.z <<\ - " expected value: " << expectedTestValues.MEMBER_NAME.x << ' ' << expectedTestValues.MEMBER_NAME.y << ' ' << expectedTestValues.MEMBER_NAME.z << std::endl;\ - _NBL_DEBUG_BREAK_IF(true);\ -} - - class TgmathTester - { - public: - void performTest() - { - std::random_device rd; - std::mt19937 mt(rd()); - - std::uniform_real_distribution realDistributionNeg(-50.0f, -1.0f); - std::uniform_real_distribution realDistributionPos(1.0f, 50.0f); - std::uniform_real_distribution realDistributionZeroToOne(0.0f, 1.0f); - std::uniform_real_distribution realDistribution(-100.0f, 100.0f); - std::uniform_int_distribution intDistribution(-100, 100); - std::uniform_int_distribution coinFlipDistribution(0, 1); - - // Set input thest values that will be used in both CPU and GPU tests - TgmathIntputTestValues commonTestValues; - commonTestValues.floor = realDistribution(mt); - commonTestValues.lerpX = realDistributionNeg(mt); - commonTestValues.lerpY = realDistributionPos(mt); - commonTestValues.lerpA = realDistributionZeroToOne(mt); - commonTestValues.isnan = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::quiet_NaN(); - commonTestValues.isinf = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::infinity(); - commonTestValues.powX = realDistribution(mt); - commonTestValues.powY = realDistribution(mt); - commonTestValues.exp = realDistribution(mt); - commonTestValues.exp2 = realDistribution(mt); - commonTestValues.log = realDistribution(mt); - commonTestValues.absF = realDistribution(mt); - commonTestValues.absI = intDistribution(mt); - commonTestValues.sqrt = realDistribution(mt); - commonTestValues.sin = realDistribution(mt); - commonTestValues.cos = realDistribution(mt); - commonTestValues.acos = realDistribution(mt); - - commonTestValues.floorVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.lerpXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); - commonTestValues.lerpYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); - commonTestValues.lerpAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); - commonTestValues.isnanVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.isinfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.powXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.powYVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.expVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.exp2Vec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.logVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.absFVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.absIVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); - commonTestValues.sqrtVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.sinVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.cosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestValues.acosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - - // use std library functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values - TgmathTestValues expectedTestValues; - expectedTestValues.floor = std::floor(commonTestValues.floor); - expectedTestValues.lerp = std::lerp(commonTestValues.lerpX, commonTestValues.lerpY, commonTestValues.lerpA); - expectedTestValues.isnan = std::isnan(commonTestValues.isnan); - expectedTestValues.isinf = std::isinf(commonTestValues.isinf); - expectedTestValues.pow = std::pow(commonTestValues.powX, commonTestValues.powY); - expectedTestValues.exp = std::exp(commonTestValues.exp); - expectedTestValues.exp2 = std::exp2(commonTestValues.exp2); - expectedTestValues.log = std::log(commonTestValues.log); - expectedTestValues.absF = std::abs(commonTestValues.absF); - expectedTestValues.absI = std::abs(commonTestValues.absI); - expectedTestValues.sqrt = std::sqrt(commonTestValues.sqrt); - expectedTestValues.sin = std::sin(commonTestValues.sin); - expectedTestValues.cos = std::cos(commonTestValues.cos); - expectedTestValues.acos = std::acos(commonTestValues.acos); - - expectedTestValues.floorVec = float32_t3(std::floor(commonTestValues.floorVec.x), std::floor(commonTestValues.floorVec.y), std::floor(commonTestValues.floorVec.z)); - - expectedTestValues.lerpVec.x = std::lerp(commonTestValues.lerpXVec.x, commonTestValues.lerpYVec.x, commonTestValues.lerpAVec.x); - expectedTestValues.lerpVec.y = std::lerp(commonTestValues.lerpXVec.y, commonTestValues.lerpYVec.y, commonTestValues.lerpAVec.y); - expectedTestValues.lerpVec.z = std::lerp(commonTestValues.lerpXVec.z, commonTestValues.lerpYVec.z, commonTestValues.lerpAVec.z); - - expectedTestValues.isnanVec = float32_t3(std::isnan(commonTestValues.isnanVec.x), std::isnan(commonTestValues.isnanVec.y), std::isnan(commonTestValues.isnanVec.z)); - expectedTestValues.isinfVec = float32_t3(std::isinf(commonTestValues.isinfVec.x), std::isinf(commonTestValues.isinfVec.y), std::isinf(commonTestValues.isinfVec.z)); - - expectedTestValues.powVec.x = std::pow(commonTestValues.powXVec.x, commonTestValues.powYVec.x); - expectedTestValues.powVec.y = std::pow(commonTestValues.powXVec.y, commonTestValues.powYVec.y); - expectedTestValues.powVec.z = std::pow(commonTestValues.powXVec.z, commonTestValues.powYVec.z); - - expectedTestValues.expVec = float32_t3(std::exp(commonTestValues.expVec.x), std::exp(commonTestValues.expVec.y), std::exp(commonTestValues.expVec.z)); - expectedTestValues.exp2Vec = float32_t3(std::exp2(commonTestValues.exp2Vec.x), std::exp2(commonTestValues.exp2Vec.y), std::exp2(commonTestValues.exp2Vec.z)); - expectedTestValues.logVec = float32_t3(std::log(commonTestValues.logVec.x), std::log(commonTestValues.logVec.y), std::log(commonTestValues.logVec.z)); - expectedTestValues.absFVec = float32_t3(std::abs(commonTestValues.absFVec.x), std::abs(commonTestValues.absFVec.y), std::abs(commonTestValues.absFVec.z)); - expectedTestValues.absIVec = float32_t3(std::abs(commonTestValues.absIVec.x), std::abs(commonTestValues.absIVec.y), std::abs(commonTestValues.absIVec.z)); - expectedTestValues.sqrtVec = float32_t3(std::sqrt(commonTestValues.sqrtVec.x), std::sqrt(commonTestValues.sqrtVec.y), std::sqrt(commonTestValues.sqrtVec.z)); - expectedTestValues.cosVec = float32_t3(std::cos(commonTestValues.cosVec.x), std::cos(commonTestValues.cosVec.y), std::cos(commonTestValues.cosVec.z)); - expectedTestValues.sinVec = float32_t3(std::sin(commonTestValues.sinVec.x), std::sin(commonTestValues.sinVec.y), std::sin(commonTestValues.sinVec.z)); - expectedTestValues.acosVec = float32_t3(std::acos(commonTestValues.acosVec.x), std::acos(commonTestValues.acosVec.y), std::acos(commonTestValues.acosVec.z)); - - // perform C++ test of functions from tgmath.hlsl - TgmathTestValues cpuTestValues; - cpuTestValues.fillTestValues(commonTestValues); - - verifyTestValues(expectedTestValues, cpuTestValues); - } - - private: - void verifyTestValues(NBL_CONST_REF_ARG(TgmathTestValues) expectedTestValues, NBL_CONST_REF_ARG(TgmathTestValues) testValues) - { - VERIFY_TEST_VALUE(floor); - VERIFY_TEST_VALUE(lerp); - VERIFY_TEST_VALUE(isnan); - VERIFY_TEST_VALUE(isinf); - VERIFY_TEST_VALUE(pow); - VERIFY_TEST_VALUE(exp); - VERIFY_TEST_VALUE(exp2); - VERIFY_TEST_VALUE(log); - VERIFY_TEST_VALUE(absF); - VERIFY_TEST_VALUE(absI); - VERIFY_TEST_VALUE(sqrt); - VERIFY_TEST_VALUE(sin); - VERIFY_TEST_VALUE(cos); - VERIFY_TEST_VALUE(acos); - - VERIFY_TEST_VECTOR_VALUE(floorVec); - VERIFY_TEST_VECTOR_VALUE(lerpVec); - VERIFY_TEST_VECTOR_VALUE(isnanVec); - VERIFY_TEST_VECTOR_VALUE(isinfVec); - VERIFY_TEST_VECTOR_VALUE(powVec); - VERIFY_TEST_VECTOR_VALUE(expVec); - VERIFY_TEST_VECTOR_VALUE(exp2Vec); - VERIFY_TEST_VECTOR_VALUE(logVec); - VERIFY_TEST_VECTOR_VALUE(absFVec); - VERIFY_TEST_VECTOR_VALUE(absIVec); - VERIFY_TEST_VECTOR_VALUE(sqrtVec); - VERIFY_TEST_VECTOR_VALUE(cosVec); - VERIFY_TEST_VECTOR_VALUE(sinVec); - VERIFY_TEST_VECTOR_VALUE(acosVec); - } - }; }; template From e91f070f88bdee41b2c431364d94969688871822 Mon Sep 17 00:00:00 2001 From: Przemek Date: Tue, 28 Jan 2025 10:44:13 +0100 Subject: [PATCH 72/83] Implemented intrinsics.hlsl tests --- 22_CppCompat/Testers.h | 528 ++++++++++++++++++------- 22_CppCompat/app_resources/common.hlsl | 127 +++++- 22_CppCompat/main.cpp | 15 +- 3 files changed, 522 insertions(+), 148 deletions(-) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index b3cda6441..0fd7b5c15 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -8,23 +8,6 @@ using namespace nbl; -static constexpr float MaxAllowedError = 0.001f; -#define VERIFY_TEST_VALUE(MEMBER_NAME)\ -if (std::abs(expectedTestValues.MEMBER_NAME - testValues.MEMBER_NAME) > MaxAllowedError)\ -{\ - std::cout << "nbl::hlsl::" #MEMBER_NAME << " produced incorrect output! test value: " << testValues.MEMBER_NAME << " expected value: " << expectedTestValues.MEMBER_NAME << std::endl;\ - assert(false);\ -} - -#define VERIFY_TEST_VECTOR_VALUE(MEMBER_NAME)\ -if (memcmp(&expectedTestValues.MEMBER_NAME, &testValues.MEMBER_NAME, sizeof(decltype(testValues.MEMBER_NAME))) != 0)\ -{\ - std::cout << "nbl::hlsl::" #MEMBER_NAME << " produced incorrect output! test value: " <<\ - testValues.MEMBER_NAME.x << ' ' << testValues.MEMBER_NAME.y << ' ' << testValues.MEMBER_NAME.z <<\ - " expected value: " << expectedTestValues.MEMBER_NAME.x << ' ' << expectedTestValues.MEMBER_NAME.y << ' ' << expectedTestValues.MEMBER_NAME.z << std::endl;\ - assert(false);\ -} - class ITester { public: @@ -215,6 +198,76 @@ class ITester m_queue = m_device->getQueue(m_queueFamily, 0); } + enum class TestType + { + CPU, + GPU + }; + + template + void verifyTestValue(const std::string& memberName, const T& expectedVal, const T& testVal, const TestType testType) + { + if (std::abs(double(expectedVal) - double(testVal)) <= MaxAllowedError) + return; + + std::stringstream ss; + switch (testType) + { + case TestType::CPU: + ss << "CPU TEST ERROR:\n"; + case TestType::GPU: + ss << "GPU TEST ERROR:\n"; + } + + ss << "nbl::hlsl::" << memberName << " produced incorrect output! test value: " << testVal << " expected value: " << expectedVal << '\n'; + + if (memberName == "pow") + { + auto a = expectedVal; + auto b = testVal; + std::cout << std::bitset<32>(reinterpret_cast(a)) << std::endl; + std::cout << std::bitset<32>(reinterpret_cast(b)) << std::endl; + } + + m_logger->log(ss.str().c_str(), system::ILogger::ELL_ERROR); + } + + template + void verifyTestVector3dValue(const std::string& memberName, const nbl::hlsl::vector& expectedVal, const nbl::hlsl::vector& testVal, const TestType testType) + { + static constexpr float MaxAllowedError = 0.1f; + if (std::abs(double(expectedVal.x) - double(testVal.x)) <= MaxAllowedError || + std::abs(double(expectedVal.y) - double(testVal.y)) <= MaxAllowedError || + std::abs(double(expectedVal.z) - double(testVal.z)) <= MaxAllowedError) + return; + + std::stringstream ss; + switch (testType) + { + case TestType::CPU: + ss << "CPU TEST ERROR:\n"; + case TestType::GPU: + ss << "GPU TEST ERROR:\n"; + } + + ss << "nbl::hlsl::" << memberName << " produced incorrect output! test value: " << + testVal.x << ' ' << testVal.y << ' ' << testVal.z << + " expected value: " << expectedVal.x << ' ' << expectedVal.y << ' ' << expectedVal.z << '\n'; + + m_logger->log(ss.str().c_str(), system::ILogger::ELL_ERROR); + } + + template + void verifyTestMatrix3x3Value(const std::string& memberName, const nbl::hlsl::matrix& expectedVal, const nbl::hlsl::matrix& testVal, const TestType testType) + { + for (int i = 0; i < 3; ++i) + { + auto expectedValRow = expectedVal[i]; + auto testValRow = testVal[i]; + verifyTestVector3dValue(memberName, expectedValRow, testValRow, testType); + } + } + protected: uint32_t m_queueFamily; core::smart_refctd_ptr m_device; @@ -275,6 +328,9 @@ class ITester return output; } + +private: + static constexpr float MaxAllowedError = 0.001f; }; class CTgmathTester final : public ITester @@ -289,149 +345,343 @@ class CTgmathTester final : public ITester std::uniform_real_distribution realDistributionPos(1.0f, 50.0f); std::uniform_real_distribution realDistributionZeroToOne(0.0f, 1.0f); std::uniform_real_distribution realDistribution(-100.0f, 100.0f); + std::uniform_real_distribution realDistributionSmall(1.0f, 4.0f); std::uniform_int_distribution intDistribution(-100, 100); std::uniform_int_distribution coinFlipDistribution(0, 1); - // Set input thest values that will be used in both CPU and GPU tests - TgmathIntputTestValues commonTestInputValues; - commonTestInputValues.floor = realDistribution(mt); - commonTestInputValues.lerpX = realDistributionNeg(mt); - commonTestInputValues.lerpY = realDistributionPos(mt); - commonTestInputValues.lerpA = realDistributionZeroToOne(mt); - commonTestInputValues.isnan = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::quiet_NaN(); - commonTestInputValues.isinf = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::infinity(); - commonTestInputValues.powX = realDistribution(mt); - commonTestInputValues.powY = realDistribution(mt); - commonTestInputValues.exp = realDistribution(mt); - commonTestInputValues.exp2 = realDistribution(mt); - commonTestInputValues.log = realDistribution(mt); - commonTestInputValues.absF = realDistribution(mt); - commonTestInputValues.absI = intDistribution(mt); - commonTestInputValues.sqrt = realDistribution(mt); - commonTestInputValues.sin = realDistribution(mt); - commonTestInputValues.cos = realDistribution(mt); - commonTestInputValues.acos = realDistribution(mt); - - commonTestInputValues.floorVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.lerpXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); - commonTestInputValues.lerpYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); - commonTestInputValues.lerpAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); - commonTestInputValues.isnanVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.isinfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.powXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.powYVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.expVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.exp2Vec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.logVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.absFVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.absIVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); - commonTestInputValues.sqrtVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.sinVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.cosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.acosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - - // use std library functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values - TgmathTestValues expectedTestValues; - expectedTestValues.floor = std::floor(commonTestInputValues.floor); - expectedTestValues.lerp = std::lerp(commonTestInputValues.lerpX, commonTestInputValues.lerpY, commonTestInputValues.lerpA); - expectedTestValues.isnan = std::isnan(commonTestInputValues.isnan); - expectedTestValues.isinf = std::isinf(commonTestInputValues.isinf); - expectedTestValues.pow = std::pow(commonTestInputValues.powX, commonTestInputValues.powY); - expectedTestValues.exp = std::exp(commonTestInputValues.exp); - expectedTestValues.exp2 = std::exp2(commonTestInputValues.exp2); - expectedTestValues.log = std::log(commonTestInputValues.log); - expectedTestValues.absF = std::abs(commonTestInputValues.absF); - expectedTestValues.absI = std::abs(commonTestInputValues.absI); - expectedTestValues.sqrt = std::sqrt(commonTestInputValues.sqrt); - expectedTestValues.sin = std::sin(commonTestInputValues.sin); - expectedTestValues.cos = std::cos(commonTestInputValues.cos); - expectedTestValues.acos = std::acos(commonTestInputValues.acos); - - expectedTestValues.floorVec = float32_t3(std::floor(commonTestInputValues.floorVec.x), std::floor(commonTestInputValues.floorVec.y), std::floor(commonTestInputValues.floorVec.z)); - - expectedTestValues.lerpVec.x = std::lerp(commonTestInputValues.lerpXVec.x, commonTestInputValues.lerpYVec.x, commonTestInputValues.lerpAVec.x); - expectedTestValues.lerpVec.y = std::lerp(commonTestInputValues.lerpXVec.y, commonTestInputValues.lerpYVec.y, commonTestInputValues.lerpAVec.y); - expectedTestValues.lerpVec.z = std::lerp(commonTestInputValues.lerpXVec.z, commonTestInputValues.lerpYVec.z, commonTestInputValues.lerpAVec.z); - - expectedTestValues.isnanVec = float32_t3(std::isnan(commonTestInputValues.isnanVec.x), std::isnan(commonTestInputValues.isnanVec.y), std::isnan(commonTestInputValues.isnanVec.z)); - expectedTestValues.isinfVec = float32_t3(std::isinf(commonTestInputValues.isinfVec.x), std::isinf(commonTestInputValues.isinfVec.y), std::isinf(commonTestInputValues.isinfVec.z)); - - expectedTestValues.powVec.x = std::pow(commonTestInputValues.powXVec.x, commonTestInputValues.powYVec.x); - expectedTestValues.powVec.y = std::pow(commonTestInputValues.powXVec.y, commonTestInputValues.powYVec.y); - expectedTestValues.powVec.z = std::pow(commonTestInputValues.powXVec.z, commonTestInputValues.powYVec.z); - - expectedTestValues.expVec = float32_t3(std::exp(commonTestInputValues.expVec.x), std::exp(commonTestInputValues.expVec.y), std::exp(commonTestInputValues.expVec.z)); - expectedTestValues.exp2Vec = float32_t3(std::exp2(commonTestInputValues.exp2Vec.x), std::exp2(commonTestInputValues.exp2Vec.y), std::exp2(commonTestInputValues.exp2Vec.z)); - expectedTestValues.logVec = float32_t3(std::log(commonTestInputValues.logVec.x), std::log(commonTestInputValues.logVec.y), std::log(commonTestInputValues.logVec.z)); - expectedTestValues.absFVec = float32_t3(std::abs(commonTestInputValues.absFVec.x), std::abs(commonTestInputValues.absFVec.y), std::abs(commonTestInputValues.absFVec.z)); - expectedTestValues.absIVec = float32_t3(std::abs(commonTestInputValues.absIVec.x), std::abs(commonTestInputValues.absIVec.y), std::abs(commonTestInputValues.absIVec.z)); - expectedTestValues.sqrtVec = float32_t3(std::sqrt(commonTestInputValues.sqrtVec.x), std::sqrt(commonTestInputValues.sqrtVec.y), std::sqrt(commonTestInputValues.sqrtVec.z)); - expectedTestValues.cosVec = float32_t3(std::cos(commonTestInputValues.cosVec.x), std::cos(commonTestInputValues.cosVec.y), std::cos(commonTestInputValues.cosVec.z)); - expectedTestValues.sinVec = float32_t3(std::sin(commonTestInputValues.sinVec.x), std::sin(commonTestInputValues.sinVec.y), std::sin(commonTestInputValues.sinVec.z)); - expectedTestValues.acosVec = float32_t3(std::acos(commonTestInputValues.acosVec.x), std::acos(commonTestInputValues.acosVec.y), std::acos(commonTestInputValues.acosVec.z)); - - // perform C++ side test of functions from tgmath.hlsl - performCpuTests(commonTestInputValues, expectedTestValues); - performGpuTests(commonTestInputValues, expectedTestValues); + m_logger->log("tgmath.hlsl TESTS:", system::ILogger::ELL_PERFORMANCE); + for (int i = 0; i < Iterations; ++i) + { + // Set input thest values that will be used in both CPU and GPU tests + TgmathIntputTestValues commonTestInputValues; + commonTestInputValues.floor = realDistribution(mt); + commonTestInputValues.lerpX = realDistributionNeg(mt); + commonTestInputValues.lerpY = realDistributionPos(mt); + commonTestInputValues.lerpA = realDistributionZeroToOne(mt); + commonTestInputValues.isnan = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::quiet_NaN(); + commonTestInputValues.isinf = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::infinity(); + commonTestInputValues.powX = realDistributionSmall(mt); + commonTestInputValues.powY = realDistributionSmall(mt); + commonTestInputValues.exp = realDistributionSmall(mt); + commonTestInputValues.exp2 = realDistributionSmall(mt); + commonTestInputValues.log = realDistribution(mt); + commonTestInputValues.absF = realDistribution(mt); + commonTestInputValues.absI = intDistribution(mt); + commonTestInputValues.sqrt = realDistribution(mt); + commonTestInputValues.sin = realDistribution(mt); + commonTestInputValues.cos = realDistribution(mt); + commonTestInputValues.acos = realDistribution(mt); + commonTestInputValues.modf = realDistribution(mt); + + commonTestInputValues.floorVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.lerpXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + commonTestInputValues.lerpYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + commonTestInputValues.lerpAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); + commonTestInputValues.isnanVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.isinfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.powXVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + commonTestInputValues.powYVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + commonTestInputValues.expVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + commonTestInputValues.exp2Vec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + commonTestInputValues.logVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.absFVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.absIVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); + commonTestInputValues.sqrtVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.sinVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.cosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.acosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.modfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + + // use std library functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values + TgmathTestValues expectedTestValues; + expectedTestValues.floor = std::floor(commonTestInputValues.floor); + expectedTestValues.lerp = std::lerp(commonTestInputValues.lerpX, commonTestInputValues.lerpY, commonTestInputValues.lerpA); + expectedTestValues.isnan = std::isnan(commonTestInputValues.isnan); + expectedTestValues.isinf = std::isinf(commonTestInputValues.isinf); + expectedTestValues.pow = std::pow(commonTestInputValues.powX, commonTestInputValues.powY); + expectedTestValues.exp = std::exp(commonTestInputValues.exp); + expectedTestValues.exp2 = std::exp2(commonTestInputValues.exp2); + expectedTestValues.log = std::log(commonTestInputValues.log); + expectedTestValues.absF = std::abs(commonTestInputValues.absF); + expectedTestValues.absI = std::abs(commonTestInputValues.absI); + expectedTestValues.sqrt = std::sqrt(commonTestInputValues.sqrt); + expectedTestValues.sin = std::sin(commonTestInputValues.sin); + expectedTestValues.cos = std::cos(commonTestInputValues.cos); + expectedTestValues.acos = std::acos(commonTestInputValues.acos); + { + float tmp; + expectedTestValues.modf = std::modf(commonTestInputValues.modf, &tmp); + } + + expectedTestValues.floorVec = float32_t3(std::floor(commonTestInputValues.floorVec.x), std::floor(commonTestInputValues.floorVec.y), std::floor(commonTestInputValues.floorVec.z)); + + expectedTestValues.lerpVec.x = std::lerp(commonTestInputValues.lerpXVec.x, commonTestInputValues.lerpYVec.x, commonTestInputValues.lerpAVec.x); + expectedTestValues.lerpVec.y = std::lerp(commonTestInputValues.lerpXVec.y, commonTestInputValues.lerpYVec.y, commonTestInputValues.lerpAVec.y); + expectedTestValues.lerpVec.z = std::lerp(commonTestInputValues.lerpXVec.z, commonTestInputValues.lerpYVec.z, commonTestInputValues.lerpAVec.z); + + expectedTestValues.isnanVec = float32_t3(std::isnan(commonTestInputValues.isnanVec.x), std::isnan(commonTestInputValues.isnanVec.y), std::isnan(commonTestInputValues.isnanVec.z)); + expectedTestValues.isinfVec = float32_t3(std::isinf(commonTestInputValues.isinfVec.x), std::isinf(commonTestInputValues.isinfVec.y), std::isinf(commonTestInputValues.isinfVec.z)); + + expectedTestValues.powVec.x = std::pow(commonTestInputValues.powXVec.x, commonTestInputValues.powYVec.x); + expectedTestValues.powVec.y = std::pow(commonTestInputValues.powXVec.y, commonTestInputValues.powYVec.y); + expectedTestValues.powVec.z = std::pow(commonTestInputValues.powXVec.z, commonTestInputValues.powYVec.z); + + expectedTestValues.expVec = float32_t3(std::exp(commonTestInputValues.expVec.x), std::exp(commonTestInputValues.expVec.y), std::exp(commonTestInputValues.expVec.z)); + expectedTestValues.exp2Vec = float32_t3(std::exp2(commonTestInputValues.exp2Vec.x), std::exp2(commonTestInputValues.exp2Vec.y), std::exp2(commonTestInputValues.exp2Vec.z)); + expectedTestValues.logVec = float32_t3(std::log(commonTestInputValues.logVec.x), std::log(commonTestInputValues.logVec.y), std::log(commonTestInputValues.logVec.z)); + expectedTestValues.absFVec = float32_t3(std::abs(commonTestInputValues.absFVec.x), std::abs(commonTestInputValues.absFVec.y), std::abs(commonTestInputValues.absFVec.z)); + expectedTestValues.absIVec = float32_t3(std::abs(commonTestInputValues.absIVec.x), std::abs(commonTestInputValues.absIVec.y), std::abs(commonTestInputValues.absIVec.z)); + expectedTestValues.sqrtVec = float32_t3(std::sqrt(commonTestInputValues.sqrtVec.x), std::sqrt(commonTestInputValues.sqrtVec.y), std::sqrt(commonTestInputValues.sqrtVec.z)); + expectedTestValues.cosVec = float32_t3(std::cos(commonTestInputValues.cosVec.x), std::cos(commonTestInputValues.cosVec.y), std::cos(commonTestInputValues.cosVec.z)); + expectedTestValues.sinVec = float32_t3(std::sin(commonTestInputValues.sinVec.x), std::sin(commonTestInputValues.sinVec.y), std::sin(commonTestInputValues.sinVec.z)); + expectedTestValues.acosVec = float32_t3(std::acos(commonTestInputValues.acosVec.x), std::acos(commonTestInputValues.acosVec.y), std::acos(commonTestInputValues.acosVec.z)); + { + float tmp; + expectedTestValues.modfVec = float32_t3(std::modf(commonTestInputValues.modfVec.x, &tmp), std::modf(commonTestInputValues.modfVec.y, &tmp), std::modf(commonTestInputValues.modfVec.z, &tmp)); + } + + performCpuTests(commonTestInputValues, expectedTestValues); + performGpuTests(commonTestInputValues, expectedTestValues); + } + m_logger->log("tgmath.hlsl TESTS DONE.", system::ILogger::ELL_PERFORMANCE); } private: - inline static constexpr int Iterations = 1u; + inline static constexpr int Iterations = 100u; void performCpuTests(const TgmathIntputTestValues& commonTestInputValues, const TgmathTestValues& expectedTestValues) { TgmathTestValues cpuTestValues; - for (int i = 0; i < Iterations; ++i) - { - cpuTestValues.fillTestValues(commonTestInputValues); - m_logger->log("CPU TESTS:", system::ILogger::ELL_PERFORMANCE); - verifyTestValues(expectedTestValues, cpuTestValues); - } + cpuTestValues.fillTestValues(commonTestInputValues); + verifyTestValues(expectedTestValues, cpuTestValues, ITester::TestType::CPU); + } void performGpuTests(const TgmathIntputTestValues& commonTestInputValues, const TgmathTestValues& expectedTestValues) { TgmathTestValues gpuTestValues; + gpuTestValues = dispatch(commonTestInputValues); + verifyTestValues(expectedTestValues, gpuTestValues, ITester::TestType::GPU); + } + + void verifyTestValues(const TgmathTestValues& expectedTestValues, const TgmathTestValues& testValues, ITester::TestType testType) + { + verifyTestValue("floor", expectedTestValues.floor, testValues.floor, testType); + verifyTestValue("lerp", expectedTestValues.lerp, testValues.lerp, testType); + verifyTestValue("isnan", expectedTestValues.isnan, testValues.isnan, testType); + verifyTestValue("isinf", expectedTestValues.isinf, testValues.isinf, testType); + verifyTestValue("pow", expectedTestValues.pow, testValues.pow, testType); + verifyTestValue("exp", expectedTestValues.exp, testValues.exp, testType); + verifyTestValue("exp2", expectedTestValues.exp2, testValues.exp2, testType); + verifyTestValue("log", expectedTestValues.log, testValues.log, testType); + verifyTestValue("absF", expectedTestValues.absF, testValues.absF, testType); + verifyTestValue("absI", expectedTestValues.absI, testValues.absI, testType); + verifyTestValue("sqrt", expectedTestValues.sqrt, testValues.sqrt, testType); + verifyTestValue("sin", expectedTestValues.sin, testValues.sin, testType); + verifyTestValue("cos", expectedTestValues.cos, testValues.cos, testType); + verifyTestValue("acos", expectedTestValues.acos, testValues.acos, testType); + verifyTestValue("modf", expectedTestValues.modf, testValues.modf, testType); + + verifyTestVector3dValue("floorVec", expectedTestValues.floorVec, testValues.floorVec, testType); + verifyTestVector3dValue("lerpVec", expectedTestValues.lerpVec, testValues.lerpVec, testType); + verifyTestVector3dValue("isnanVec", expectedTestValues.isnanVec, testValues.isnanVec, testType); + verifyTestVector3dValue("isinfVec", expectedTestValues.isinfVec, testValues.isinfVec, testType); + verifyTestVector3dValue("powVec", expectedTestValues.powVec, testValues.powVec, testType); + verifyTestVector3dValue("expVec", expectedTestValues.expVec, testValues.expVec, testType); + verifyTestVector3dValue("exp2Vec", expectedTestValues.exp2Vec, testValues.exp2Vec, testType); + verifyTestVector3dValue("logVec", expectedTestValues.logVec, testValues.logVec, testType); + verifyTestVector3dValue("absFVec", expectedTestValues.absFVec, testValues.absFVec, testType); + verifyTestVector3dValue("absIVec", expectedTestValues.absIVec, testValues.absIVec, testType); + verifyTestVector3dValue("sqrtVec", expectedTestValues.sqrtVec, testValues.sqrtVec, testType); + verifyTestVector3dValue("sinVec", expectedTestValues.sinVec, testValues.sinVec, testType); + verifyTestVector3dValue("cosVec", expectedTestValues.cosVec, testValues.cosVec, testType); + verifyTestVector3dValue("acosVec", expectedTestValues.acosVec, testValues.acosVec, testType); + verifyTestVector3dValue("modfVec", expectedTestValues.modfVec, testValues.modfVec, testType); + } +}; + +class CIntrinsicsTester final : public ITester +{ +public: + void performTests() + { + std::random_device rd; + std::mt19937 mt(rd()); + + std::uniform_real_distribution realDistributionNeg(-50.0f, -1.0f); + std::uniform_real_distribution realDistributionPos(1.0f, 50.0f); + std::uniform_real_distribution realDistribution(-100.0f, 100.0f); + std::uniform_int_distribution intDistribution(-100, 100); + std::uniform_int_distribution uintDistribution(0, 100); + + m_logger->log("intrinsics.hlsl TESTS:", system::ILogger::ELL_PERFORMANCE); for (int i = 0; i < Iterations; ++i) { - gpuTestValues = dispatch(commonTestInputValues); - m_logger->log("GPU TESTS:", system::ILogger::ELL_PERFORMANCE); - verifyTestValues(expectedTestValues, gpuTestValues); - __debugbreak(); + // Set input thest values that will be used in both CPU and GPU tests + IntrinsicsIntputTestValues commonTestInputValues; + commonTestInputValues.bitCount = intDistribution(mt); + commonTestInputValues.crossLhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.crossRhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.clampVal = realDistribution(mt); + commonTestInputValues.clampMin = realDistributionNeg(mt); + commonTestInputValues.clampMax = realDistributionPos(mt); + commonTestInputValues.length = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.normalize = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.dotLhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.dotRhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.determinant = float32_t3x3( + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt) + ); + commonTestInputValues.findMSB = realDistribution(mt); + commonTestInputValues.findLSB = realDistribution(mt); + commonTestInputValues.inverse = float32_t3x3( + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt) + ); + commonTestInputValues.transpose = float32_t3x3( + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt) + ); + commonTestInputValues.mulLhs = float32_t3x3( + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt) + ); + commonTestInputValues.mulRhs = float32_t3x3( + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt), + realDistribution(mt), realDistribution(mt), realDistribution(mt) + ); + commonTestInputValues.minA = realDistribution(mt); + commonTestInputValues.minB = realDistribution(mt); + commonTestInputValues.maxA = realDistribution(mt); + commonTestInputValues.maxB = realDistribution(mt); + commonTestInputValues.rsqrt = realDistributionPos(mt); + commonTestInputValues.bitReverse = realDistribution(mt); + commonTestInputValues.frac = realDistribution(mt); + + commonTestInputValues.bitCountVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); + commonTestInputValues.clampValVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.clampMinVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + commonTestInputValues.clampMaxVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + commonTestInputValues.findMSBVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); + commonTestInputValues.findLSBVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); + commonTestInputValues.minAVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.minBVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.maxAVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.maxBVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.rsqrtVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + commonTestInputValues.bitReverseVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); + commonTestInputValues.fracVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + + // use std library or glm functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values + IntrinsicsTestValues expectedTestValues; + expectedTestValues.bitCount = glm::bitCount(commonTestInputValues.bitCount); + expectedTestValues.clamp = glm::clamp(commonTestInputValues.clampVal, commonTestInputValues.clampMin, commonTestInputValues.clampMax); + expectedTestValues.length = glm::length(commonTestInputValues.length); + expectedTestValues.dot = glm::dot(commonTestInputValues.dotLhs, commonTestInputValues.dotRhs); + expectedTestValues.determinant = glm::determinant(reinterpret_cast(commonTestInputValues.determinant)); + expectedTestValues.findMSB = glm::findMSB(commonTestInputValues.findMSB); + expectedTestValues.findLSB = glm::findLSB(commonTestInputValues.findLSB); + expectedTestValues.min = glm::min(commonTestInputValues.minA, commonTestInputValues.minB); + expectedTestValues.max = glm::max(commonTestInputValues.maxA, commonTestInputValues.maxB); + expectedTestValues.rsqrt = (1.0f / std::sqrt(commonTestInputValues.rsqrt)); + + expectedTestValues.frac = commonTestInputValues.frac - std::floor(commonTestInputValues.frac); + expectedTestValues.bitReverse = glm::bitfieldReverse(commonTestInputValues.bitReverse); + + expectedTestValues.normalize = glm::normalize(commonTestInputValues.normalize); + expectedTestValues.cross = glm::cross(commonTestInputValues.crossLhs, commonTestInputValues.crossRhs); + expectedTestValues.bitCountVec = int32_t3(glm::bitCount(commonTestInputValues.bitCountVec.x), glm::bitCount(commonTestInputValues.bitCountVec.y), glm::bitCount(commonTestInputValues.bitCountVec.z)); + expectedTestValues.clampVec = float32_t3( + glm::clamp(commonTestInputValues.clampValVec.x, commonTestInputValues.clampMinVec.x, commonTestInputValues.clampMaxVec.x), + glm::clamp(commonTestInputValues.clampValVec.y, commonTestInputValues.clampMinVec.y, commonTestInputValues.clampMaxVec.y), + glm::clamp(commonTestInputValues.clampValVec.z, commonTestInputValues.clampMinVec.z, commonTestInputValues.clampMaxVec.z) + ); + expectedTestValues.findMSBVec = glm::findMSB(commonTestInputValues.findMSBVec); + expectedTestValues.findLSBVec = glm::findLSB(commonTestInputValues.findLSBVec); + expectedTestValues.minVec = float32_t3( + glm::min(commonTestInputValues.minAVec.x, commonTestInputValues.minBVec.x), + glm::min(commonTestInputValues.minAVec.y, commonTestInputValues.minBVec.y), + glm::min(commonTestInputValues.minAVec.z, commonTestInputValues.minBVec.z) + ); + expectedTestValues.maxVec = float32_t3( + glm::max(commonTestInputValues.maxAVec.x, commonTestInputValues.maxBVec.x), + glm::max(commonTestInputValues.maxAVec.y, commonTestInputValues.maxBVec.y), + glm::max(commonTestInputValues.maxAVec.z, commonTestInputValues.maxBVec.z) + ); + expectedTestValues.rsqrtVec = float32_t3(1.0f / std::sqrt(commonTestInputValues.rsqrtVec.x), 1.0f / std::sqrt(commonTestInputValues.rsqrtVec.y), 1.0f / std::sqrt(commonTestInputValues.rsqrtVec.z)); + expectedTestValues.bitReverseVec = glm::bitfieldReverse(commonTestInputValues.bitReverseVec); + expectedTestValues.fracVec = float32_t3( + commonTestInputValues.fracVec.x - std::floor(commonTestInputValues.fracVec.x), + commonTestInputValues.fracVec.y - std::floor(commonTestInputValues.fracVec.y), + commonTestInputValues.fracVec.z - std::floor(commonTestInputValues.fracVec.z)); + + auto mulGlm = nbl::hlsl::mul(commonTestInputValues.mulLhs, commonTestInputValues.mulRhs); + expectedTestValues.mul = reinterpret_cast(mulGlm); + auto transposeGlm = glm::transpose(reinterpret_cast(commonTestInputValues.transpose)); + expectedTestValues.transpose = reinterpret_cast(transposeGlm); + auto inverseGlm = glm::inverse(reinterpret_cast(commonTestInputValues.inverse)); + expectedTestValues.inverse = reinterpret_cast(inverseGlm); + + performCpuTests(commonTestInputValues, expectedTestValues); + //performGpuTests(commonTestInputValues, expectedTestValues); } + m_logger->log("intrinsics.hlsl TESTS DONE.", system::ILogger::ELL_PERFORMANCE); + } + +private: + inline static constexpr int Iterations = 100u; + + void performCpuTests(const IntrinsicsIntputTestValues& commonTestInputValues, const IntrinsicsTestValues& expectedTestValues) + { + IntrinsicsTestValues cpuTestValues; + cpuTestValues.fillTestValues(commonTestInputValues); + verifyTestValues(expectedTestValues, cpuTestValues, ITester::TestType::CPU); + + } + + void performGpuTests(const IntrinsicsIntputTestValues& commonTestInputValues, const IntrinsicsTestValues& expectedTestValues) + { + IntrinsicsTestValues gpuTestValues; + gpuTestValues = dispatch(commonTestInputValues); + verifyTestValues(expectedTestValues, gpuTestValues, ITester::TestType::GPU); } - void verifyTestValues(const TgmathTestValues& expectedTestValues, const TgmathTestValues& testValues) + void verifyTestValues(const IntrinsicsTestValues& expectedTestValues, const IntrinsicsTestValues& testValues, ITester::TestType testType) { - VERIFY_TEST_VALUE(floor); - VERIFY_TEST_VALUE(lerp); - VERIFY_TEST_VALUE(isnan); - VERIFY_TEST_VALUE(isinf); - VERIFY_TEST_VALUE(pow); - VERIFY_TEST_VALUE(exp); - VERIFY_TEST_VALUE(exp2); - VERIFY_TEST_VALUE(log); - VERIFY_TEST_VALUE(absF); - VERIFY_TEST_VALUE(absI); - VERIFY_TEST_VALUE(sqrt); - VERIFY_TEST_VALUE(sin); - VERIFY_TEST_VALUE(cos); - VERIFY_TEST_VALUE(acos); - - VERIFY_TEST_VECTOR_VALUE(floorVec); - VERIFY_TEST_VECTOR_VALUE(lerpVec); - VERIFY_TEST_VECTOR_VALUE(isnanVec); - VERIFY_TEST_VECTOR_VALUE(isinfVec); - VERIFY_TEST_VECTOR_VALUE(powVec); - VERIFY_TEST_VECTOR_VALUE(expVec); - VERIFY_TEST_VECTOR_VALUE(exp2Vec); - VERIFY_TEST_VECTOR_VALUE(logVec); - VERIFY_TEST_VECTOR_VALUE(absFVec); - VERIFY_TEST_VECTOR_VALUE(absIVec); - VERIFY_TEST_VECTOR_VALUE(sqrtVec); - VERIFY_TEST_VECTOR_VALUE(cosVec); - VERIFY_TEST_VECTOR_VALUE(sinVec); - VERIFY_TEST_VECTOR_VALUE(acosVec); + verifyTestValue("bitCount", expectedTestValues.bitCount, testValues.bitCount, testType); + verifyTestValue("clamp", expectedTestValues.clamp, testValues.clamp, testType); + verifyTestValue("length", expectedTestValues.length, testValues.length, testType); + verifyTestValue("dot", expectedTestValues.dot, testValues.dot, testType); + verifyTestValue("determinant", expectedTestValues.determinant, testValues.determinant, testType); + verifyTestValue("findMSB", expectedTestValues.findMSB, testValues.findMSB, testType); + verifyTestValue("findLSB", expectedTestValues.findLSB, testValues.findLSB, testType); + //verifyTestValue("min", expectedTestValues.min, testValues.min, testType); + //verifyTestValue("max", expectedTestValues.max, testValues.max, testType); + verifyTestValue("rsqrt", expectedTestValues.rsqrt, testValues.rsqrt, testType); + verifyTestValue("frac", expectedTestValues.frac, testValues.frac, testType); + verifyTestValue("bitReverse", expectedTestValues.bitReverse, testValues.bitReverse, testType); + + verifyTestVector3dValue("normalize", expectedTestValues.normalize, testValues.normalize, testType); + verifyTestVector3dValue("cross", expectedTestValues.cross, testValues.cross, testType); + verifyTestVector3dValue("bitCountVec", expectedTestValues.bitCountVec, testValues.bitCountVec, testType); + verifyTestVector3dValue("clampVec", expectedTestValues.clampVec, testValues.clampVec, testType); + verifyTestVector3dValue("findMSBVec", expectedTestValues.findMSBVec, testValues.findMSBVec, testType); + verifyTestVector3dValue("findLSBVec", expectedTestValues.findLSBVec, testValues.findLSBVec, testType); + //verifyTestVector3dValue("minVec", expectedTestValues.minVec, testValues.minVec, testType); + //verifyTestVector3dValue("maxVec", expectedTestValues.maxVec, testValues.maxVec, testType); + verifyTestVector3dValue("rsqrtVec", expectedTestValues.rsqrtVec, testValues.rsqrtVec, testType); + verifyTestVector3dValue("bitReverseVec", expectedTestValues.bitReverseVec, testValues.bitReverseVec, testType); + verifyTestVector3dValue("fracVec", expectedTestValues.fracVec, testValues.fracVec, testType); + + verifyTestMatrix3x3Value("mul", expectedTestValues.mul, testValues.mul, testType); + verifyTestMatrix3x3Value("transpose", expectedTestValues.transpose, testValues.transpose, testType); + verifyTestMatrix3x3Value("inverse", expectedTestValues.inverse, testValues.inverse, testType); } }; diff --git a/22_CppCompat/app_resources/common.hlsl b/22_CppCompat/app_resources/common.hlsl index d88752730..74d9ff8e7 100644 --- a/22_CppCompat/app_resources/common.hlsl +++ b/22_CppCompat/app_resources/common.hlsl @@ -58,6 +58,7 @@ struct TgmathIntputTestValues float sin; float cos; float acos; + float modf; float32_t3 floorVec; float32_t3 lerpXVec; @@ -76,6 +77,7 @@ struct TgmathIntputTestValues float32_t3 sinVec; float32_t3 cosVec; float32_t3 acosVec; + float32_t3 modfVec; }; struct TgmathTestValues @@ -94,11 +96,18 @@ struct TgmathTestValues float sin; float cos; float acos; + float modf; float32_t3 floorVec; float32_t3 lerpVec; - int32_t3 isnanVec; - int32_t3 isinfVec; +#ifndef __HLSL_VERSION + nbl::hlsl::vector isnanVec; + nbl::hlsl::vector isinfVec; +#else + vector isnanVec; + vector isinfVec; +#endif + float32_t3 powVec; float32_t3 expVec; float32_t3 exp2Vec; @@ -109,6 +118,7 @@ struct TgmathTestValues float32_t3 cosVec; float32_t3 sinVec; float32_t3 acosVec; + float32_t3 modfVec; void fillTestValues(NBL_CONST_REF_ARG(TgmathIntputTestValues) input) { @@ -126,11 +136,12 @@ struct TgmathTestValues sin = nbl::hlsl::sin(input.sin); cos = nbl::hlsl::cos(input.cos); acos = nbl::hlsl::acos(input.acos); + modf = nbl::hlsl::modf(input.modf); floorVec = nbl::hlsl::floor(input.floorVec); lerpVec = nbl::hlsl::lerp(input.lerpXVec, input.lerpYVec, input.lerpAVec); - //isnanVec = nbl::hlsl::isnan(input.isnanVec); - //isinfVec = nbl::hlsl::isinf(input.isinfVec); + isnanVec = nbl::hlsl::isnan(input.isnanVec); + isinfVec = nbl::hlsl::isinf(input.isinfVec); powVec = nbl::hlsl::pow(input.powXVec, input.powYVec); expVec = nbl::hlsl::exp(input.expVec); exp2Vec = nbl::hlsl::exp2(input.exp2Vec); @@ -141,6 +152,114 @@ struct TgmathTestValues sinVec = nbl::hlsl::sin(input.sinVec); cosVec = nbl::hlsl::cos(input.cosVec); acosVec = nbl::hlsl::acos(input.acosVec); + modfVec = nbl::hlsl::modf(input.modfVec); + } +}; + +struct IntrinsicsIntputTestValues +{ + int bitCount; + float32_t3 crossLhs; + float32_t3 crossRhs; + float clampVal; + float clampMin; + float clampMax; + float32_t3 length; + float32_t3 normalize; + float32_t3 dotLhs; + float32_t3 dotRhs; + float32_t3x3 determinant; + uint32_t findMSB; + uint32_t findLSB; + float32_t3x3 inverse; + float32_t3x3 transpose; + float32_t3x3 mulLhs; + float32_t3x3 mulRhs; + float minA; + float minB; + float maxA; + float maxB; + float rsqrt; + uint32_t bitReverse; + float frac; + + int32_t3 bitCountVec; + float32_t3 clampValVec; + float32_t3 clampMinVec; + float32_t3 clampMaxVec; + uint32_t3 findMSBVec; + uint32_t3 findLSBVec; + float32_t3 minAVec; + float32_t3 minBVec; + float32_t3 maxAVec; + float32_t3 maxBVec; + float32_t3 rsqrtVec; + uint32_t3 bitReverseVec; + float32_t3 fracVec; +}; + +struct IntrinsicsTestValues +{ + int bitCount; + float clamp; + float length; + float dot; + float determinant; + int findMSB; + int findLSB; + float min; + float max; + float rsqrt; + float frac; + uint32_t bitReverse; + + float32_t3 normalize; + float32_t3 cross; + int32_t3 bitCountVec; + float32_t3 clampVec; + uint32_t3 findMSBVec; + uint32_t3 findLSBVec; + float32_t3 minVec; + float32_t3 maxVec; + float32_t3 rsqrtVec; + uint32_t3 bitReverseVec; + float32_t3 fracVec; + + float32_t3x3 mul; + float32_t3x3 transpose; + float32_t3x3 inverse; + + void fillTestValues(NBL_CONST_REF_ARG(IntrinsicsIntputTestValues) input) + { + bitCount = nbl::hlsl::bitCount(input.bitCount); + cross = nbl::hlsl::cross(input.crossLhs, input.crossRhs); + clamp = nbl::hlsl::clamp(input.clampVal, input.clampMin, input.clampMax); + length = nbl::hlsl::length(input.length); + normalize = nbl::hlsl::normalize(input.normalize); + dot = nbl::hlsl::dot(input.dotLhs, input.dotRhs); + determinant = nbl::hlsl::determinant(input.determinant); + findMSB = nbl::hlsl::findMSB(input.findMSB); + findLSB = nbl::hlsl::findLSB(input.findLSB); + inverse = nbl::hlsl::inverse(input.inverse); + transpose = nbl::hlsl::transpose(input.transpose); + mul = nbl::hlsl::mul(input.mulLhs, input.mulRhs); + // TODO: fix min and max + //min = nbl::hlsl::min(input.minA, input.minB); + //max = nbl::hlsl::max(input.maxA, input.maxB); + rsqrt = nbl::hlsl::rsqrt(input.rsqrt); + bitReverse = nbl::hlsl::bitReverse(input.bitReverse); + frac = nbl::hlsl::frac(input.frac); + + bitCountVec = nbl::hlsl::bitCount(input.bitCountVec); + clampVec = nbl::hlsl::clamp(input.clampValVec, input.clampMinVec, input.clampMaxVec); + findMSBVec = nbl::hlsl::findMSB(input.findMSBVec); + findLSBVec = nbl::hlsl::findLSB(input.findLSBVec); + // TODO: fix min and max + //minVec = nbl::hlsl::min(input.minAVec, input.minBVec); + //maxVec = nbl::hlsl::max(input.maxAVec, input.maxBVec); + rsqrtVec = nbl::hlsl::rsqrt(input.rsqrtVec); + bitReverseVec = nbl::hlsl::bitReverse(input.bitReverseVec); + fracVec = nbl::hlsl::frac(input.fracVec); } }; diff --git a/22_CppCompat/main.cpp b/22_CppCompat/main.cpp index 06a0b07e8..58d4627bf 100644 --- a/22_CppCompat/main.cpp +++ b/22_CppCompat/main.cpp @@ -58,8 +58,6 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa if (!asset_base_t::onAppInitialized(std::move(system))) return false; - CTgmathTester tgmathTester; - ITester::PipelineSetupData pplnSetupData; pplnSetupData.device = m_device; pplnSetupData.api = m_api; @@ -68,9 +66,16 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa pplnSetupData.physicalDevice = m_physicalDevice; pplnSetupData.computeFamilyIndex = getComputeQueue()->getFamilyIndex(); - tgmathTester.setupPipeline(pplnSetupData); - tgmathTester.performTests(); - std::cout << "tgmath.hlsl tests done.\n\n"; + { + CTgmathTester tgmathTester; + tgmathTester.setupPipeline(pplnSetupData); + tgmathTester.performTests(); + } + { + CIntrinsicsTester intrinsicsTester; + intrinsicsTester.setupPipeline(pplnSetupData); + intrinsicsTester.performTests(); + } m_queue = m_device->getQueue(0, 0); m_commandPool = m_device->createCommandPool(m_queue->getFamilyIndex(), IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT); From a8ac36cecf779e51e761e1d52874fcf90aac6d92 Mon Sep 17 00:00:00 2001 From: Przemek Date: Tue, 28 Jan 2025 10:55:36 +0100 Subject: [PATCH 73/83] Implemented `logFail` --- 22_CppCompat/Testers.h | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index 0fd7b5c15..bff06370f 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -40,7 +40,7 @@ class ITester m_semaphore = m_device->createSemaphore(0); m_cmdpool = m_device->createCommandPool(m_queueFamily, video::IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT); if (!m_cmdpool->createCommandBuffers(video::IGPUCommandPool::BUFFER_LEVEL::PRIMARY, 1u, &m_cmdbuf)) - ;//TODO: app.logFail("Failed to create Command Buffers!\n"); + logFail("Failed to create Command Buffers!\n"); // Load shaders, set up pipeline core::smart_refctd_ptr shader; @@ -48,12 +48,11 @@ class ITester asset::IAssetLoader::SAssetLoadParams lp = {}; lp.logger = m_logger.get(); lp.workingDirectory = ""; // virtual root - // this time we load a shader directly from a file auto assetBundle = m_assetMgr->getAsset("app_resources/tgmathTest.comp.hlsl", lp); const auto assets = assetBundle.getContents(); if (assets.empty()) { - ;//TODO: app.logFail("Could not load shader!"); + logFail("Could not load shader!"); assert(0); } @@ -80,7 +79,7 @@ class ITester } if (!shader) - ;//TODO: app.logFail("Failed to create a GPU Shader, seems the Driver doesn't like the SPIR-V we're feeding it!\n"); + logFail("Failed to create a GPU Shader, seems the Driver doesn't like the SPIR-V we're feeding it!\n"); video::IGPUDescriptorSetLayout::SBinding bindings[2] = { { @@ -101,11 +100,11 @@ class ITester core::smart_refctd_ptr dsLayout = m_device->createDescriptorSetLayout(bindings); if (!dsLayout) - ;//TODO: app.logFail("Failed to create a Descriptor Layout!\n"); + logFail("Failed to create a Descriptor Layout!\n"); m_pplnLayout = m_device->createPipelineLayout({}, core::smart_refctd_ptr(dsLayout)); if (!m_pplnLayout) - ;//TODO: app.logFail("Failed to create a Pipeline Layout!\n"); + logFail("Failed to create a Pipeline Layout!\n"); { video::IGPUComputePipeline::SCreationParams params = {}; @@ -113,7 +112,7 @@ class ITester params.shader.entryPoint = "main"; params.shader.shader = shader.get(); if (!m_device->createComputePipelines(nullptr, { ¶ms,1 }, &m_pipeline)) - ;//TODO: app.logFail("Failed to create pipelines (compile & link shaders)!\n"); + logFail("Failed to create pipelines (compile & link shaders)!\n"); } // Allocate memory of the input buffer @@ -125,7 +124,7 @@ class ITester params.usage = video::IGPUBuffer::EUF_STORAGE_BUFFER_BIT; core::smart_refctd_ptr inputBuff = m_device->createBuffer(std::move(params)); if (!inputBuff) - ;//TODO: app.logFail("Failed to create a GPU Buffer of size %d!\n", params.size); + logFail("Failed to create a GPU Buffer of size %d!\n", params.size); inputBuff->setObjectDebugName("emulated_float64_t output buffer"); @@ -134,7 +133,7 @@ class ITester m_inputBufferAllocation = m_device->allocate(reqs, inputBuff.get(), video::IDeviceMemoryAllocation::EMAF_NONE); if (!m_inputBufferAllocation.isValid()) - ;//TODO: app.logFail("Failed to allocate Device Memory compatible with our GPU Buffer!\n"); + logFail("Failed to allocate Device Memory compatible with our GPU Buffer!\n"); assert(inputBuff->getBoundMemory().memory == m_inputBufferAllocation.memory.get()); core::smart_refctd_ptr pool = m_device->createDescriptorPoolForDSLayouts(video::IDescriptorPool::ECF_NONE, { &dsLayout.get(),1 }); @@ -160,7 +159,7 @@ class ITester params.usage = video::IGPUBuffer::EUF_STORAGE_BUFFER_BIT; core::smart_refctd_ptr outputBuff = m_device->createBuffer(std::move(params)); if (!outputBuff) - ;//TODO: app.logFail("Failed to create a GPU Buffer of size %d!\n", params.size); + logFail("Failed to create a GPU Buffer of size %d!\n", params.size); outputBuff->setObjectDebugName("emulated_float64_t output buffer"); @@ -169,7 +168,7 @@ class ITester m_outputBufferAllocation = m_device->allocate(reqs, outputBuff.get(), video::IDeviceMemoryAllocation::EMAF_NONE); if (!m_outputBufferAllocation.isValid()) - ;//TODO: app.logFail("Failed to allocate Device Memory compatible with our GPU Buffer!\n"); + logFail("Failed to allocate Device Memory compatible with our GPU Buffer!\n"); assert(outputBuff->getBoundMemory().memory == m_outputBufferAllocation.memory.get()); core::smart_refctd_ptr pool = m_device->createDescriptorPoolForDSLayouts(video::IDescriptorPool::ECF_NONE, { &dsLayout.get(),1 }); @@ -186,7 +185,7 @@ class ITester } if (!m_outputBufferAllocation.memory->map({ 0ull,m_outputBufferAllocation.memory->getAllocationSize() }, video::IDeviceMemoryAllocation::EMCAF_READ)) - ;//TODO: app.logFail("Failed to map the Device Memory!\n"); + logFail("Failed to map the Device Memory!\n"); // if the mapping is not coherent the range needs to be invalidated to pull in new data for the CPU's caches const video::ILogicalDevice::MappedMemoryRange memoryRange(m_outputBufferAllocation.memory.get(), 0ull, m_outputBufferAllocation.memory->getAllocationSize()); @@ -291,7 +290,7 @@ class ITester { // Update input buffer if (!m_inputBufferAllocation.memory->map({ 0ull,m_inputBufferAllocation.memory->getAllocationSize() }, video::IDeviceMemoryAllocation::EMCAF_READ)) - __debugbreak();//TODO: app.logFail("Failed to map the Device Memory!\n"); + logFail("Failed to map the Device Memory!\n"); const video::ILogicalDevice::MappedMemoryRange memoryRange(m_inputBufferAllocation.memory.get(), 0ull, m_inputBufferAllocation.memory->getAllocationSize()); if (!m_inputBufferAllocation.memory->getMemoryPropertyFlags().hasFlags(video::IDeviceMemoryAllocation::EMPF_HOST_COHERENT_BIT)) @@ -331,6 +330,13 @@ class ITester private: static constexpr float MaxAllowedError = 0.001f; + + template + inline void logFail(const char* msg, Args&&... args) + { + m_logger->log(msg, system::ILogger::ELL_ERROR, std::forward(args)...); + exit(-1); + } }; class CTgmathTester final : public ITester From bcd079a474f0e401954de7e303602fc3a869d306 Mon Sep 17 00:00:00 2001 From: Przemek Date: Tue, 28 Jan 2025 12:17:31 +0100 Subject: [PATCH 74/83] Fixed gpu tests --- 22_CppCompat/Testers.h | 4 +++- .../app_resources/intrinsicsTest.comp.hlsl | 16 ++++++++++++++++ 22_CppCompat/main.cpp | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 22_CppCompat/app_resources/intrinsicsTest.comp.hlsl diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index bff06370f..80f8c5add 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -18,6 +18,8 @@ class ITester struct PipelineSetupData { + std::string testShaderPath; + core::smart_refctd_ptr device; core::smart_refctd_ptr api; core::smart_refctd_ptr assetMgr; @@ -48,7 +50,7 @@ class ITester asset::IAssetLoader::SAssetLoadParams lp = {}; lp.logger = m_logger.get(); lp.workingDirectory = ""; // virtual root - auto assetBundle = m_assetMgr->getAsset("app_resources/tgmathTest.comp.hlsl", lp); + auto assetBundle = m_assetMgr->getAsset(pipleineSetupData.testShaderPath, lp); const auto assets = assetBundle.getContents(); if (assets.empty()) { diff --git a/22_CppCompat/app_resources/intrinsicsTest.comp.hlsl b/22_CppCompat/app_resources/intrinsicsTest.comp.hlsl new file mode 100644 index 000000000..3e634ed1f --- /dev/null +++ b/22_CppCompat/app_resources/intrinsicsTest.comp.hlsl @@ -0,0 +1,16 @@ +//// Copyright (C) 2023-2024 - DevSH Graphics Programming Sp. z O.O. +//// This file is part of the "Nabla Engine". +//// For conditions of distribution and use, see copyright notice in nabla.h +#pragma shader_stage(compute) + +#include "common.hlsl" + +[[vk::binding(0, 0)]] RWStructuredBuffer inputTestValues; +[[vk::binding(1, 0)]] RWStructuredBuffer outputTestValues; + +[numthreads(16, 1, 1)] +void main(uint3 invocationID : SV_DispatchThreadID) +{ + if(invocationID.x == 0) + outputTestValues[0].fillTestValues(inputTestValues[0]); +} diff --git a/22_CppCompat/main.cpp b/22_CppCompat/main.cpp index 58d4627bf..17b658bb1 100644 --- a/22_CppCompat/main.cpp +++ b/22_CppCompat/main.cpp @@ -68,11 +68,13 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa { CTgmathTester tgmathTester; + pplnSetupData.testShaderPath = "app_resources/tgmathTest.comp.hlsl"; tgmathTester.setupPipeline(pplnSetupData); tgmathTester.performTests(); } { CIntrinsicsTester intrinsicsTester; + pplnSetupData.testShaderPath = "app_resources/intrinsicsTest.comp.hlsl"; intrinsicsTester.setupPipeline(pplnSetupData); intrinsicsTester.performTests(); } From 071446826a7a11d28ece2db6b07cf30e3091eebb Mon Sep 17 00:00:00 2001 From: Przemek Date: Tue, 28 Jan 2025 12:57:30 +0100 Subject: [PATCH 75/83] Fixes --- 22_CppCompat/Testers.h | 13 +++++++------ 22_CppCompat/main.cpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index 80f8c5add..a8486fdca 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -119,7 +119,7 @@ class ITester // Allocate memory of the input buffer { - constexpr size_t BufferSize = sizeof(TgmathIntputTestValues); + constexpr size_t BufferSize = sizeof(InputStruct); video::IGPUBuffer::SCreationParams params = {}; params.size = BufferSize; @@ -519,6 +519,7 @@ class CIntrinsicsTester final : public ITester std::uniform_real_distribution realDistributionNeg(-50.0f, -1.0f); std::uniform_real_distribution realDistributionPos(1.0f, 50.0f); std::uniform_real_distribution realDistribution(-100.0f, 100.0f); + std::uniform_real_distribution realDistributionSmall(1.0f, 4.0f); std::uniform_int_distribution intDistribution(-100, 100); std::uniform_int_distribution uintDistribution(0, 100); @@ -538,9 +539,9 @@ class CIntrinsicsTester final : public ITester commonTestInputValues.dotLhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); commonTestInputValues.dotRhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); commonTestInputValues.determinant = float32_t3x3( - realDistribution(mt), realDistribution(mt), realDistribution(mt), - realDistribution(mt), realDistribution(mt), realDistribution(mt), - realDistribution(mt), realDistribution(mt), realDistribution(mt) + realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), + realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), + realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt) ); commonTestInputValues.findMSB = realDistribution(mt); commonTestInputValues.findLSB = realDistribution(mt); @@ -586,7 +587,7 @@ class CIntrinsicsTester final : public ITester commonTestInputValues.bitReverseVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); commonTestInputValues.fracVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - // use std library or glm functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values + // use std library or glm functions to determine expected test values, the output of functions from intrinsics.hlsl will be verified against these values IntrinsicsTestValues expectedTestValues; expectedTestValues.bitCount = glm::bitCount(commonTestInputValues.bitCount); expectedTestValues.clamp = glm::clamp(commonTestInputValues.clampVal, commonTestInputValues.clampMin, commonTestInputValues.clampMax); @@ -637,7 +638,7 @@ class CIntrinsicsTester final : public ITester expectedTestValues.inverse = reinterpret_cast(inverseGlm); performCpuTests(commonTestInputValues, expectedTestValues); - //performGpuTests(commonTestInputValues, expectedTestValues); + performGpuTests(commonTestInputValues, expectedTestValues); } m_logger->log("intrinsics.hlsl TESTS DONE.", system::ILogger::ELL_PERFORMANCE); } diff --git a/22_CppCompat/main.cpp b/22_CppCompat/main.cpp index 17b658bb1..31352d6bc 100644 --- a/22_CppCompat/main.cpp +++ b/22_CppCompat/main.cpp @@ -75,7 +75,7 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa { CIntrinsicsTester intrinsicsTester; pplnSetupData.testShaderPath = "app_resources/intrinsicsTest.comp.hlsl"; - intrinsicsTester.setupPipeline(pplnSetupData); + intrinsicsTester.setupPipeline(pplnSetupData); intrinsicsTester.performTests(); } From c39b0df3fd4469dbafdfc0c638bd41e2062964c5 Mon Sep 17 00:00:00 2001 From: Przemek Date: Wed, 29 Jan 2025 11:23:04 +0100 Subject: [PATCH 76/83] Renamed `lerp` to `mix` --- 22_CppCompat/Testers.h | 24 ++++++++++++------------ 22_CppCompat/app_resources/common.hlsl | 20 ++++++++++---------- 22_CppCompat/main.cpp | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index a8486fdca..5a8840dd0 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -363,9 +363,9 @@ class CTgmathTester final : public ITester // Set input thest values that will be used in both CPU and GPU tests TgmathIntputTestValues commonTestInputValues; commonTestInputValues.floor = realDistribution(mt); - commonTestInputValues.lerpX = realDistributionNeg(mt); - commonTestInputValues.lerpY = realDistributionPos(mt); - commonTestInputValues.lerpA = realDistributionZeroToOne(mt); + commonTestInputValues.mixX = realDistributionNeg(mt); + commonTestInputValues.mixY = realDistributionPos(mt); + commonTestInputValues.mixA = realDistributionZeroToOne(mt); commonTestInputValues.isnan = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::quiet_NaN(); commonTestInputValues.isinf = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::infinity(); commonTestInputValues.powX = realDistributionSmall(mt); @@ -382,9 +382,9 @@ class CTgmathTester final : public ITester commonTestInputValues.modf = realDistribution(mt); commonTestInputValues.floorVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.lerpXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); - commonTestInputValues.lerpYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); - commonTestInputValues.lerpAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); + commonTestInputValues.mixXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + commonTestInputValues.mixYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + commonTestInputValues.mixAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); commonTestInputValues.isnanVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); commonTestInputValues.isinfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); commonTestInputValues.powXVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); @@ -403,7 +403,7 @@ class CTgmathTester final : public ITester // use std library functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values TgmathTestValues expectedTestValues; expectedTestValues.floor = std::floor(commonTestInputValues.floor); - expectedTestValues.lerp = std::lerp(commonTestInputValues.lerpX, commonTestInputValues.lerpY, commonTestInputValues.lerpA); + expectedTestValues.mix = std::lerp(commonTestInputValues.mixX, commonTestInputValues.mixY, commonTestInputValues.mixA); expectedTestValues.isnan = std::isnan(commonTestInputValues.isnan); expectedTestValues.isinf = std::isinf(commonTestInputValues.isinf); expectedTestValues.pow = std::pow(commonTestInputValues.powX, commonTestInputValues.powY); @@ -423,9 +423,9 @@ class CTgmathTester final : public ITester expectedTestValues.floorVec = float32_t3(std::floor(commonTestInputValues.floorVec.x), std::floor(commonTestInputValues.floorVec.y), std::floor(commonTestInputValues.floorVec.z)); - expectedTestValues.lerpVec.x = std::lerp(commonTestInputValues.lerpXVec.x, commonTestInputValues.lerpYVec.x, commonTestInputValues.lerpAVec.x); - expectedTestValues.lerpVec.y = std::lerp(commonTestInputValues.lerpXVec.y, commonTestInputValues.lerpYVec.y, commonTestInputValues.lerpAVec.y); - expectedTestValues.lerpVec.z = std::lerp(commonTestInputValues.lerpXVec.z, commonTestInputValues.lerpYVec.z, commonTestInputValues.lerpAVec.z); + expectedTestValues.mixVec.x = std::lerp(commonTestInputValues.mixXVec.x, commonTestInputValues.mixYVec.x, commonTestInputValues.mixAVec.x); + expectedTestValues.mixVec.y = std::lerp(commonTestInputValues.mixXVec.y, commonTestInputValues.mixYVec.y, commonTestInputValues.mixAVec.y); + expectedTestValues.mixVec.z = std::lerp(commonTestInputValues.mixXVec.z, commonTestInputValues.mixYVec.z, commonTestInputValues.mixAVec.z); expectedTestValues.isnanVec = float32_t3(std::isnan(commonTestInputValues.isnanVec.x), std::isnan(commonTestInputValues.isnanVec.y), std::isnan(commonTestInputValues.isnanVec.z)); expectedTestValues.isinfVec = float32_t3(std::isinf(commonTestInputValues.isinfVec.x), std::isinf(commonTestInputValues.isinfVec.y), std::isinf(commonTestInputValues.isinfVec.z)); @@ -475,7 +475,7 @@ class CTgmathTester final : public ITester void verifyTestValues(const TgmathTestValues& expectedTestValues, const TgmathTestValues& testValues, ITester::TestType testType) { verifyTestValue("floor", expectedTestValues.floor, testValues.floor, testType); - verifyTestValue("lerp", expectedTestValues.lerp, testValues.lerp, testType); + verifyTestValue("mix", expectedTestValues.mix, testValues.mix, testType); verifyTestValue("isnan", expectedTestValues.isnan, testValues.isnan, testType); verifyTestValue("isinf", expectedTestValues.isinf, testValues.isinf, testType); verifyTestValue("pow", expectedTestValues.pow, testValues.pow, testType); @@ -491,7 +491,7 @@ class CTgmathTester final : public ITester verifyTestValue("modf", expectedTestValues.modf, testValues.modf, testType); verifyTestVector3dValue("floorVec", expectedTestValues.floorVec, testValues.floorVec, testType); - verifyTestVector3dValue("lerpVec", expectedTestValues.lerpVec, testValues.lerpVec, testType); + verifyTestVector3dValue("mixVec", expectedTestValues.mixVec, testValues.mixVec, testType); verifyTestVector3dValue("isnanVec", expectedTestValues.isnanVec, testValues.isnanVec, testType); verifyTestVector3dValue("isinfVec", expectedTestValues.isinfVec, testValues.isinfVec, testType); verifyTestVector3dValue("powVec", expectedTestValues.powVec, testValues.powVec, testType); diff --git a/22_CppCompat/app_resources/common.hlsl b/22_CppCompat/app_resources/common.hlsl index 74d9ff8e7..b4ddda9ef 100644 --- a/22_CppCompat/app_resources/common.hlsl +++ b/22_CppCompat/app_resources/common.hlsl @@ -42,9 +42,9 @@ using namespace nbl::hlsl; struct TgmathIntputTestValues { float floor; - float lerpX; - float lerpY; - float lerpA; + float mixX; + float mixY; + float mixA; float isnan; float isinf; float powX; @@ -61,9 +61,9 @@ struct TgmathIntputTestValues float modf; float32_t3 floorVec; - float32_t3 lerpXVec; - float32_t3 lerpYVec; - float32_t3 lerpAVec; + float32_t3 mixXVec; + float32_t3 mixYVec; + float32_t3 mixAVec; float32_t3 isnanVec; float32_t3 isinfVec; float32_t3 powXVec; @@ -83,7 +83,7 @@ struct TgmathIntputTestValues struct TgmathTestValues { float floor; - float lerp; + float mix; int isnan; int isinf; float pow; @@ -99,7 +99,7 @@ struct TgmathTestValues float modf; float32_t3 floorVec; - float32_t3 lerpVec; + float32_t3 mixVec; #ifndef __HLSL_VERSION nbl::hlsl::vector isnanVec; nbl::hlsl::vector isinfVec; @@ -123,7 +123,7 @@ struct TgmathTestValues void fillTestValues(NBL_CONST_REF_ARG(TgmathIntputTestValues) input) { floor = nbl::hlsl::floor(input.floor); - lerp = nbl::hlsl::lerp(input.lerpX, input.lerpY, input.lerpA); + mix = nbl::hlsl::mix(input.mixX, input.mixY, input.mixA); isnan = nbl::hlsl::isnan(input.isnan); isinf = nbl::hlsl::isinf(input.isinf); pow = nbl::hlsl::pow(input.powX, input.powY); @@ -139,7 +139,7 @@ struct TgmathTestValues modf = nbl::hlsl::modf(input.modf); floorVec = nbl::hlsl::floor(input.floorVec); - lerpVec = nbl::hlsl::lerp(input.lerpXVec, input.lerpYVec, input.lerpAVec); + mixVec = nbl::hlsl::mix(input.mixXVec, input.mixYVec, input.mixAVec); isnanVec = nbl::hlsl::isnan(input.isnanVec); isinfVec = nbl::hlsl::isinf(input.isinfVec); powVec = nbl::hlsl::pow(input.powXVec, input.powYVec); diff --git a/22_CppCompat/main.cpp b/22_CppCompat/main.cpp index 31352d6bc..ff9d3d5f7 100644 --- a/22_CppCompat/main.cpp +++ b/22_CppCompat/main.cpp @@ -582,7 +582,7 @@ void cpu_tests() auto zero = cross(x,x); auto lenX2 = dot(x,x); //auto z_inv = inverse(z); //busted return type conversion - auto mid = nbl::hlsl::lerp(x,x,0.5f); + auto mid = nbl::hlsl::mix(x,x,0.5f); //auto w = transpose(y); //also busted From 086987d59770a2c9ef1802c84aa51e1fba52d8ce Mon Sep 17 00:00:00 2001 From: Przemek Date: Wed, 29 Jan 2025 14:32:37 +0100 Subject: [PATCH 77/83] Added log2 tests --- 22_CppCompat/Testers.h | 6 ++++++ 22_CppCompat/app_resources/common.hlsl | 10 ++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index 5a8840dd0..5fb315e46 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -373,6 +373,7 @@ class CTgmathTester final : public ITester commonTestInputValues.exp = realDistributionSmall(mt); commonTestInputValues.exp2 = realDistributionSmall(mt); commonTestInputValues.log = realDistribution(mt); + commonTestInputValues.log2 = realDistribution(mt); commonTestInputValues.absF = realDistribution(mt); commonTestInputValues.absI = intDistribution(mt); commonTestInputValues.sqrt = realDistribution(mt); @@ -392,6 +393,7 @@ class CTgmathTester final : public ITester commonTestInputValues.expVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); commonTestInputValues.exp2Vec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); commonTestInputValues.logVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.log2Vec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); commonTestInputValues.absFVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); commonTestInputValues.absIVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); commonTestInputValues.sqrtVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); @@ -410,6 +412,7 @@ class CTgmathTester final : public ITester expectedTestValues.exp = std::exp(commonTestInputValues.exp); expectedTestValues.exp2 = std::exp2(commonTestInputValues.exp2); expectedTestValues.log = std::log(commonTestInputValues.log); + expectedTestValues.log2 = std::log2(commonTestInputValues.log2); expectedTestValues.absF = std::abs(commonTestInputValues.absF); expectedTestValues.absI = std::abs(commonTestInputValues.absI); expectedTestValues.sqrt = std::sqrt(commonTestInputValues.sqrt); @@ -437,6 +440,7 @@ class CTgmathTester final : public ITester expectedTestValues.expVec = float32_t3(std::exp(commonTestInputValues.expVec.x), std::exp(commonTestInputValues.expVec.y), std::exp(commonTestInputValues.expVec.z)); expectedTestValues.exp2Vec = float32_t3(std::exp2(commonTestInputValues.exp2Vec.x), std::exp2(commonTestInputValues.exp2Vec.y), std::exp2(commonTestInputValues.exp2Vec.z)); expectedTestValues.logVec = float32_t3(std::log(commonTestInputValues.logVec.x), std::log(commonTestInputValues.logVec.y), std::log(commonTestInputValues.logVec.z)); + expectedTestValues.log2Vec = float32_t3(std::log2(commonTestInputValues.log2Vec.x), std::log2(commonTestInputValues.log2Vec.y), std::log2(commonTestInputValues.log2Vec.z)); expectedTestValues.absFVec = float32_t3(std::abs(commonTestInputValues.absFVec.x), std::abs(commonTestInputValues.absFVec.y), std::abs(commonTestInputValues.absFVec.z)); expectedTestValues.absIVec = float32_t3(std::abs(commonTestInputValues.absIVec.x), std::abs(commonTestInputValues.absIVec.y), std::abs(commonTestInputValues.absIVec.z)); expectedTestValues.sqrtVec = float32_t3(std::sqrt(commonTestInputValues.sqrtVec.x), std::sqrt(commonTestInputValues.sqrtVec.y), std::sqrt(commonTestInputValues.sqrtVec.z)); @@ -482,6 +486,7 @@ class CTgmathTester final : public ITester verifyTestValue("exp", expectedTestValues.exp, testValues.exp, testType); verifyTestValue("exp2", expectedTestValues.exp2, testValues.exp2, testType); verifyTestValue("log", expectedTestValues.log, testValues.log, testType); + verifyTestValue("log2", expectedTestValues.log2, testValues.log2, testType); verifyTestValue("absF", expectedTestValues.absF, testValues.absF, testType); verifyTestValue("absI", expectedTestValues.absI, testValues.absI, testType); verifyTestValue("sqrt", expectedTestValues.sqrt, testValues.sqrt, testType); @@ -498,6 +503,7 @@ class CTgmathTester final : public ITester verifyTestVector3dValue("expVec", expectedTestValues.expVec, testValues.expVec, testType); verifyTestVector3dValue("exp2Vec", expectedTestValues.exp2Vec, testValues.exp2Vec, testType); verifyTestVector3dValue("logVec", expectedTestValues.logVec, testValues.logVec, testType); + verifyTestVector3dValue("log2Vec", expectedTestValues.log2Vec, testValues.log2Vec, testType); verifyTestVector3dValue("absFVec", expectedTestValues.absFVec, testValues.absFVec, testType); verifyTestVector3dValue("absIVec", expectedTestValues.absIVec, testValues.absIVec, testType); verifyTestVector3dValue("sqrtVec", expectedTestValues.sqrtVec, testValues.sqrtVec, testType); diff --git a/22_CppCompat/app_resources/common.hlsl b/22_CppCompat/app_resources/common.hlsl index b4ddda9ef..e1d445da9 100644 --- a/22_CppCompat/app_resources/common.hlsl +++ b/22_CppCompat/app_resources/common.hlsl @@ -36,7 +36,7 @@ #include #include -// tmath.hlsl and intrinsics.hlsl tests +// tgmath.hlsl and intrinsics.hlsl tests using namespace nbl::hlsl; struct TgmathIntputTestValues @@ -52,6 +52,7 @@ struct TgmathIntputTestValues float exp; float exp2; float log; + float log2; float absF; int absI; float sqrt; @@ -71,6 +72,7 @@ struct TgmathIntputTestValues float32_t3 expVec; float32_t3 exp2Vec; float32_t3 logVec; + float32_t3 log2Vec; float32_t3 absFVec; int32_t3 absIVec; float32_t3 sqrtVec; @@ -90,6 +92,7 @@ struct TgmathTestValues float exp; float exp2; float log; + float log2; float absF; int absI; float sqrt; @@ -112,6 +115,7 @@ struct TgmathTestValues float32_t3 expVec; float32_t3 exp2Vec; float32_t3 logVec; + float32_t3 log2Vec; float32_t3 absFVec; int32_t3 absIVec; float32_t3 sqrtVec; @@ -130,6 +134,7 @@ struct TgmathTestValues exp = nbl::hlsl::exp(input.exp); exp2 = nbl::hlsl::exp2(input.exp2); log = nbl::hlsl::log(input.log); + log2 = nbl::hlsl::log2(input.log2); absF = nbl::hlsl::abs(input.absF); absI = nbl::hlsl::abs(input.absI); sqrt = nbl::hlsl::sqrt(input.sqrt); @@ -146,6 +151,7 @@ struct TgmathTestValues expVec = nbl::hlsl::exp(input.expVec); exp2Vec = nbl::hlsl::exp2(input.exp2Vec); logVec = nbl::hlsl::log(input.logVec); + log2Vec = nbl::hlsl::log2(input.log2Vec); absFVec = nbl::hlsl::abs(input.absFVec); absIVec = nbl::hlsl::abs(input.absIVec); sqrtVec = nbl::hlsl::sqrt(input.sqrtVec); @@ -263,4 +269,4 @@ struct IntrinsicsTestValues } }; -#endif \ No newline at end of file +#endif From 06ed5335fa96482264412eeb4445220396608310 Mon Sep 17 00:00:00 2001 From: Przemek Date: Thu, 30 Jan 2025 11:51:32 +0100 Subject: [PATCH 78/83] Extened tgmath tests --- 22_CppCompat/Testers.h | 113 +++++++++++++++++++------ 22_CppCompat/app_resources/common.hlsl | 62 +++++++++++--- 22_CppCompat/main.cpp | 2 +- 3 files changed, 142 insertions(+), 35 deletions(-) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index 5fb315e46..9bcf36ae2 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -222,14 +222,6 @@ class ITester ss << "nbl::hlsl::" << memberName << " produced incorrect output! test value: " << testVal << " expected value: " << expectedVal << '\n'; - if (memberName == "pow") - { - auto a = expectedVal; - auto b = testVal; - std::cout << std::bitset<32>(reinterpret_cast(a)) << std::endl; - std::cout << std::bitset<32>(reinterpret_cast(b)) << std::endl; - } - m_logger->log(ss.str().c_str(), system::ILogger::ELL_ERROR); } @@ -351,7 +343,6 @@ class CTgmathTester final : public ITester std::uniform_real_distribution realDistributionNeg(-50.0f, -1.0f); std::uniform_real_distribution realDistributionPos(1.0f, 50.0f); - std::uniform_real_distribution realDistributionZeroToOne(0.0f, 1.0f); std::uniform_real_distribution realDistribution(-100.0f, 100.0f); std::uniform_real_distribution realDistributionSmall(1.0f, 4.0f); std::uniform_int_distribution intDistribution(-100, 100); @@ -363,9 +354,6 @@ class CTgmathTester final : public ITester // Set input thest values that will be used in both CPU and GPU tests TgmathIntputTestValues commonTestInputValues; commonTestInputValues.floor = realDistribution(mt); - commonTestInputValues.mixX = realDistributionNeg(mt); - commonTestInputValues.mixY = realDistributionPos(mt); - commonTestInputValues.mixA = realDistributionZeroToOne(mt); commonTestInputValues.isnan = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::quiet_NaN(); commonTestInputValues.isinf = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::infinity(); commonTestInputValues.powX = realDistributionSmall(mt); @@ -381,11 +369,17 @@ class CTgmathTester final : public ITester commonTestInputValues.cos = realDistribution(mt); commonTestInputValues.acos = realDistribution(mt); commonTestInputValues.modf = realDistribution(mt); + commonTestInputValues.round = realDistribution(mt); + commonTestInputValues.roundEven = coinFlipDistribution(mt) ? realDistributionSmall(mt) : (static_cast(intDistribution(mt) / 2) + 0.5f); + commonTestInputValues.trunc = realDistribution(mt); + commonTestInputValues.ceil = realDistribution(mt); + commonTestInputValues.fmaX = realDistribution(mt); + commonTestInputValues.fmaY = realDistribution(mt); + commonTestInputValues.fmaZ = realDistribution(mt); + commonTestInputValues.ldexpArg = realDistributionSmall(mt); + commonTestInputValues.ldexpExp = intDistribution(mt); commonTestInputValues.floorVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.mixXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); - commonTestInputValues.mixYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); - commonTestInputValues.mixAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); commonTestInputValues.isnanVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); commonTestInputValues.isinfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); commonTestInputValues.powXVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); @@ -405,7 +399,6 @@ class CTgmathTester final : public ITester // use std library functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values TgmathTestValues expectedTestValues; expectedTestValues.floor = std::floor(commonTestInputValues.floor); - expectedTestValues.mix = std::lerp(commonTestInputValues.mixX, commonTestInputValues.mixY, commonTestInputValues.mixA); expectedTestValues.isnan = std::isnan(commonTestInputValues.isnan); expectedTestValues.isinf = std::isinf(commonTestInputValues.isinf); expectedTestValues.pow = std::pow(commonTestInputValues.powX, commonTestInputValues.powY); @@ -423,12 +416,31 @@ class CTgmathTester final : public ITester float tmp; expectedTestValues.modf = std::modf(commonTestInputValues.modf, &tmp); } + expectedTestValues.round = std::round(commonTestInputValues.round); + // TODO: uncomment when C++23 + //expectedTestValues.roundEven = std::roundeven(commonTestInputValues.roundEven); + // TODO: remove when C++23 + auto roundeven = [](const float& val) -> float + { + float tmp; + if (std::abs(std::modf(val, &tmp)) == 0.5f) + { + int32_t result = static_cast(val); + if (result % 2 != 0) + result >= 0 ? ++result : --result; + return result; + } + + return std::round(val); + }; + expectedTestValues.roundEven = roundeven(commonTestInputValues.roundEven); - expectedTestValues.floorVec = float32_t3(std::floor(commonTestInputValues.floorVec.x), std::floor(commonTestInputValues.floorVec.y), std::floor(commonTestInputValues.floorVec.z)); + expectedTestValues.trunc = std::trunc(commonTestInputValues.trunc); + expectedTestValues.ceil = std::ceil(commonTestInputValues.ceil); + expectedTestValues.fma = std::fma(commonTestInputValues.fmaX, commonTestInputValues.fmaY, commonTestInputValues.fmaZ); + expectedTestValues.ldexp = std::ldexp(commonTestInputValues.ldexpArg, commonTestInputValues.ldexpExp); - expectedTestValues.mixVec.x = std::lerp(commonTestInputValues.mixXVec.x, commonTestInputValues.mixYVec.x, commonTestInputValues.mixAVec.x); - expectedTestValues.mixVec.y = std::lerp(commonTestInputValues.mixXVec.y, commonTestInputValues.mixYVec.y, commonTestInputValues.mixAVec.y); - expectedTestValues.mixVec.z = std::lerp(commonTestInputValues.mixXVec.z, commonTestInputValues.mixYVec.z, commonTestInputValues.mixAVec.z); + expectedTestValues.floorVec = float32_t3(std::floor(commonTestInputValues.floorVec.x), std::floor(commonTestInputValues.floorVec.y), std::floor(commonTestInputValues.floorVec.z)); expectedTestValues.isnanVec = float32_t3(std::isnan(commonTestInputValues.isnanVec.x), std::isnan(commonTestInputValues.isnanVec.y), std::isnan(commonTestInputValues.isnanVec.z)); expectedTestValues.isinfVec = float32_t3(std::isinf(commonTestInputValues.isinfVec.x), std::isinf(commonTestInputValues.isinfVec.y), std::isinf(commonTestInputValues.isinfVec.z)); @@ -451,6 +463,36 @@ class CTgmathTester final : public ITester float tmp; expectedTestValues.modfVec = float32_t3(std::modf(commonTestInputValues.modfVec.x, &tmp), std::modf(commonTestInputValues.modfVec.y, &tmp), std::modf(commonTestInputValues.modfVec.z, &tmp)); } + expectedTestValues.roundVec = float32_t3( + std::round(commonTestInputValues.roundVec.x), + std::round(commonTestInputValues.roundVec.y), + std::round(commonTestInputValues.roundVec.z) + ); + // TODO: uncomment when C++23 + //expectedTestValues.roundEven = float32_t( + // std::roundeven(commonTestInputValues.roundEvenVec.x), + // std::roundeven(commonTestInputValues.roundEvenVec.y), + // std::roundeven(commonTestInputValues.roundEvenVec.z) + // ); + // TODO: remove when C++23 + expectedTestValues.roundEvenVec = float32_t3( + roundeven(commonTestInputValues.roundEvenVec.x), + roundeven(commonTestInputValues.roundEvenVec.y), + roundeven(commonTestInputValues.roundEvenVec.z) + ); + + expectedTestValues.truncVec = float32_t3(std::trunc(commonTestInputValues.truncVec.x), std::trunc(commonTestInputValues.truncVec.y), std::trunc(commonTestInputValues.truncVec.z)); + expectedTestValues.ceilVec = float32_t3(std::ceil(commonTestInputValues.ceilVec.x), std::ceil(commonTestInputValues.ceilVec.y), std::ceil(commonTestInputValues.ceilVec.z)); + expectedTestValues.fmaVec = float32_t3( + std::fma(commonTestInputValues.fmaXVec.x, commonTestInputValues.fmaYVec.x, commonTestInputValues.fmaZVec.x), + std::fma(commonTestInputValues.fmaXVec.y, commonTestInputValues.fmaYVec.y, commonTestInputValues.fmaZVec.y), + std::fma(commonTestInputValues.fmaXVec.z, commonTestInputValues.fmaYVec.z, commonTestInputValues.fmaZVec.z) + ); + expectedTestValues.ldexpVec = float32_t3( + std::ldexp(commonTestInputValues.ldexpArgVec.x, commonTestInputValues.ldexpExpVec.x), + std::ldexp(commonTestInputValues.ldexpArgVec.y, commonTestInputValues.ldexpExpVec.y), + std::ldexp(commonTestInputValues.ldexpArgVec.z, commonTestInputValues.ldexpExpVec.z) + ); performCpuTests(commonTestInputValues, expectedTestValues); performGpuTests(commonTestInputValues, expectedTestValues); @@ -479,7 +521,6 @@ class CTgmathTester final : public ITester void verifyTestValues(const TgmathTestValues& expectedTestValues, const TgmathTestValues& testValues, ITester::TestType testType) { verifyTestValue("floor", expectedTestValues.floor, testValues.floor, testType); - verifyTestValue("mix", expectedTestValues.mix, testValues.mix, testType); verifyTestValue("isnan", expectedTestValues.isnan, testValues.isnan, testType); verifyTestValue("isinf", expectedTestValues.isinf, testValues.isinf, testType); verifyTestValue("pow", expectedTestValues.pow, testValues.pow, testType); @@ -494,9 +535,14 @@ class CTgmathTester final : public ITester verifyTestValue("cos", expectedTestValues.cos, testValues.cos, testType); verifyTestValue("acos", expectedTestValues.acos, testValues.acos, testType); verifyTestValue("modf", expectedTestValues.modf, testValues.modf, testType); + verifyTestValue("round", expectedTestValues.round, testValues.round, testType); + verifyTestValue("roundEven", expectedTestValues.roundEven, testValues.roundEven, testType); + verifyTestValue("trunc", expectedTestValues.trunc, testValues.trunc, testType); + verifyTestValue("ceil", expectedTestValues.ceil, testValues.ceil, testType); + verifyTestValue("fma", expectedTestValues.fma, testValues.fma, testType); + verifyTestValue("ldexp", expectedTestValues.ldexp, testValues.ldexp, testType); verifyTestVector3dValue("floorVec", expectedTestValues.floorVec, testValues.floorVec, testType); - verifyTestVector3dValue("mixVec", expectedTestValues.mixVec, testValues.mixVec, testType); verifyTestVector3dValue("isnanVec", expectedTestValues.isnanVec, testValues.isnanVec, testType); verifyTestVector3dValue("isinfVec", expectedTestValues.isinfVec, testValues.isinfVec, testType); verifyTestVector3dValue("powVec", expectedTestValues.powVec, testValues.powVec, testType); @@ -511,6 +557,12 @@ class CTgmathTester final : public ITester verifyTestVector3dValue("cosVec", expectedTestValues.cosVec, testValues.cosVec, testType); verifyTestVector3dValue("acosVec", expectedTestValues.acosVec, testValues.acosVec, testType); verifyTestVector3dValue("modfVec", expectedTestValues.modfVec, testValues.modfVec, testType); + verifyTestVector3dValue("roundVec", expectedTestValues.roundVec, testValues.roundVec, testType); + verifyTestVector3dValue("roundEvenVec", expectedTestValues.roundEvenVec, testValues.roundEvenVec, testType); + verifyTestVector3dValue("truncVec", expectedTestValues.truncVec, testValues.truncVec, testType); + verifyTestVector3dValue("ceilVec", expectedTestValues.ceilVec, testValues.ceilVec, testType); + verifyTestVector3dValue("fmaVec", expectedTestValues.fmaVec, testValues.fmaVec, testType); + verifyTestVector3dValue("ldexp", expectedTestValues.ldexpVec, testValues.ldexpVec, testType); } }; @@ -524,6 +576,7 @@ class CIntrinsicsTester final : public ITester std::uniform_real_distribution realDistributionNeg(-50.0f, -1.0f); std::uniform_real_distribution realDistributionPos(1.0f, 50.0f); + std::uniform_real_distribution realDistributionZeroToOne(0.0f, 1.0f); std::uniform_real_distribution realDistribution(-100.0f, 100.0f); std::uniform_real_distribution realDistributionSmall(1.0f, 4.0f); std::uniform_int_distribution intDistribution(-100, 100); @@ -542,8 +595,8 @@ class CIntrinsicsTester final : public ITester commonTestInputValues.clampMax = realDistributionPos(mt); commonTestInputValues.length = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); commonTestInputValues.normalize = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.dotLhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.dotRhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.dotLhs = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + commonTestInputValues.dotRhs = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); commonTestInputValues.determinant = float32_t3x3( realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), @@ -578,6 +631,9 @@ class CIntrinsicsTester final : public ITester commonTestInputValues.rsqrt = realDistributionPos(mt); commonTestInputValues.bitReverse = realDistribution(mt); commonTestInputValues.frac = realDistribution(mt); + commonTestInputValues.mixX = realDistributionNeg(mt); + commonTestInputValues.mixY = realDistributionPos(mt); + commonTestInputValues.mixA = realDistributionZeroToOne(mt); commonTestInputValues.bitCountVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); commonTestInputValues.clampValVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); @@ -592,6 +648,9 @@ class CIntrinsicsTester final : public ITester commonTestInputValues.rsqrtVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); commonTestInputValues.bitReverseVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); commonTestInputValues.fracVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.mixXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + commonTestInputValues.mixYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + commonTestInputValues.mixAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); // use std library or glm functions to determine expected test values, the output of functions from intrinsics.hlsl will be verified against these values IntrinsicsTestValues expectedTestValues; @@ -605,6 +664,7 @@ class CIntrinsicsTester final : public ITester expectedTestValues.min = glm::min(commonTestInputValues.minA, commonTestInputValues.minB); expectedTestValues.max = glm::max(commonTestInputValues.maxA, commonTestInputValues.maxB); expectedTestValues.rsqrt = (1.0f / std::sqrt(commonTestInputValues.rsqrt)); + expectedTestValues.mix = std::lerp(commonTestInputValues.mixX, commonTestInputValues.mixY, commonTestInputValues.mixA); expectedTestValues.frac = commonTestInputValues.frac - std::floor(commonTestInputValues.frac); expectedTestValues.bitReverse = glm::bitfieldReverse(commonTestInputValues.bitReverse); @@ -635,6 +695,9 @@ class CIntrinsicsTester final : public ITester commonTestInputValues.fracVec.x - std::floor(commonTestInputValues.fracVec.x), commonTestInputValues.fracVec.y - std::floor(commonTestInputValues.fracVec.y), commonTestInputValues.fracVec.z - std::floor(commonTestInputValues.fracVec.z)); + expectedTestValues.mixVec.x = std::lerp(commonTestInputValues.mixXVec.x, commonTestInputValues.mixYVec.x, commonTestInputValues.mixAVec.x); + expectedTestValues.mixVec.y = std::lerp(commonTestInputValues.mixXVec.y, commonTestInputValues.mixYVec.y, commonTestInputValues.mixAVec.y); + expectedTestValues.mixVec.z = std::lerp(commonTestInputValues.mixXVec.z, commonTestInputValues.mixYVec.z, commonTestInputValues.mixAVec.z); auto mulGlm = nbl::hlsl::mul(commonTestInputValues.mulLhs, commonTestInputValues.mulRhs); expectedTestValues.mul = reinterpret_cast(mulGlm); @@ -681,6 +744,7 @@ class CIntrinsicsTester final : public ITester verifyTestValue("rsqrt", expectedTestValues.rsqrt, testValues.rsqrt, testType); verifyTestValue("frac", expectedTestValues.frac, testValues.frac, testType); verifyTestValue("bitReverse", expectedTestValues.bitReverse, testValues.bitReverse, testType); + verifyTestValue("mix", expectedTestValues.mix, testValues.mix, testType); verifyTestVector3dValue("normalize", expectedTestValues.normalize, testValues.normalize, testType); verifyTestVector3dValue("cross", expectedTestValues.cross, testValues.cross, testType); @@ -693,6 +757,7 @@ class CIntrinsicsTester final : public ITester verifyTestVector3dValue("rsqrtVec", expectedTestValues.rsqrtVec, testValues.rsqrtVec, testType); verifyTestVector3dValue("bitReverseVec", expectedTestValues.bitReverseVec, testValues.bitReverseVec, testType); verifyTestVector3dValue("fracVec", expectedTestValues.fracVec, testValues.fracVec, testType); + verifyTestVector3dValue("mixVec", expectedTestValues.mixVec, testValues.mixVec, testType); verifyTestMatrix3x3Value("mul", expectedTestValues.mul, testValues.mul, testType); verifyTestMatrix3x3Value("transpose", expectedTestValues.transpose, testValues.transpose, testType); diff --git a/22_CppCompat/app_resources/common.hlsl b/22_CppCompat/app_resources/common.hlsl index e1d445da9..177e172c7 100644 --- a/22_CppCompat/app_resources/common.hlsl +++ b/22_CppCompat/app_resources/common.hlsl @@ -42,9 +42,6 @@ using namespace nbl::hlsl; struct TgmathIntputTestValues { float floor; - float mixX; - float mixY; - float mixA; float isnan; float isinf; float powX; @@ -60,11 +57,17 @@ struct TgmathIntputTestValues float cos; float acos; float modf; + float round; + float roundEven; + float trunc; + float ceil; + float fmaX; + float fmaY; + float fmaZ; + float ldexpArg; + int ldexpExp; float32_t3 floorVec; - float32_t3 mixXVec; - float32_t3 mixYVec; - float32_t3 mixAVec; float32_t3 isnanVec; float32_t3 isinfVec; float32_t3 powXVec; @@ -80,12 +83,20 @@ struct TgmathIntputTestValues float32_t3 cosVec; float32_t3 acosVec; float32_t3 modfVec; + float32_t3 roundVec; + float32_t3 roundEvenVec; + float32_t3 truncVec; + float32_t3 ceilVec; + float32_t3 fmaXVec; + float32_t3 fmaYVec; + float32_t3 fmaZVec; + float32_t3 ldexpArgVec; + int32_t3 ldexpExpVec; }; struct TgmathTestValues { float floor; - float mix; int isnan; int isinf; float pow; @@ -100,9 +111,14 @@ struct TgmathTestValues float cos; float acos; float modf; + float round; + float roundEven; + float trunc; + float ceil; + float fma; + float ldexp; float32_t3 floorVec; - float32_t3 mixVec; #ifndef __HLSL_VERSION nbl::hlsl::vector isnanVec; nbl::hlsl::vector isinfVec; @@ -123,11 +139,16 @@ struct TgmathTestValues float32_t3 sinVec; float32_t3 acosVec; float32_t3 modfVec; + float32_t3 roundVec; + float32_t3 roundEvenVec; + float32_t3 truncVec; + float32_t3 ceilVec; + float32_t3 fmaVec; + float32_t3 ldexpVec; void fillTestValues(NBL_CONST_REF_ARG(TgmathIntputTestValues) input) { floor = nbl::hlsl::floor(input.floor); - mix = nbl::hlsl::mix(input.mixX, input.mixY, input.mixA); isnan = nbl::hlsl::isnan(input.isnan); isinf = nbl::hlsl::isinf(input.isinf); pow = nbl::hlsl::pow(input.powX, input.powY); @@ -142,9 +163,14 @@ struct TgmathTestValues cos = nbl::hlsl::cos(input.cos); acos = nbl::hlsl::acos(input.acos); modf = nbl::hlsl::modf(input.modf); + round = nbl::hlsl::round(input.round); + roundEven = nbl::hlsl::roundEven(input.roundEven); + trunc = nbl::hlsl::trunc(input.trunc); + ceil = nbl::hlsl::ceil(input.ceil); + fma = nbl::hlsl::fma(input.fmaX, input.fmaY, input.fmaZ); + ldexp = nbl::hlsl::ldexp(input.ldexpArg, input.ldexpExp); floorVec = nbl::hlsl::floor(input.floorVec); - mixVec = nbl::hlsl::mix(input.mixXVec, input.mixYVec, input.mixAVec); isnanVec = nbl::hlsl::isnan(input.isnanVec); isinfVec = nbl::hlsl::isinf(input.isinfVec); powVec = nbl::hlsl::pow(input.powXVec, input.powYVec); @@ -159,6 +185,12 @@ struct TgmathTestValues cosVec = nbl::hlsl::cos(input.cosVec); acosVec = nbl::hlsl::acos(input.acosVec); modfVec = nbl::hlsl::modf(input.modfVec); + roundVec = nbl::hlsl::round(input.roundVec); + roundEvenVec = nbl::hlsl::roundEven(input.roundEvenVec); + truncVec = nbl::hlsl::trunc(input.truncVec); + ceilVec = nbl::hlsl::ceil(input.ceilVec); + fmaVec = nbl::hlsl::fma(input.fmaXVec, input.fmaYVec, input.fmaZVec); + ldexpVec = nbl::hlsl::ldexp(input.ldexpArgVec, input.ldexpExpVec); } }; @@ -188,6 +220,9 @@ struct IntrinsicsIntputTestValues float rsqrt; uint32_t bitReverse; float frac; + float mixX; + float mixY; + float mixA; int32_t3 bitCountVec; float32_t3 clampValVec; @@ -202,6 +237,9 @@ struct IntrinsicsIntputTestValues float32_t3 rsqrtVec; uint32_t3 bitReverseVec; float32_t3 fracVec; + float32_t3 mixXVec; + float32_t3 mixYVec; + float32_t3 mixAVec; }; struct IntrinsicsTestValues @@ -218,6 +256,7 @@ struct IntrinsicsTestValues float rsqrt; float frac; uint32_t bitReverse; + float mix; float32_t3 normalize; float32_t3 cross; @@ -230,6 +269,7 @@ struct IntrinsicsTestValues float32_t3 rsqrtVec; uint32_t3 bitReverseVec; float32_t3 fracVec; + float32_t3 mixVec; float32_t3x3 mul; float32_t3x3 transpose; @@ -255,6 +295,7 @@ struct IntrinsicsTestValues rsqrt = nbl::hlsl::rsqrt(input.rsqrt); bitReverse = nbl::hlsl::bitReverse(input.bitReverse); frac = nbl::hlsl::frac(input.frac); + mix = nbl::hlsl::mix(input.mixX, input.mixY, input.mixA); bitCountVec = nbl::hlsl::bitCount(input.bitCountVec); clampVec = nbl::hlsl::clamp(input.clampValVec, input.clampMinVec, input.clampMaxVec); @@ -266,6 +307,7 @@ struct IntrinsicsTestValues rsqrtVec = nbl::hlsl::rsqrt(input.rsqrtVec); bitReverseVec = nbl::hlsl::bitReverse(input.bitReverseVec); fracVec = nbl::hlsl::frac(input.fracVec); + mixVec = nbl::hlsl::mix(input.mixXVec, input.mixYVec, input.mixAVec); } }; diff --git a/22_CppCompat/main.cpp b/22_CppCompat/main.cpp index ff9d3d5f7..7b547c253 100644 --- a/22_CppCompat/main.cpp +++ b/22_CppCompat/main.cpp @@ -57,7 +57,7 @@ class CompatibilityTest final : public MonoDeviceApplication, public MonoAssetMa return false; if (!asset_base_t::onAppInitialized(std::move(system))) return false; - + ITester::PipelineSetupData pplnSetupData; pplnSetupData.device = m_device; pplnSetupData.api = m_api; From a92746361cdf02328284db57888c564e36e2cd52 Mon Sep 17 00:00:00 2001 From: Przemek Date: Thu, 30 Jan 2025 19:24:55 +0100 Subject: [PATCH 79/83] Added tests for new intirnsics functions --- 22_CppCompat/Testers.h | 53 ++++++++++++++++++++++++++ 22_CppCompat/app_resources/common.hlsl | 51 +++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index 9bcf36ae2..50f0c47ac 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -634,6 +634,14 @@ class CIntrinsicsTester final : public ITester commonTestInputValues.mixX = realDistributionNeg(mt); commonTestInputValues.mixY = realDistributionPos(mt); commonTestInputValues.mixA = realDistributionZeroToOne(mt); + commonTestInputValues.sign = realDistribution(mt); + commonTestInputValues.radians = realDistribution(mt); + commonTestInputValues.degrees = realDistribution(mt); + commonTestInputValues.stepEdge = realDistribution(mt); + commonTestInputValues.stepX = realDistribution(mt); + commonTestInputValues.smoothStepEdge0 = realDistributionNeg(mt); + commonTestInputValues.smoothStepEdge1 = realDistributionPos(mt); + commonTestInputValues.smoothStepX = realDistribution(mt); commonTestInputValues.bitCountVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); commonTestInputValues.clampValVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); @@ -652,6 +660,23 @@ class CIntrinsicsTester final : public ITester commonTestInputValues.mixYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); commonTestInputValues.mixAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); + commonTestInputValues.signVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.radiansVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.degreesVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.stepEdgeVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.stepXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.smoothStepEdge0Vec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + commonTestInputValues.smoothStepEdge1Vec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + commonTestInputValues.smoothStepXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.faceForwardN = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.faceForwardI = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.faceForwardNref = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.reflectI = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.reflectN = glm::normalize(float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt))); + commonTestInputValues.refractI = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + commonTestInputValues.refractN = glm::normalize(float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt))); + commonTestInputValues.refractEta = realDistribution(mt); + // use std library or glm functions to determine expected test values, the output of functions from intrinsics.hlsl will be verified against these values IntrinsicsTestValues expectedTestValues; expectedTestValues.bitCount = glm::bitCount(commonTestInputValues.bitCount); @@ -665,6 +690,11 @@ class CIntrinsicsTester final : public ITester expectedTestValues.max = glm::max(commonTestInputValues.maxA, commonTestInputValues.maxB); expectedTestValues.rsqrt = (1.0f / std::sqrt(commonTestInputValues.rsqrt)); expectedTestValues.mix = std::lerp(commonTestInputValues.mixX, commonTestInputValues.mixY, commonTestInputValues.mixA); + expectedTestValues.sign = glm::sign(commonTestInputValues.sign); + expectedTestValues.radians = glm::radians(commonTestInputValues.radians); + expectedTestValues.degrees = glm::degrees(commonTestInputValues.degrees); + expectedTestValues.step = glm::step(commonTestInputValues.stepEdge, commonTestInputValues.stepX); + expectedTestValues.smoothStep = glm::smoothstep(commonTestInputValues.smoothStepEdge0, commonTestInputValues.smoothStepEdge1, commonTestInputValues.smoothStepX); expectedTestValues.frac = commonTestInputValues.frac - std::floor(commonTestInputValues.frac); expectedTestValues.bitReverse = glm::bitfieldReverse(commonTestInputValues.bitReverse); @@ -699,6 +729,15 @@ class CIntrinsicsTester final : public ITester expectedTestValues.mixVec.y = std::lerp(commonTestInputValues.mixXVec.y, commonTestInputValues.mixYVec.y, commonTestInputValues.mixAVec.y); expectedTestValues.mixVec.z = std::lerp(commonTestInputValues.mixXVec.z, commonTestInputValues.mixYVec.z, commonTestInputValues.mixAVec.z); + expectedTestValues.signVec = glm::sign(commonTestInputValues.signVec); + expectedTestValues.radiansVec = glm::radians(commonTestInputValues.radiansVec); + expectedTestValues.degreesVec = glm::degrees(commonTestInputValues.degreesVec); + expectedTestValues.stepVec = glm::step(commonTestInputValues.stepEdgeVec, commonTestInputValues.stepXVec); + expectedTestValues.smoothStepVec = glm::smoothstep(commonTestInputValues.smoothStepEdge0Vec, commonTestInputValues.smoothStepEdge1Vec, commonTestInputValues.smoothStepXVec); + expectedTestValues.faceForward = glm::faceforward(commonTestInputValues.faceForwardN, commonTestInputValues.faceForwardI, commonTestInputValues.faceForwardNref); + expectedTestValues.reflect = glm::reflect(commonTestInputValues.reflectI, commonTestInputValues.reflectN); + expectedTestValues.refract = glm::refract(commonTestInputValues.refractI, commonTestInputValues.refractN, commonTestInputValues.refractEta); + auto mulGlm = nbl::hlsl::mul(commonTestInputValues.mulLhs, commonTestInputValues.mulRhs); expectedTestValues.mul = reinterpret_cast(mulGlm); auto transposeGlm = glm::transpose(reinterpret_cast(commonTestInputValues.transpose)); @@ -745,6 +784,11 @@ class CIntrinsicsTester final : public ITester verifyTestValue("frac", expectedTestValues.frac, testValues.frac, testType); verifyTestValue("bitReverse", expectedTestValues.bitReverse, testValues.bitReverse, testType); verifyTestValue("mix", expectedTestValues.mix, testValues.mix, testType); + verifyTestValue("sign", expectedTestValues.sign, testValues.sign, testType); + verifyTestValue("radians", expectedTestValues.radians, testValues.radians, testType); + verifyTestValue("degrees", expectedTestValues.degrees, testValues.degrees, testType); + verifyTestValue("step", expectedTestValues.step, testValues.step, testType); + verifyTestValue("smoothStep", expectedTestValues.smoothStep, testValues.smoothStep, testType); verifyTestVector3dValue("normalize", expectedTestValues.normalize, testValues.normalize, testType); verifyTestVector3dValue("cross", expectedTestValues.cross, testValues.cross, testType); @@ -759,6 +803,15 @@ class CIntrinsicsTester final : public ITester verifyTestVector3dValue("fracVec", expectedTestValues.fracVec, testValues.fracVec, testType); verifyTestVector3dValue("mixVec", expectedTestValues.mixVec, testValues.mixVec, testType); + verifyTestVector3dValue("signVec", expectedTestValues.signVec, testValues.signVec, testType); + verifyTestVector3dValue("radiansVec", expectedTestValues.radiansVec, testValues.radiansVec, testType); + verifyTestVector3dValue("degreesVec", expectedTestValues.degreesVec, testValues.degreesVec, testType); + verifyTestVector3dValue("stepVec", expectedTestValues.stepVec, testValues.stepVec, testType); + verifyTestVector3dValue("smoothStepVec", expectedTestValues.smoothStepVec, testValues.smoothStepVec, testType); + verifyTestVector3dValue("faceForward", expectedTestValues.faceForward, testValues.faceForward, testType); + verifyTestVector3dValue("reflect", expectedTestValues.reflect, testValues.reflect, testType); + verifyTestVector3dValue("refract", expectedTestValues.refract, testValues.refract, testType); + verifyTestMatrix3x3Value("mul", expectedTestValues.mul, testValues.mul, testType); verifyTestMatrix3x3Value("transpose", expectedTestValues.transpose, testValues.transpose, testType); verifyTestMatrix3x3Value("inverse", expectedTestValues.inverse, testValues.inverse, testType); diff --git a/22_CppCompat/app_resources/common.hlsl b/22_CppCompat/app_resources/common.hlsl index 177e172c7..cab98117e 100644 --- a/22_CppCompat/app_resources/common.hlsl +++ b/22_CppCompat/app_resources/common.hlsl @@ -223,6 +223,14 @@ struct IntrinsicsIntputTestValues float mixX; float mixY; float mixA; + float sign; + float radians; + float degrees; + float stepEdge; + float stepX; + float smoothStepEdge0; + float smoothStepEdge1; + float smoothStepX; int32_t3 bitCountVec; float32_t3 clampValVec; @@ -240,6 +248,22 @@ struct IntrinsicsIntputTestValues float32_t3 mixXVec; float32_t3 mixYVec; float32_t3 mixAVec; + float32_t3 signVec; + float32_t3 radiansVec; + float32_t3 degreesVec; + float32_t3 stepEdgeVec; + float32_t3 stepXVec; + float32_t3 smoothStepEdge0Vec; + float32_t3 smoothStepEdge1Vec; + float32_t3 smoothStepXVec; + float32_t3 faceForwardN; + float32_t3 faceForwardI; + float32_t3 faceForwardNref; + float32_t3 reflectI; + float32_t3 reflectN; + float32_t3 refractI; + float32_t3 refractN; + float refractEta; }; struct IntrinsicsTestValues @@ -257,6 +281,11 @@ struct IntrinsicsTestValues float frac; uint32_t bitReverse; float mix; + float sign; + float radians; + float degrees; + float step; + float smoothStep; float32_t3 normalize; float32_t3 cross; @@ -270,6 +299,14 @@ struct IntrinsicsTestValues uint32_t3 bitReverseVec; float32_t3 fracVec; float32_t3 mixVec; + float32_t3 signVec; + float32_t3 radiansVec; + float32_t3 degreesVec; + float32_t3 stepVec; + float32_t3 smoothStepVec; + float32_t3 faceForward; + float32_t3 reflect; + float32_t3 refract; float32_t3x3 mul; float32_t3x3 transpose; @@ -296,6 +333,11 @@ struct IntrinsicsTestValues bitReverse = nbl::hlsl::bitReverse(input.bitReverse); frac = nbl::hlsl::frac(input.frac); mix = nbl::hlsl::mix(input.mixX, input.mixY, input.mixA); + sign = nbl::hlsl::sign(input.sign); + radians = nbl::hlsl::radians(input.radians); + degrees = nbl::hlsl::degrees(input.degrees); + step = nbl::hlsl::step(input.stepEdge, input.stepX); + smoothStep = nbl::hlsl::smoothStep(input.smoothStepEdge0, input.smoothStepEdge1, input.smoothStepX); bitCountVec = nbl::hlsl::bitCount(input.bitCountVec); clampVec = nbl::hlsl::clamp(input.clampValVec, input.clampMinVec, input.clampMaxVec); @@ -308,6 +350,15 @@ struct IntrinsicsTestValues bitReverseVec = nbl::hlsl::bitReverse(input.bitReverseVec); fracVec = nbl::hlsl::frac(input.fracVec); mixVec = nbl::hlsl::mix(input.mixXVec, input.mixYVec, input.mixAVec); + + signVec = nbl::hlsl::sign(input.signVec); + radiansVec = nbl::hlsl::radians(input.radiansVec); + degreesVec = nbl::hlsl::degrees(input.degreesVec); + stepVec = nbl::hlsl::step(input.stepEdgeVec, input.stepXVec); + smoothStepVec = nbl::hlsl::smoothStep(input.smoothStepEdge0Vec, input.smoothStepEdge1Vec, input.smoothStepXVec); + faceForward = nbl::hlsl::faceForward(input.faceForwardN, input.faceForwardI, input.faceForwardNref); + reflect = nbl::hlsl::reflect(input.reflectI, input.reflectN); + refract = nbl::hlsl::refract(input.refractI, input.refractN, input.refractEta); } }; From 2bc6d88557a7b907deed0067596cb67ee1836279 Mon Sep 17 00:00:00 2001 From: Przemek Date: Mon, 3 Feb 2025 11:16:12 +0100 Subject: [PATCH 80/83] Example 62 fix --- 62_CAD/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/62_CAD/main.cpp b/62_CAD/main.cpp index 3a57355b4..b3932efb3 100644 --- a/62_CAD/main.cpp +++ b/62_CAD/main.cpp @@ -400,9 +400,9 @@ class ComputerAidedDesign final : public examples::SimpleWindowedApplication, pu } IGPUSampler::SParams samplerParams = {}; - samplerParams.TextureWrapU = IGPUSampler::ETC_CLAMP_TO_BORDER; - samplerParams.TextureWrapV = IGPUSampler::ETC_CLAMP_TO_BORDER; - samplerParams.TextureWrapW = IGPUSampler::ETC_CLAMP_TO_BORDER; + samplerParams.TextureWrapU = IGPUSampler::E_TEXTURE_CLAMP::ETC_CLAMP_TO_BORDER; + samplerParams.TextureWrapV = IGPUSampler::E_TEXTURE_CLAMP::ETC_CLAMP_TO_BORDER; + samplerParams.TextureWrapW = IGPUSampler::E_TEXTURE_CLAMP::ETC_CLAMP_TO_BORDER; samplerParams.BorderColor = IGPUSampler::ETBC_FLOAT_OPAQUE_WHITE; // positive means outside shape samplerParams.MinFilter = IGPUSampler::ETF_LINEAR; samplerParams.MaxFilter = IGPUSampler::ETF_LINEAR; From 99cb3cf0ab8ca156498ebe44786eee53894e3840 Mon Sep 17 00:00:00 2001 From: Przemek Date: Mon, 3 Feb 2025 16:33:31 +0100 Subject: [PATCH 81/83] Added modfStruct and frexpStruct tests --- 22_CppCompat/Testers.h | 315 ++++++++++++++----------- 22_CppCompat/app_resources/common.hlsl | 16 ++ 2 files changed, 192 insertions(+), 139 deletions(-) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index 50f0c47ac..a455c9454 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -208,6 +208,7 @@ class ITester template void verifyTestValue(const std::string& memberName, const T& expectedVal, const T& testVal, const TestType testType) { + static constexpr float MaxAllowedError = 0.1f; if (std::abs(double(expectedVal) - double(testVal)) <= MaxAllowedError) return; @@ -229,8 +230,8 @@ class ITester void verifyTestVector3dValue(const std::string& memberName, const nbl::hlsl::vector& expectedVal, const nbl::hlsl::vector& testVal, const TestType testType) { static constexpr float MaxAllowedError = 0.1f; - if (std::abs(double(expectedVal.x) - double(testVal.x)) <= MaxAllowedError || - std::abs(double(expectedVal.y) - double(testVal.y)) <= MaxAllowedError || + if (std::abs(double(expectedVal.x) - double(testVal.x)) <= MaxAllowedError && + std::abs(double(expectedVal.y) - double(testVal.y)) <= MaxAllowedError && std::abs(double(expectedVal.z) - double(testVal.z)) <= MaxAllowedError) return; @@ -323,8 +324,6 @@ class ITester } private: - static constexpr float MaxAllowedError = 0.001f; - template inline void logFail(const char* msg, Args&&... args) { @@ -586,167 +585,194 @@ class CIntrinsicsTester final : public ITester for (int i = 0; i < Iterations; ++i) { // Set input thest values that will be used in both CPU and GPU tests - IntrinsicsIntputTestValues commonTestInputValues; - commonTestInputValues.bitCount = intDistribution(mt); - commonTestInputValues.crossLhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.crossRhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.clampVal = realDistribution(mt); - commonTestInputValues.clampMin = realDistributionNeg(mt); - commonTestInputValues.clampMax = realDistributionPos(mt); - commonTestInputValues.length = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.normalize = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.dotLhs = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); - commonTestInputValues.dotRhs = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); - commonTestInputValues.determinant = float32_t3x3( + IntrinsicsIntputTestValues testInput; + testInput.bitCount = intDistribution(mt); + testInput.crossLhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.crossRhs = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.clampVal = realDistribution(mt); + testInput.clampMin = realDistributionNeg(mt); + testInput.clampMax = realDistributionPos(mt); + testInput.length = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.normalize = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.dotLhs = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + testInput.dotRhs = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + testInput.determinant = float32_t3x3( realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt) ); - commonTestInputValues.findMSB = realDistribution(mt); - commonTestInputValues.findLSB = realDistribution(mt); - commonTestInputValues.inverse = float32_t3x3( + testInput.findMSB = realDistribution(mt); + testInput.findLSB = realDistribution(mt); + testInput.inverse = float32_t3x3( realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt) ); - commonTestInputValues.transpose = float32_t3x3( + testInput.transpose = float32_t3x3( realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt) ); - commonTestInputValues.mulLhs = float32_t3x3( + testInput.mulLhs = float32_t3x3( realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt) ); - commonTestInputValues.mulRhs = float32_t3x3( + testInput.mulRhs = float32_t3x3( realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt), realDistribution(mt) ); - commonTestInputValues.minA = realDistribution(mt); - commonTestInputValues.minB = realDistribution(mt); - commonTestInputValues.maxA = realDistribution(mt); - commonTestInputValues.maxB = realDistribution(mt); - commonTestInputValues.rsqrt = realDistributionPos(mt); - commonTestInputValues.bitReverse = realDistribution(mt); - commonTestInputValues.frac = realDistribution(mt); - commonTestInputValues.mixX = realDistributionNeg(mt); - commonTestInputValues.mixY = realDistributionPos(mt); - commonTestInputValues.mixA = realDistributionZeroToOne(mt); - commonTestInputValues.sign = realDistribution(mt); - commonTestInputValues.radians = realDistribution(mt); - commonTestInputValues.degrees = realDistribution(mt); - commonTestInputValues.stepEdge = realDistribution(mt); - commonTestInputValues.stepX = realDistribution(mt); - commonTestInputValues.smoothStepEdge0 = realDistributionNeg(mt); - commonTestInputValues.smoothStepEdge1 = realDistributionPos(mt); - commonTestInputValues.smoothStepX = realDistribution(mt); - - commonTestInputValues.bitCountVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); - commonTestInputValues.clampValVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.clampMinVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); - commonTestInputValues.clampMaxVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); - commonTestInputValues.findMSBVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); - commonTestInputValues.findLSBVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); - commonTestInputValues.minAVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.minBVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.maxAVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.maxBVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.rsqrtVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); - commonTestInputValues.bitReverseVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); - commonTestInputValues.fracVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.mixXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); - commonTestInputValues.mixYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); - commonTestInputValues.mixAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); - - commonTestInputValues.signVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.radiansVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.degreesVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.stepEdgeVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.stepXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.smoothStepEdge0Vec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); - commonTestInputValues.smoothStepEdge1Vec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); - commonTestInputValues.smoothStepXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.faceForwardN = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.faceForwardI = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.faceForwardNref = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.reflectI = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.reflectN = glm::normalize(float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt))); - commonTestInputValues.refractI = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.refractN = glm::normalize(float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt))); - commonTestInputValues.refractEta = realDistribution(mt); + testInput.minA = realDistribution(mt); + testInput.minB = realDistribution(mt); + testInput.maxA = realDistribution(mt); + testInput.maxB = realDistribution(mt); + testInput.rsqrt = realDistributionPos(mt); + testInput.bitReverse = realDistribution(mt); + testInput.frac = realDistribution(mt); + testInput.mixX = realDistributionNeg(mt); + testInput.mixY = realDistributionPos(mt); + testInput.mixA = realDistributionZeroToOne(mt); + testInput.sign = realDistribution(mt); + testInput.radians = realDistribution(mt); + testInput.degrees = realDistribution(mt); + testInput.stepEdge = realDistribution(mt); + testInput.stepX = realDistribution(mt); + testInput.smoothStepEdge0 = realDistributionNeg(mt); + testInput.smoothStepEdge1 = realDistributionPos(mt); + testInput.smoothStepX = realDistribution(mt); + + testInput.bitCountVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); + testInput.clampValVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.clampMinVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + testInput.clampMaxVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + testInput.findMSBVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); + testInput.findLSBVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); + testInput.minAVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.minBVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.maxAVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.maxBVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.rsqrtVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + testInput.bitReverseVec = uint32_t3(uintDistribution(mt), uintDistribution(mt), uintDistribution(mt)); + testInput.fracVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.mixXVec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + testInput.mixYVec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + testInput.mixAVec = float32_t3(realDistributionZeroToOne(mt), realDistributionZeroToOne(mt), realDistributionZeroToOne(mt)); + + testInput.signVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.radiansVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.degreesVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.stepEdgeVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.stepXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.smoothStepEdge0Vec = float32_t3(realDistributionNeg(mt), realDistributionNeg(mt), realDistributionNeg(mt)); + testInput.smoothStepEdge1Vec = float32_t3(realDistributionPos(mt), realDistributionPos(mt), realDistributionPos(mt)); + testInput.smoothStepXVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.faceForwardN = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.faceForwardI = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.faceForwardNref = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.reflectI = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.reflectN = glm::normalize(float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt))); + testInput.refractI = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.refractN = glm::normalize(float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt))); + testInput.refractEta = realDistribution(mt); + + testInput.modfStruct = realDistribution(mt); + testInput.modfStructVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.frexpStruct = realDistribution(mt); + testInput.frexpStructVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); // use std library or glm functions to determine expected test values, the output of functions from intrinsics.hlsl will be verified against these values - IntrinsicsTestValues expectedTestValues; - expectedTestValues.bitCount = glm::bitCount(commonTestInputValues.bitCount); - expectedTestValues.clamp = glm::clamp(commonTestInputValues.clampVal, commonTestInputValues.clampMin, commonTestInputValues.clampMax); - expectedTestValues.length = glm::length(commonTestInputValues.length); - expectedTestValues.dot = glm::dot(commonTestInputValues.dotLhs, commonTestInputValues.dotRhs); - expectedTestValues.determinant = glm::determinant(reinterpret_cast(commonTestInputValues.determinant)); - expectedTestValues.findMSB = glm::findMSB(commonTestInputValues.findMSB); - expectedTestValues.findLSB = glm::findLSB(commonTestInputValues.findLSB); - expectedTestValues.min = glm::min(commonTestInputValues.minA, commonTestInputValues.minB); - expectedTestValues.max = glm::max(commonTestInputValues.maxA, commonTestInputValues.maxB); - expectedTestValues.rsqrt = (1.0f / std::sqrt(commonTestInputValues.rsqrt)); - expectedTestValues.mix = std::lerp(commonTestInputValues.mixX, commonTestInputValues.mixY, commonTestInputValues.mixA); - expectedTestValues.sign = glm::sign(commonTestInputValues.sign); - expectedTestValues.radians = glm::radians(commonTestInputValues.radians); - expectedTestValues.degrees = glm::degrees(commonTestInputValues.degrees); - expectedTestValues.step = glm::step(commonTestInputValues.stepEdge, commonTestInputValues.stepX); - expectedTestValues.smoothStep = glm::smoothstep(commonTestInputValues.smoothStepEdge0, commonTestInputValues.smoothStepEdge1, commonTestInputValues.smoothStepX); - - expectedTestValues.frac = commonTestInputValues.frac - std::floor(commonTestInputValues.frac); - expectedTestValues.bitReverse = glm::bitfieldReverse(commonTestInputValues.bitReverse); - - expectedTestValues.normalize = glm::normalize(commonTestInputValues.normalize); - expectedTestValues.cross = glm::cross(commonTestInputValues.crossLhs, commonTestInputValues.crossRhs); - expectedTestValues.bitCountVec = int32_t3(glm::bitCount(commonTestInputValues.bitCountVec.x), glm::bitCount(commonTestInputValues.bitCountVec.y), glm::bitCount(commonTestInputValues.bitCountVec.z)); - expectedTestValues.clampVec = float32_t3( - glm::clamp(commonTestInputValues.clampValVec.x, commonTestInputValues.clampMinVec.x, commonTestInputValues.clampMaxVec.x), - glm::clamp(commonTestInputValues.clampValVec.y, commonTestInputValues.clampMinVec.y, commonTestInputValues.clampMaxVec.y), - glm::clamp(commonTestInputValues.clampValVec.z, commonTestInputValues.clampMinVec.z, commonTestInputValues.clampMaxVec.z) + IntrinsicsTestValues expected; + expected.bitCount = glm::bitCount(testInput.bitCount); + expected.clamp = glm::clamp(testInput.clampVal, testInput.clampMin, testInput.clampMax); + expected.length = glm::length(testInput.length); + expected.dot = glm::dot(testInput.dotLhs, testInput.dotRhs); + expected.determinant = glm::determinant(reinterpret_cast(testInput.determinant)); + expected.findMSB = glm::findMSB(testInput.findMSB); + expected.findLSB = glm::findLSB(testInput.findLSB); + expected.min = glm::min(testInput.minA, testInput.minB); + expected.max = glm::max(testInput.maxA, testInput.maxB); + expected.rsqrt = (1.0f / std::sqrt(testInput.rsqrt)); + expected.mix = std::lerp(testInput.mixX, testInput.mixY, testInput.mixA); + expected.sign = glm::sign(testInput.sign); + expected.radians = glm::radians(testInput.radians); + expected.degrees = glm::degrees(testInput.degrees); + expected.step = glm::step(testInput.stepEdge, testInput.stepX); + expected.smoothStep = glm::smoothstep(testInput.smoothStepEdge0, testInput.smoothStepEdge1, testInput.smoothStepX); + + expected.frac = testInput.frac - std::floor(testInput.frac); + expected.bitReverse = glm::bitfieldReverse(testInput.bitReverse); + + expected.normalize = glm::normalize(testInput.normalize); + expected.cross = glm::cross(testInput.crossLhs, testInput.crossRhs); + expected.bitCountVec = int32_t3(glm::bitCount(testInput.bitCountVec.x), glm::bitCount(testInput.bitCountVec.y), glm::bitCount(testInput.bitCountVec.z)); + expected.clampVec = float32_t3( + glm::clamp(testInput.clampValVec.x, testInput.clampMinVec.x, testInput.clampMaxVec.x), + glm::clamp(testInput.clampValVec.y, testInput.clampMinVec.y, testInput.clampMaxVec.y), + glm::clamp(testInput.clampValVec.z, testInput.clampMinVec.z, testInput.clampMaxVec.z) ); - expectedTestValues.findMSBVec = glm::findMSB(commonTestInputValues.findMSBVec); - expectedTestValues.findLSBVec = glm::findLSB(commonTestInputValues.findLSBVec); - expectedTestValues.minVec = float32_t3( - glm::min(commonTestInputValues.minAVec.x, commonTestInputValues.minBVec.x), - glm::min(commonTestInputValues.minAVec.y, commonTestInputValues.minBVec.y), - glm::min(commonTestInputValues.minAVec.z, commonTestInputValues.minBVec.z) + expected.findMSBVec = glm::findMSB(testInput.findMSBVec); + expected.findLSBVec = glm::findLSB(testInput.findLSBVec); + expected.minVec = float32_t3( + glm::min(testInput.minAVec.x, testInput.minBVec.x), + glm::min(testInput.minAVec.y, testInput.minBVec.y), + glm::min(testInput.minAVec.z, testInput.minBVec.z) ); - expectedTestValues.maxVec = float32_t3( - glm::max(commonTestInputValues.maxAVec.x, commonTestInputValues.maxBVec.x), - glm::max(commonTestInputValues.maxAVec.y, commonTestInputValues.maxBVec.y), - glm::max(commonTestInputValues.maxAVec.z, commonTestInputValues.maxBVec.z) + expected.maxVec = float32_t3( + glm::max(testInput.maxAVec.x, testInput.maxBVec.x), + glm::max(testInput.maxAVec.y, testInput.maxBVec.y), + glm::max(testInput.maxAVec.z, testInput.maxBVec.z) ); - expectedTestValues.rsqrtVec = float32_t3(1.0f / std::sqrt(commonTestInputValues.rsqrtVec.x), 1.0f / std::sqrt(commonTestInputValues.rsqrtVec.y), 1.0f / std::sqrt(commonTestInputValues.rsqrtVec.z)); - expectedTestValues.bitReverseVec = glm::bitfieldReverse(commonTestInputValues.bitReverseVec); - expectedTestValues.fracVec = float32_t3( - commonTestInputValues.fracVec.x - std::floor(commonTestInputValues.fracVec.x), - commonTestInputValues.fracVec.y - std::floor(commonTestInputValues.fracVec.y), - commonTestInputValues.fracVec.z - std::floor(commonTestInputValues.fracVec.z)); - expectedTestValues.mixVec.x = std::lerp(commonTestInputValues.mixXVec.x, commonTestInputValues.mixYVec.x, commonTestInputValues.mixAVec.x); - expectedTestValues.mixVec.y = std::lerp(commonTestInputValues.mixXVec.y, commonTestInputValues.mixYVec.y, commonTestInputValues.mixAVec.y); - expectedTestValues.mixVec.z = std::lerp(commonTestInputValues.mixXVec.z, commonTestInputValues.mixYVec.z, commonTestInputValues.mixAVec.z); - - expectedTestValues.signVec = glm::sign(commonTestInputValues.signVec); - expectedTestValues.radiansVec = glm::radians(commonTestInputValues.radiansVec); - expectedTestValues.degreesVec = glm::degrees(commonTestInputValues.degreesVec); - expectedTestValues.stepVec = glm::step(commonTestInputValues.stepEdgeVec, commonTestInputValues.stepXVec); - expectedTestValues.smoothStepVec = glm::smoothstep(commonTestInputValues.smoothStepEdge0Vec, commonTestInputValues.smoothStepEdge1Vec, commonTestInputValues.smoothStepXVec); - expectedTestValues.faceForward = glm::faceforward(commonTestInputValues.faceForwardN, commonTestInputValues.faceForwardI, commonTestInputValues.faceForwardNref); - expectedTestValues.reflect = glm::reflect(commonTestInputValues.reflectI, commonTestInputValues.reflectN); - expectedTestValues.refract = glm::refract(commonTestInputValues.refractI, commonTestInputValues.refractN, commonTestInputValues.refractEta); - - auto mulGlm = nbl::hlsl::mul(commonTestInputValues.mulLhs, commonTestInputValues.mulRhs); - expectedTestValues.mul = reinterpret_cast(mulGlm); - auto transposeGlm = glm::transpose(reinterpret_cast(commonTestInputValues.transpose)); - expectedTestValues.transpose = reinterpret_cast(transposeGlm); - auto inverseGlm = glm::inverse(reinterpret_cast(commonTestInputValues.inverse)); - expectedTestValues.inverse = reinterpret_cast(inverseGlm); + expected.rsqrtVec = float32_t3(1.0f / std::sqrt(testInput.rsqrtVec.x), 1.0f / std::sqrt(testInput.rsqrtVec.y), 1.0f / std::sqrt(testInput.rsqrtVec.z)); + expected.bitReverseVec = glm::bitfieldReverse(testInput.bitReverseVec); + expected.fracVec = float32_t3( + testInput.fracVec.x - std::floor(testInput.fracVec.x), + testInput.fracVec.y - std::floor(testInput.fracVec.y), + testInput.fracVec.z - std::floor(testInput.fracVec.z)); + expected.mixVec.x = std::lerp(testInput.mixXVec.x, testInput.mixYVec.x, testInput.mixAVec.x); + expected.mixVec.y = std::lerp(testInput.mixXVec.y, testInput.mixYVec.y, testInput.mixAVec.y); + expected.mixVec.z = std::lerp(testInput.mixXVec.z, testInput.mixYVec.z, testInput.mixAVec.z); + + expected.signVec = glm::sign(testInput.signVec); + expected.radiansVec = glm::radians(testInput.radiansVec); + expected.degreesVec = glm::degrees(testInput.degreesVec); + expected.stepVec = glm::step(testInput.stepEdgeVec, testInput.stepXVec); + expected.smoothStepVec = glm::smoothstep(testInput.smoothStepEdge0Vec, testInput.smoothStepEdge1Vec, testInput.smoothStepXVec); + expected.faceForward = glm::faceforward(testInput.faceForwardN, testInput.faceForwardI, testInput.faceForwardNref); + expected.reflect = glm::reflect(testInput.reflectI, testInput.reflectN); + expected.refract = glm::refract(testInput.refractI, testInput.refractN, testInput.refractEta); + + auto mulGlm = nbl::hlsl::mul(testInput.mulLhs, testInput.mulRhs); + expected.mul = reinterpret_cast(mulGlm); + auto transposeGlm = glm::transpose(reinterpret_cast(testInput.transpose)); + expected.transpose = reinterpret_cast(transposeGlm); + auto inverseGlm = glm::inverse(reinterpret_cast(testInput.inverse)); + expected.inverse = reinterpret_cast(inverseGlm); - performCpuTests(commonTestInputValues, expectedTestValues); - performGpuTests(commonTestInputValues, expectedTestValues); + { + ModfOutput expectedModfStructOutput; + expectedModfStructOutput.fractionalPart = std::modf(testInput.modfStruct, &expectedModfStructOutput.wholeNumberPart); + expected.modfStruct = expectedModfStructOutput; + + ModfOutput expectedModfStructOutputVec; + for (int i = 0; i < 3; ++i) + expectedModfStructOutputVec.fractionalPart[i] = std::modf(testInput.modfStructVec[i], &expectedModfStructOutputVec.wholeNumberPart[i]); + expected.modfStructVec = expectedModfStructOutputVec; + } + + { + FrexpOutput expectedFrexpStructOutput; + expectedFrexpStructOutput.significand = std::frexp(testInput.frexpStruct, &expectedFrexpStructOutput.exponent); + expected.frexpStruct = expectedFrexpStructOutput; + + FrexpOutput expectedFrexpStructOutputVec; + for (int i = 0; i < 3; ++i) + expectedFrexpStructOutputVec.significand[i] = std::frexp(testInput.frexpStructVec[i], &expectedFrexpStructOutputVec.exponent[i]); + expected.frexpStructVec = expectedFrexpStructOutputVec; + } + + performCpuTests(testInput, expected); + performGpuTests(testInput, expected); } m_logger->log("intrinsics.hlsl TESTS DONE.", system::ILogger::ELL_PERFORMANCE); } @@ -815,6 +841,17 @@ class CIntrinsicsTester final : public ITester verifyTestMatrix3x3Value("mul", expectedTestValues.mul, testValues.mul, testType); verifyTestMatrix3x3Value("transpose", expectedTestValues.transpose, testValues.transpose, testType); verifyTestMatrix3x3Value("inverse", expectedTestValues.inverse, testValues.inverse, testType); + + // verify output of struct producing functions + verifyTestValue("modfStruct", expectedTestValues.modfStruct.fractionalPart, testValues.modfStruct.fractionalPart, testType); + verifyTestValue("modfStruct", expectedTestValues.modfStruct.wholeNumberPart, testValues.modfStruct.wholeNumberPart, testType); + verifyTestVector3dValue("modfStructVec", expectedTestValues.modfStructVec.fractionalPart, testValues.modfStructVec.fractionalPart, testType); + verifyTestVector3dValue("modfStructVec", expectedTestValues.modfStructVec.wholeNumberPart, testValues.modfStructVec.wholeNumberPart, testType); + + verifyTestValue("frexpStruct", expectedTestValues.frexpStruct.significand, testValues.frexpStruct.significand, testType); + verifyTestValue("frexpStruct", expectedTestValues.frexpStruct.exponent, testValues.frexpStruct.exponent, testType); + verifyTestVector3dValue("frexpStructVec", expectedTestValues.frexpStructVec.significand, testValues.frexpStructVec.significand, testType); + verifyTestVector3dValue("frexpStructVec", expectedTestValues.frexpStructVec.exponent, testValues.frexpStructVec.exponent, testType); } }; diff --git a/22_CppCompat/app_resources/common.hlsl b/22_CppCompat/app_resources/common.hlsl index cab98117e..c196a389b 100644 --- a/22_CppCompat/app_resources/common.hlsl +++ b/22_CppCompat/app_resources/common.hlsl @@ -231,6 +231,8 @@ struct IntrinsicsIntputTestValues float smoothStepEdge0; float smoothStepEdge1; float smoothStepX; + float modfStruct; + float frexpStruct; int32_t3 bitCountVec; float32_t3 clampValVec; @@ -264,6 +266,8 @@ struct IntrinsicsIntputTestValues float32_t3 refractI; float32_t3 refractN; float refractEta; + float32_t3 modfStructVec; + float32_t3 frexpStructVec; }; struct IntrinsicsTestValues @@ -312,6 +316,12 @@ struct IntrinsicsTestValues float32_t3x3 transpose; float32_t3x3 inverse; + ModfOutput modfStruct; + ModfOutput modfStructVec; + + FrexpOutput frexpStruct; + FrexpOutput frexpStructVec; + void fillTestValues(NBL_CONST_REF_ARG(IntrinsicsIntputTestValues) input) { bitCount = nbl::hlsl::bitCount(input.bitCount); @@ -359,6 +369,12 @@ struct IntrinsicsTestValues faceForward = nbl::hlsl::faceForward(input.faceForwardN, input.faceForwardI, input.faceForwardNref); reflect = nbl::hlsl::reflect(input.reflectI, input.reflectN); refract = nbl::hlsl::refract(input.refractI, input.refractN, input.refractEta); + + modfStruct = nbl::hlsl::modfStruct(input.modfStruct); + modfStructVec = nbl::hlsl::modfStruct(input.modfStructVec); + + frexpStruct = nbl::hlsl::frexpStruct(input.frexpStruct); + frexpStructVec = nbl::hlsl::frexpStruct(input.frexpStructVec); } }; From ccc637adce9140f28de52274205aaee5f00adfa7 Mon Sep 17 00:00:00 2001 From: Przemek Date: Mon, 3 Feb 2025 16:46:54 +0100 Subject: [PATCH 82/83] Bug fix --- 22_CppCompat/Testers.h | 230 +++++++++++++++++++++-------------------- 1 file changed, 116 insertions(+), 114 deletions(-) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index a455c9454..2426e3e49 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -351,73 +351,75 @@ class CTgmathTester final : public ITester for (int i = 0; i < Iterations; ++i) { // Set input thest values that will be used in both CPU and GPU tests - TgmathIntputTestValues commonTestInputValues; - commonTestInputValues.floor = realDistribution(mt); - commonTestInputValues.isnan = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::quiet_NaN(); - commonTestInputValues.isinf = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::infinity(); - commonTestInputValues.powX = realDistributionSmall(mt); - commonTestInputValues.powY = realDistributionSmall(mt); - commonTestInputValues.exp = realDistributionSmall(mt); - commonTestInputValues.exp2 = realDistributionSmall(mt); - commonTestInputValues.log = realDistribution(mt); - commonTestInputValues.log2 = realDistribution(mt); - commonTestInputValues.absF = realDistribution(mt); - commonTestInputValues.absI = intDistribution(mt); - commonTestInputValues.sqrt = realDistribution(mt); - commonTestInputValues.sin = realDistribution(mt); - commonTestInputValues.cos = realDistribution(mt); - commonTestInputValues.acos = realDistribution(mt); - commonTestInputValues.modf = realDistribution(mt); - commonTestInputValues.round = realDistribution(mt); - commonTestInputValues.roundEven = coinFlipDistribution(mt) ? realDistributionSmall(mt) : (static_cast(intDistribution(mt) / 2) + 0.5f); - commonTestInputValues.trunc = realDistribution(mt); - commonTestInputValues.ceil = realDistribution(mt); - commonTestInputValues.fmaX = realDistribution(mt); - commonTestInputValues.fmaY = realDistribution(mt); - commonTestInputValues.fmaZ = realDistribution(mt); - commonTestInputValues.ldexpArg = realDistributionSmall(mt); - commonTestInputValues.ldexpExp = intDistribution(mt); - - commonTestInputValues.floorVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.isnanVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.isinfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.powXVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); - commonTestInputValues.powYVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); - commonTestInputValues.expVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); - commonTestInputValues.exp2Vec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); - commonTestInputValues.logVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.log2Vec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.absFVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.absIVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); - commonTestInputValues.sqrtVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.sinVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.cosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.acosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - commonTestInputValues.modfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + TgmathIntputTestValues testInput; + testInput.floor = realDistribution(mt); + testInput.isnan = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::quiet_NaN(); + testInput.isinf = coinFlipDistribution(mt) ? realDistribution(mt) : std::numeric_limits::infinity(); + testInput.powX = realDistributionSmall(mt); + testInput.powY = realDistributionSmall(mt); + testInput.exp = realDistributionSmall(mt); + testInput.exp2 = realDistributionSmall(mt); + testInput.log = realDistribution(mt); + testInput.log2 = realDistribution(mt); + testInput.absF = realDistribution(mt); + testInput.absI = intDistribution(mt); + testInput.sqrt = realDistribution(mt); + testInput.sin = realDistribution(mt); + testInput.cos = realDistribution(mt); + testInput.acos = realDistribution(mt); + testInput.modf = realDistribution(mt); + testInput.round = realDistribution(mt); + testInput.roundEven = coinFlipDistribution(mt) ? realDistributionSmall(mt) : (static_cast(intDistribution(mt) / 2) + 0.5f); + testInput.trunc = realDistribution(mt); + testInput.ceil = realDistribution(mt); + testInput.fmaX = realDistribution(mt); + testInput.fmaY = realDistribution(mt); + testInput.fmaZ = realDistribution(mt); + testInput.ldexpArg = realDistributionSmall(mt); + testInput.ldexpExp = intDistribution(mt); + + testInput.floorVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.isnanVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.isinfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.powXVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + testInput.powYVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + testInput.expVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + testInput.exp2Vec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + testInput.logVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.log2Vec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.absFVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.absIVec = int32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); + testInput.sqrtVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.sinVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.cosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.acosVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.modfVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.ldexpArgVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); + testInput.ldexpExpVec = float32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); // use std library functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values - TgmathTestValues expectedTestValues; - expectedTestValues.floor = std::floor(commonTestInputValues.floor); - expectedTestValues.isnan = std::isnan(commonTestInputValues.isnan); - expectedTestValues.isinf = std::isinf(commonTestInputValues.isinf); - expectedTestValues.pow = std::pow(commonTestInputValues.powX, commonTestInputValues.powY); - expectedTestValues.exp = std::exp(commonTestInputValues.exp); - expectedTestValues.exp2 = std::exp2(commonTestInputValues.exp2); - expectedTestValues.log = std::log(commonTestInputValues.log); - expectedTestValues.log2 = std::log2(commonTestInputValues.log2); - expectedTestValues.absF = std::abs(commonTestInputValues.absF); - expectedTestValues.absI = std::abs(commonTestInputValues.absI); - expectedTestValues.sqrt = std::sqrt(commonTestInputValues.sqrt); - expectedTestValues.sin = std::sin(commonTestInputValues.sin); - expectedTestValues.cos = std::cos(commonTestInputValues.cos); - expectedTestValues.acos = std::acos(commonTestInputValues.acos); + TgmathTestValues expected; + expected.floor = std::floor(testInput.floor); + expected.isnan = std::isnan(testInput.isnan); + expected.isinf = std::isinf(testInput.isinf); + expected.pow = std::pow(testInput.powX, testInput.powY); + expected.exp = std::exp(testInput.exp); + expected.exp2 = std::exp2(testInput.exp2); + expected.log = std::log(testInput.log); + expected.log2 = std::log2(testInput.log2); + expected.absF = std::abs(testInput.absF); + expected.absI = std::abs(testInput.absI); + expected.sqrt = std::sqrt(testInput.sqrt); + expected.sin = std::sin(testInput.sin); + expected.cos = std::cos(testInput.cos); + expected.acos = std::acos(testInput.acos); { float tmp; - expectedTestValues.modf = std::modf(commonTestInputValues.modf, &tmp); + expected.modf = std::modf(testInput.modf, &tmp); } - expectedTestValues.round = std::round(commonTestInputValues.round); + expected.round = std::round(testInput.round); // TODO: uncomment when C++23 - //expectedTestValues.roundEven = std::roundeven(commonTestInputValues.roundEven); + //expected.roundEven = std::roundeven(testInput.roundEven); // TODO: remove when C++23 auto roundeven = [](const float& val) -> float { @@ -432,75 +434,75 @@ class CTgmathTester final : public ITester return std::round(val); }; - expectedTestValues.roundEven = roundeven(commonTestInputValues.roundEven); - - expectedTestValues.trunc = std::trunc(commonTestInputValues.trunc); - expectedTestValues.ceil = std::ceil(commonTestInputValues.ceil); - expectedTestValues.fma = std::fma(commonTestInputValues.fmaX, commonTestInputValues.fmaY, commonTestInputValues.fmaZ); - expectedTestValues.ldexp = std::ldexp(commonTestInputValues.ldexpArg, commonTestInputValues.ldexpExp); - - expectedTestValues.floorVec = float32_t3(std::floor(commonTestInputValues.floorVec.x), std::floor(commonTestInputValues.floorVec.y), std::floor(commonTestInputValues.floorVec.z)); - - expectedTestValues.isnanVec = float32_t3(std::isnan(commonTestInputValues.isnanVec.x), std::isnan(commonTestInputValues.isnanVec.y), std::isnan(commonTestInputValues.isnanVec.z)); - expectedTestValues.isinfVec = float32_t3(std::isinf(commonTestInputValues.isinfVec.x), std::isinf(commonTestInputValues.isinfVec.y), std::isinf(commonTestInputValues.isinfVec.z)); - - expectedTestValues.powVec.x = std::pow(commonTestInputValues.powXVec.x, commonTestInputValues.powYVec.x); - expectedTestValues.powVec.y = std::pow(commonTestInputValues.powXVec.y, commonTestInputValues.powYVec.y); - expectedTestValues.powVec.z = std::pow(commonTestInputValues.powXVec.z, commonTestInputValues.powYVec.z); - - expectedTestValues.expVec = float32_t3(std::exp(commonTestInputValues.expVec.x), std::exp(commonTestInputValues.expVec.y), std::exp(commonTestInputValues.expVec.z)); - expectedTestValues.exp2Vec = float32_t3(std::exp2(commonTestInputValues.exp2Vec.x), std::exp2(commonTestInputValues.exp2Vec.y), std::exp2(commonTestInputValues.exp2Vec.z)); - expectedTestValues.logVec = float32_t3(std::log(commonTestInputValues.logVec.x), std::log(commonTestInputValues.logVec.y), std::log(commonTestInputValues.logVec.z)); - expectedTestValues.log2Vec = float32_t3(std::log2(commonTestInputValues.log2Vec.x), std::log2(commonTestInputValues.log2Vec.y), std::log2(commonTestInputValues.log2Vec.z)); - expectedTestValues.absFVec = float32_t3(std::abs(commonTestInputValues.absFVec.x), std::abs(commonTestInputValues.absFVec.y), std::abs(commonTestInputValues.absFVec.z)); - expectedTestValues.absIVec = float32_t3(std::abs(commonTestInputValues.absIVec.x), std::abs(commonTestInputValues.absIVec.y), std::abs(commonTestInputValues.absIVec.z)); - expectedTestValues.sqrtVec = float32_t3(std::sqrt(commonTestInputValues.sqrtVec.x), std::sqrt(commonTestInputValues.sqrtVec.y), std::sqrt(commonTestInputValues.sqrtVec.z)); - expectedTestValues.cosVec = float32_t3(std::cos(commonTestInputValues.cosVec.x), std::cos(commonTestInputValues.cosVec.y), std::cos(commonTestInputValues.cosVec.z)); - expectedTestValues.sinVec = float32_t3(std::sin(commonTestInputValues.sinVec.x), std::sin(commonTestInputValues.sinVec.y), std::sin(commonTestInputValues.sinVec.z)); - expectedTestValues.acosVec = float32_t3(std::acos(commonTestInputValues.acosVec.x), std::acos(commonTestInputValues.acosVec.y), std::acos(commonTestInputValues.acosVec.z)); + expected.roundEven = roundeven(testInput.roundEven); + + expected.trunc = std::trunc(testInput.trunc); + expected.ceil = std::ceil(testInput.ceil); + expected.fma = std::fma(testInput.fmaX, testInput.fmaY, testInput.fmaZ); + expected.ldexp = std::ldexp(testInput.ldexpArg, testInput.ldexpExp); + + expected.floorVec = float32_t3(std::floor(testInput.floorVec.x), std::floor(testInput.floorVec.y), std::floor(testInput.floorVec.z)); + + expected.isnanVec = float32_t3(std::isnan(testInput.isnanVec.x), std::isnan(testInput.isnanVec.y), std::isnan(testInput.isnanVec.z)); + expected.isinfVec = float32_t3(std::isinf(testInput.isinfVec.x), std::isinf(testInput.isinfVec.y), std::isinf(testInput.isinfVec.z)); + + expected.powVec.x = std::pow(testInput.powXVec.x, testInput.powYVec.x); + expected.powVec.y = std::pow(testInput.powXVec.y, testInput.powYVec.y); + expected.powVec.z = std::pow(testInput.powXVec.z, testInput.powYVec.z); + + expected.expVec = float32_t3(std::exp(testInput.expVec.x), std::exp(testInput.expVec.y), std::exp(testInput.expVec.z)); + expected.exp2Vec = float32_t3(std::exp2(testInput.exp2Vec.x), std::exp2(testInput.exp2Vec.y), std::exp2(testInput.exp2Vec.z)); + expected.logVec = float32_t3(std::log(testInput.logVec.x), std::log(testInput.logVec.y), std::log(testInput.logVec.z)); + expected.log2Vec = float32_t3(std::log2(testInput.log2Vec.x), std::log2(testInput.log2Vec.y), std::log2(testInput.log2Vec.z)); + expected.absFVec = float32_t3(std::abs(testInput.absFVec.x), std::abs(testInput.absFVec.y), std::abs(testInput.absFVec.z)); + expected.absIVec = float32_t3(std::abs(testInput.absIVec.x), std::abs(testInput.absIVec.y), std::abs(testInput.absIVec.z)); + expected.sqrtVec = float32_t3(std::sqrt(testInput.sqrtVec.x), std::sqrt(testInput.sqrtVec.y), std::sqrt(testInput.sqrtVec.z)); + expected.cosVec = float32_t3(std::cos(testInput.cosVec.x), std::cos(testInput.cosVec.y), std::cos(testInput.cosVec.z)); + expected.sinVec = float32_t3(std::sin(testInput.sinVec.x), std::sin(testInput.sinVec.y), std::sin(testInput.sinVec.z)); + expected.acosVec = float32_t3(std::acos(testInput.acosVec.x), std::acos(testInput.acosVec.y), std::acos(testInput.acosVec.z)); { float tmp; - expectedTestValues.modfVec = float32_t3(std::modf(commonTestInputValues.modfVec.x, &tmp), std::modf(commonTestInputValues.modfVec.y, &tmp), std::modf(commonTestInputValues.modfVec.z, &tmp)); + expected.modfVec = float32_t3(std::modf(testInput.modfVec.x, &tmp), std::modf(testInput.modfVec.y, &tmp), std::modf(testInput.modfVec.z, &tmp)); } - expectedTestValues.roundVec = float32_t3( - std::round(commonTestInputValues.roundVec.x), - std::round(commonTestInputValues.roundVec.y), - std::round(commonTestInputValues.roundVec.z) + expected.roundVec = float32_t3( + std::round(testInput.roundVec.x), + std::round(testInput.roundVec.y), + std::round(testInput.roundVec.z) ); // TODO: uncomment when C++23 - //expectedTestValues.roundEven = float32_t( - // std::roundeven(commonTestInputValues.roundEvenVec.x), - // std::roundeven(commonTestInputValues.roundEvenVec.y), - // std::roundeven(commonTestInputValues.roundEvenVec.z) + //expected.roundEven = float32_t( + // std::roundeven(testInput.roundEvenVec.x), + // std::roundeven(testInput.roundEvenVec.y), + // std::roundeven(testInput.roundEvenVec.z) // ); // TODO: remove when C++23 - expectedTestValues.roundEvenVec = float32_t3( - roundeven(commonTestInputValues.roundEvenVec.x), - roundeven(commonTestInputValues.roundEvenVec.y), - roundeven(commonTestInputValues.roundEvenVec.z) + expected.roundEvenVec = float32_t3( + roundeven(testInput.roundEvenVec.x), + roundeven(testInput.roundEvenVec.y), + roundeven(testInput.roundEvenVec.z) ); - expectedTestValues.truncVec = float32_t3(std::trunc(commonTestInputValues.truncVec.x), std::trunc(commonTestInputValues.truncVec.y), std::trunc(commonTestInputValues.truncVec.z)); - expectedTestValues.ceilVec = float32_t3(std::ceil(commonTestInputValues.ceilVec.x), std::ceil(commonTestInputValues.ceilVec.y), std::ceil(commonTestInputValues.ceilVec.z)); - expectedTestValues.fmaVec = float32_t3( - std::fma(commonTestInputValues.fmaXVec.x, commonTestInputValues.fmaYVec.x, commonTestInputValues.fmaZVec.x), - std::fma(commonTestInputValues.fmaXVec.y, commonTestInputValues.fmaYVec.y, commonTestInputValues.fmaZVec.y), - std::fma(commonTestInputValues.fmaXVec.z, commonTestInputValues.fmaYVec.z, commonTestInputValues.fmaZVec.z) + expected.truncVec = float32_t3(std::trunc(testInput.truncVec.x), std::trunc(testInput.truncVec.y), std::trunc(testInput.truncVec.z)); + expected.ceilVec = float32_t3(std::ceil(testInput.ceilVec.x), std::ceil(testInput.ceilVec.y), std::ceil(testInput.ceilVec.z)); + expected.fmaVec = float32_t3( + std::fma(testInput.fmaXVec.x, testInput.fmaYVec.x, testInput.fmaZVec.x), + std::fma(testInput.fmaXVec.y, testInput.fmaYVec.y, testInput.fmaZVec.y), + std::fma(testInput.fmaXVec.z, testInput.fmaYVec.z, testInput.fmaZVec.z) ); - expectedTestValues.ldexpVec = float32_t3( - std::ldexp(commonTestInputValues.ldexpArgVec.x, commonTestInputValues.ldexpExpVec.x), - std::ldexp(commonTestInputValues.ldexpArgVec.y, commonTestInputValues.ldexpExpVec.y), - std::ldexp(commonTestInputValues.ldexpArgVec.z, commonTestInputValues.ldexpExpVec.z) + expected.ldexpVec = float32_t3( + std::ldexp(testInput.ldexpArgVec.x, testInput.ldexpExpVec.x), + std::ldexp(testInput.ldexpArgVec.y, testInput.ldexpExpVec.y), + std::ldexp(testInput.ldexpArgVec.z, testInput.ldexpExpVec.z) ); - performCpuTests(commonTestInputValues, expectedTestValues); - performGpuTests(commonTestInputValues, expectedTestValues); + performCpuTests(testInput, expected); + performGpuTests(testInput, expected); } m_logger->log("tgmath.hlsl TESTS DONE.", system::ILogger::ELL_PERFORMANCE); } private: - inline static constexpr int Iterations = 100u; + inline static constexpr int Iterations = 1u; void performCpuTests(const TgmathIntputTestValues& commonTestInputValues, const TgmathTestValues& expectedTestValues) { @@ -778,7 +780,7 @@ class CIntrinsicsTester final : public ITester } private: - inline static constexpr int Iterations = 100u; + inline static constexpr int Iterations = 1u; void performCpuTests(const IntrinsicsIntputTestValues& commonTestInputValues, const IntrinsicsTestValues& expectedTestValues) { From 608765317860bcb1b34fba4e858143a8037e2446 Mon Sep 17 00:00:00 2001 From: Przemek Date: Tue, 4 Feb 2025 14:10:28 +0100 Subject: [PATCH 83/83] Updated tests --- 22_CppCompat/Testers.h | 76 +++++++++++++------------- 22_CppCompat/app_resources/common.hlsl | 30 +++++----- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/22_CppCompat/Testers.h b/22_CppCompat/Testers.h index 2426e3e49..17b2ad0db 100644 --- a/22_CppCompat/Testers.h +++ b/22_CppCompat/Testers.h @@ -397,6 +397,11 @@ class CTgmathTester final : public ITester testInput.ldexpArgVec = float32_t3(realDistributionSmall(mt), realDistributionSmall(mt), realDistributionSmall(mt)); testInput.ldexpExpVec = float32_t3(intDistribution(mt), intDistribution(mt), intDistribution(mt)); + testInput.modfStruct = realDistribution(mt); + testInput.modfStructVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + testInput.frexpStruct = realDistribution(mt); + testInput.frexpStructVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); + // use std library functions to determine expected test values, the output of functions from tgmath.hlsl will be verified against these values TgmathTestValues expected; expected.floor = std::floor(testInput.floor); @@ -495,6 +500,28 @@ class CTgmathTester final : public ITester std::ldexp(testInput.ldexpArgVec.z, testInput.ldexpExpVec.z) ); + { + ModfOutput expectedModfStructOutput; + expectedModfStructOutput.fractionalPart = std::modf(testInput.modfStruct, &expectedModfStructOutput.wholeNumberPart); + expected.modfStruct = expectedModfStructOutput; + + ModfOutput expectedModfStructOutputVec; + for (int i = 0; i < 3; ++i) + expectedModfStructOutputVec.fractionalPart[i] = std::modf(testInput.modfStructVec[i], &expectedModfStructOutputVec.wholeNumberPart[i]); + expected.modfStructVec = expectedModfStructOutputVec; + } + + { + FrexpOutput expectedFrexpStructOutput; + expectedFrexpStructOutput.significand = std::frexp(testInput.frexpStruct, &expectedFrexpStructOutput.exponent); + expected.frexpStruct = expectedFrexpStructOutput; + + FrexpOutput expectedFrexpStructOutputVec; + for (int i = 0; i < 3; ++i) + expectedFrexpStructOutputVec.significand[i] = std::frexp(testInput.frexpStructVec[i], &expectedFrexpStructOutputVec.exponent[i]); + expected.frexpStructVec = expectedFrexpStructOutputVec; + } + performCpuTests(testInput, expected); performGpuTests(testInput, expected); } @@ -564,6 +591,17 @@ class CTgmathTester final : public ITester verifyTestVector3dValue("ceilVec", expectedTestValues.ceilVec, testValues.ceilVec, testType); verifyTestVector3dValue("fmaVec", expectedTestValues.fmaVec, testValues.fmaVec, testType); verifyTestVector3dValue("ldexp", expectedTestValues.ldexpVec, testValues.ldexpVec, testType); + + // verify output of struct producing functions + verifyTestValue("modfStruct", expectedTestValues.modfStruct.fractionalPart, testValues.modfStruct.fractionalPart, testType); + verifyTestValue("modfStruct", expectedTestValues.modfStruct.wholeNumberPart, testValues.modfStruct.wholeNumberPart, testType); + verifyTestVector3dValue("modfStructVec", expectedTestValues.modfStructVec.fractionalPart, testValues.modfStructVec.fractionalPart, testType); + verifyTestVector3dValue("modfStructVec", expectedTestValues.modfStructVec.wholeNumberPart, testValues.modfStructVec.wholeNumberPart, testType); + + verifyTestValue("frexpStruct", expectedTestValues.frexpStruct.significand, testValues.frexpStruct.significand, testType); + verifyTestValue("frexpStruct", expectedTestValues.frexpStruct.exponent, testValues.frexpStruct.exponent, testType); + verifyTestVector3dValue("frexpStructVec", expectedTestValues.frexpStructVec.significand, testValues.frexpStructVec.significand, testType); + verifyTestVector3dValue("frexpStructVec", expectedTestValues.frexpStructVec.exponent, testValues.frexpStructVec.exponent, testType); } }; @@ -678,11 +716,6 @@ class CIntrinsicsTester final : public ITester testInput.refractN = glm::normalize(float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt))); testInput.refractEta = realDistribution(mt); - testInput.modfStruct = realDistribution(mt); - testInput.modfStructVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - testInput.frexpStruct = realDistribution(mt); - testInput.frexpStructVec = float32_t3(realDistribution(mt), realDistribution(mt), realDistribution(mt)); - // use std library or glm functions to determine expected test values, the output of functions from intrinsics.hlsl will be verified against these values IntrinsicsTestValues expected; expected.bitCount = glm::bitCount(testInput.bitCount); @@ -751,28 +784,6 @@ class CIntrinsicsTester final : public ITester auto inverseGlm = glm::inverse(reinterpret_cast(testInput.inverse)); expected.inverse = reinterpret_cast(inverseGlm); - { - ModfOutput expectedModfStructOutput; - expectedModfStructOutput.fractionalPart = std::modf(testInput.modfStruct, &expectedModfStructOutput.wholeNumberPart); - expected.modfStruct = expectedModfStructOutput; - - ModfOutput expectedModfStructOutputVec; - for (int i = 0; i < 3; ++i) - expectedModfStructOutputVec.fractionalPart[i] = std::modf(testInput.modfStructVec[i], &expectedModfStructOutputVec.wholeNumberPart[i]); - expected.modfStructVec = expectedModfStructOutputVec; - } - - { - FrexpOutput expectedFrexpStructOutput; - expectedFrexpStructOutput.significand = std::frexp(testInput.frexpStruct, &expectedFrexpStructOutput.exponent); - expected.frexpStruct = expectedFrexpStructOutput; - - FrexpOutput expectedFrexpStructOutputVec; - for (int i = 0; i < 3; ++i) - expectedFrexpStructOutputVec.significand[i] = std::frexp(testInput.frexpStructVec[i], &expectedFrexpStructOutputVec.exponent[i]); - expected.frexpStructVec = expectedFrexpStructOutputVec; - } - performCpuTests(testInput, expected); performGpuTests(testInput, expected); } @@ -843,17 +854,6 @@ class CIntrinsicsTester final : public ITester verifyTestMatrix3x3Value("mul", expectedTestValues.mul, testValues.mul, testType); verifyTestMatrix3x3Value("transpose", expectedTestValues.transpose, testValues.transpose, testType); verifyTestMatrix3x3Value("inverse", expectedTestValues.inverse, testValues.inverse, testType); - - // verify output of struct producing functions - verifyTestValue("modfStruct", expectedTestValues.modfStruct.fractionalPart, testValues.modfStruct.fractionalPart, testType); - verifyTestValue("modfStruct", expectedTestValues.modfStruct.wholeNumberPart, testValues.modfStruct.wholeNumberPart, testType); - verifyTestVector3dValue("modfStructVec", expectedTestValues.modfStructVec.fractionalPart, testValues.modfStructVec.fractionalPart, testType); - verifyTestVector3dValue("modfStructVec", expectedTestValues.modfStructVec.wholeNumberPart, testValues.modfStructVec.wholeNumberPart, testType); - - verifyTestValue("frexpStruct", expectedTestValues.frexpStruct.significand, testValues.frexpStruct.significand, testType); - verifyTestValue("frexpStruct", expectedTestValues.frexpStruct.exponent, testValues.frexpStruct.exponent, testType); - verifyTestVector3dValue("frexpStructVec", expectedTestValues.frexpStructVec.significand, testValues.frexpStructVec.significand, testType); - verifyTestVector3dValue("frexpStructVec", expectedTestValues.frexpStructVec.exponent, testValues.frexpStructVec.exponent, testType); } }; diff --git a/22_CppCompat/app_resources/common.hlsl b/22_CppCompat/app_resources/common.hlsl index c196a389b..381b00563 100644 --- a/22_CppCompat/app_resources/common.hlsl +++ b/22_CppCompat/app_resources/common.hlsl @@ -66,6 +66,8 @@ struct TgmathIntputTestValues float fmaZ; float ldexpArg; int ldexpExp; + float modfStruct; + float frexpStruct; float32_t3 floorVec; float32_t3 isnanVec; @@ -92,6 +94,8 @@ struct TgmathIntputTestValues float32_t3 fmaZVec; float32_t3 ldexpArgVec; int32_t3 ldexpExpVec; + float32_t3 modfStructVec; + float32_t3 frexpStructVec; }; struct TgmathTestValues @@ -146,6 +150,11 @@ struct TgmathTestValues float32_t3 fmaVec; float32_t3 ldexpVec; + ModfOutput modfStruct; + ModfOutput modfStructVec; + FrexpOutput frexpStruct; + FrexpOutput frexpStructVec; + void fillTestValues(NBL_CONST_REF_ARG(TgmathIntputTestValues) input) { floor = nbl::hlsl::floor(input.floor); @@ -191,6 +200,11 @@ struct TgmathTestValues ceilVec = nbl::hlsl::ceil(input.ceilVec); fmaVec = nbl::hlsl::fma(input.fmaXVec, input.fmaYVec, input.fmaZVec); ldexpVec = nbl::hlsl::ldexp(input.ldexpArgVec, input.ldexpExpVec); + + modfStruct = nbl::hlsl::modfStruct(input.modfStruct); + modfStructVec = nbl::hlsl::modfStruct(input.modfStructVec); + frexpStruct = nbl::hlsl::frexpStruct(input.frexpStruct); + frexpStructVec = nbl::hlsl::frexpStruct(input.frexpStructVec); } }; @@ -231,8 +245,6 @@ struct IntrinsicsIntputTestValues float smoothStepEdge0; float smoothStepEdge1; float smoothStepX; - float modfStruct; - float frexpStruct; int32_t3 bitCountVec; float32_t3 clampValVec; @@ -266,8 +278,6 @@ struct IntrinsicsIntputTestValues float32_t3 refractI; float32_t3 refractN; float refractEta; - float32_t3 modfStructVec; - float32_t3 frexpStructVec; }; struct IntrinsicsTestValues @@ -316,12 +326,6 @@ struct IntrinsicsTestValues float32_t3x3 transpose; float32_t3x3 inverse; - ModfOutput modfStruct; - ModfOutput modfStructVec; - - FrexpOutput frexpStruct; - FrexpOutput frexpStructVec; - void fillTestValues(NBL_CONST_REF_ARG(IntrinsicsIntputTestValues) input) { bitCount = nbl::hlsl::bitCount(input.bitCount); @@ -369,12 +373,6 @@ struct IntrinsicsTestValues faceForward = nbl::hlsl::faceForward(input.faceForwardN, input.faceForwardI, input.faceForwardNref); reflect = nbl::hlsl::reflect(input.reflectI, input.reflectN); refract = nbl::hlsl::refract(input.refractI, input.refractN, input.refractEta); - - modfStruct = nbl::hlsl::modfStruct(input.modfStruct); - modfStructVec = nbl::hlsl::modfStruct(input.modfStructVec); - - frexpStruct = nbl::hlsl::frexpStruct(input.frexpStruct); - frexpStructVec = nbl::hlsl::frexpStruct(input.frexpStructVec); } };