Bulk update nvpro-samples 11/20/23

5c72ddfc0522eb6604828e74886cf39be646ba78
This commit is contained in:
Mathias Heyer 2023-11-20 13:54:44 -08:00
parent debd0d5e33
commit 0c73e8ec1b
96 changed files with 927 additions and 922 deletions

View file

@ -37,6 +37,8 @@
#include "nvvk/shaders_vk.hpp"
#include "nvvk/buffers_vk.hpp"
#include <glm/gtc/matrix_access.hpp>
extern std::vector<std::string> defaultSearchPaths;
@ -61,12 +63,12 @@ void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
GlobalUniforms hostUBO = {};
const auto& view = CameraManip.getMatrix();
const auto& proj = nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, 0.1f, 1000.0f);
// proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f);
proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
hostUBO.viewProj = proj * view;
hostUBO.viewInverse = nvmath::invert(view);
hostUBO.projInverse = nvmath::invert(proj);
hostUBO.viewInverse = glm::inverse(view);
hostUBO.projInverse = glm::inverse(proj);
// UBO on the device, and what stages access it.
VkBuffer deviceUBO = m_bGlobals.buffer;
@ -185,7 +187,7 @@ void HelloVulkan::createGraphicsPipeline()
//--------------------------------------------------------------------------------------------------
// Loading the OBJ file and setting up all buffers
//
void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform)
void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform)
{
LOGI("Loading File: %s \n", filename.c_str());
ObjLoader loader;
@ -194,9 +196,9 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
// Converting from Srgb to linear
for(auto& m : loader.m_materials)
{
m.ambient = nvmath::pow(m.ambient, 2.2f);
m.diffuse = nvmath::pow(m.diffuse, 2.2f);
m.specular = nvmath::pow(m.specular, 2.2f);
m.ambient = glm::pow(m.ambient, glm::vec3(2.2f));
m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f));
m.specular = glm::pow(m.specular, glm::vec3(2.2f));
}
ObjModel model;
@ -245,7 +247,7 @@ void HelloVulkan::loadModel(const std::string& filename, nvmath::mat4f transform
}
// Add a light-emitting colored lantern to the scene. May only be called before TLAS build.
void HelloVulkan::addLantern(nvmath::vec3f pos, nvmath::vec3f color, float brightness, float radius)
void HelloVulkan::addLantern(glm::vec3 pos, glm::vec3 color, float brightness, float radius)
{
assert(m_lanternCount == 0); // Indicates TLAS build has not happened yet.
@ -656,13 +658,13 @@ auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
// Tesselate a sphere as a list of triangles; return its
// vertices and indices as reference arguments.
void HelloVulkan::fillLanternVerts(std::vector<nvmath::vec3f>& vertices, std::vector<uint32_t>& indices)
void HelloVulkan::fillLanternVerts(std::vector<glm::vec3>& vertices, std::vector<uint32_t>& indices)
{
// Create a spherical lantern model by recursively tesselating an octahedron.
struct VertexIndex
{
nvmath::vec3f vertex;
uint32_t index; // Keep track of this vert's _eventual_ index in vertices.
glm::vec3 vertex;
uint32_t index; // Keep track of this vert's _eventual_ index in vertices.
};
struct Triangle
{
@ -691,9 +693,9 @@ void HelloVulkan::fillLanternVerts(std::vector<nvmath::vec3f>& vertices, std::ve
// Split each of three edges in half, then fixup the
// length of the midpoint to match m_lanternModelRadius.
// Record the index the new vertices will eventually have in vertices.
VertexIndex v01{m_lanternModelRadius * nvmath::normalize(t.vert0.vertex + t.vert1.vertex), vertexCount++};
VertexIndex v12{m_lanternModelRadius * nvmath::normalize(t.vert1.vertex + t.vert2.vertex), vertexCount++};
VertexIndex v02{m_lanternModelRadius * nvmath::normalize(t.vert0.vertex + t.vert2.vertex), vertexCount++};
VertexIndex v01{m_lanternModelRadius * glm::normalize(t.vert0.vertex + t.vert1.vertex), vertexCount++};
VertexIndex v12{m_lanternModelRadius * glm::normalize(t.vert1.vertex + t.vert2.vertex), vertexCount++};
VertexIndex v02{m_lanternModelRadius * glm::normalize(t.vert0.vertex + t.vert2.vertex), vertexCount++};
// Old triangle becomes 4 new triangles.
new_triangles.push_back({t.vert0, v01, v02});
@ -731,8 +733,8 @@ void HelloVulkan::fillLanternVerts(std::vector<nvmath::vec3f>& vertices, std::ve
// concept of intersection shaders here.
void HelloVulkan::createLanternModel()
{
std::vector<nvmath::vec3f> vertices;
std::vector<uint32_t> indices;
std::vector<glm::vec3> vertices;
std::vector<uint32_t> indices;
fillLanternVerts(vertices, indices);
// Upload vertex and index data to buffers.
@ -761,7 +763,7 @@ void HelloVulkan::createLanternModel()
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
triangles.vertexData.deviceAddress = vertexAddress;
triangles.vertexStride = sizeof(nvmath::vec3f);
triangles.vertexStride = sizeof(glm::vec3);
// Describe index data (32-bit unsigned int)
triangles.indexType = VK_INDEX_TYPE_UINT32;
triangles.indexData.deviceAddress = indexAddress;
@ -849,8 +851,8 @@ void HelloVulkan::createTopLevelAS()
for(int i = 0; i < static_cast<int>(m_lanterns.size()); ++i)
{
VkAccelerationStructureInstanceKHR lanternInstance;
lanternInstance.transform = nvvk::toTransformMatrixKHR(nvmath::translation_mat4(m_lanterns[i].position));
lanternInstance.instanceCustomIndex = i;
lanternInstance.transform = nvvk::toTransformMatrixKHR(glm::translate(glm::mat4(1), m_lanterns[i].position));
lanternInstance.instanceCustomIndex = i;
lanternInstance.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(uint32_t(m_lanternBlasId));
lanternInstance.instanceShaderBindingTableRecordOffset = 1; // Next hit group is for lanterns.
lanternInstance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
@ -887,7 +889,7 @@ void HelloVulkan::createRtDescriptorSet()
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet);
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
descASInfo.accelerationStructureCount = 1;
descASInfo.pAccelerationStructures = &tlas;
@ -1126,9 +1128,9 @@ void HelloVulkan::createRtShaderBindingTable()
// The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned.
uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment);
m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment);
m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member
m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member
m_missRegion.stride = handleSizeAligned;
m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment);
m_hitRegion.stride = handleSizeAligned;
@ -1143,9 +1145,9 @@ void HelloVulkan::createRtShaderBindingTable()
// Allocate a buffer for storing the SBT.
VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size;
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
| VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
| VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight.
// Find the SBT addresses of each group
@ -1284,7 +1286,7 @@ void HelloVulkan::createLanternIndirectBuffer()
// effect. This is stored in m_lanternIndirectBuffer. Then an indirect trace rays command
// is run for every lantern within its scissor rectangle. The lanterns' light
// contribution is additively blended into the output image.
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor)
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor)
{
// Before tracing rays, we need to dispatch the compute shaders that
// fill in the ray trace indirect parameters for each lantern pass.
@ -1306,10 +1308,10 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
// Bind compute shader, update push constant and descriptors, dispatch compute.
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipeline);
nvmath::mat4f view = getViewMatrix();
m_lanternIndirectPushConstants.viewRowX = view.row(0);
m_lanternIndirectPushConstants.viewRowY = view.row(1);
m_lanternIndirectPushConstants.viewRowZ = view.row(2);
glm::mat4 view = getViewMatrix();
m_lanternIndirectPushConstants.viewRowX = glm::row(view, 0);
m_lanternIndirectPushConstants.viewRowY = glm::row(view, 1);
m_lanternIndirectPushConstants.viewRowZ = glm::row(view, 2);
m_lanternIndirectPushConstants.proj = getProjMatrix();
m_lanternIndirectPushConstants.nearZ = nearZ;
m_lanternIndirectPushConstants.screenX = m_size.width;
@ -1360,7 +1362,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c
for(int i = 0; i < static_cast<int>(m_lanternCount); ++i)
{
// Barrier to ensure previous pass finished.
VkImage offscreenImage{m_offscreenColor.image};
VkImage offscreenImage{m_offscreenColor.image};
VkImageSubresourceRange colorRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS};
VkImageMemoryBarrier imageBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
imageBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;

View file

@ -42,20 +42,22 @@ public:
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
void createDescriptorSetLayout();
void createGraphicsPipeline();
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
void addLantern(nvmath::vec3f pos, nvmath::vec3f color, float brightness, float radius);
void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1));
void addLantern(glm::vec3 pos, glm::vec3 color, float brightness, float radius);
void updateDescriptorSet();
void createUniformBuffer();
void createObjDescriptionBuffer();
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
nvmath::mat4f getViewMatrix() { return CameraManip.getMatrix(); }
glm::mat4 getViewMatrix() { return CameraManip.getMatrix(); }
static constexpr float nearZ = 0.1f;
nvmath::mat4f getProjMatrix()
glm::mat4 getProjMatrix()
{
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
return nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, nearZ, 1000.0f);
glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, nearZ, 1000.0f);
proj[1][1] *= -1;
return proj;
}
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
@ -76,27 +78,27 @@ public:
struct ObjInstance
{
nvmath::mat4f transform; // Matrix of the instance
uint32_t objIndex{0}; // Model index reference
glm::mat4 transform; // Matrix of the instance
uint32_t objIndex{0}; // Model index reference
};
// Information pushed at each draw call
PushConstantRaster m_pcRaster{
{1}, // Identity matrix
{10.f, 15.f, 8.f}, // light position
0, // instance Id
100.f, // light intensity
0 // light type
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix
{10.f, 15.f, 8.f}, // light position
0, // instance Id
100.f, // light intensity
0 // light type
};
// Information on each colored lantern illuminating the scene.
struct Lantern
{
nvmath::vec3f position;
nvmath::vec3f color;
float brightness{0};
float radius{0}; // Max world-space distance that light illuminates.
glm::vec3 position;
glm::vec3 color;
float brightness{0};
float radius{0}; // Max world-space distance that light illuminates.
};
// Information on each colored lantern, plus the info needed for dispatching the
@ -166,7 +168,7 @@ public:
auto objectToVkGeometryKHR(const ObjModel& model);
private:
void fillLanternVerts(std::vector<nvmath::vec3f>& vertices, std::vector<uint32_t>& indices);
void fillLanternVerts(std::vector<glm::vec3>& vertices, std::vector<uint32_t>& indices);
void createLanternModel();
public:
@ -180,7 +182,7 @@ public:
void createRtShaderBindingTable();
void createLanternIndirectBuffer();
void raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor);
// Used to store lantern model, generated at runtime.
const float m_lanternModelRadius = 0.125;
@ -192,11 +194,11 @@ public:
size_t m_lanternBlasId;
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
VkDescriptorPool m_rtDescPool;
VkDescriptorSetLayout m_rtDescSetLayout;
VkDescriptorSet m_rtDescSet;
nvvk::RaytracingBuilderKHR m_rtBuilder;
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
VkDescriptorPool m_rtDescPool;
VkDescriptorSetLayout m_rtDescSetLayout;
VkDescriptorSet m_rtDescSet;
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
VkPipelineLayout m_rtPipelineLayout;
VkPipeline m_rtPipeline;
@ -233,12 +235,12 @@ public:
// Barely fits in 128-byte push constant limit guaranteed by spec.
struct LanternIndirectPushConstants
{
nvmath::vec4f viewRowX; // First 3 rows of view matrix.
nvmath::vec4f viewRowY; // Set w=1 implicitly in shader.
nvmath::vec4f viewRowZ;
glm::vec4 viewRowX; // First 3 rows of view matrix.
glm::vec4 viewRowY; // Set w=1 implicitly in shader.
glm::vec4 viewRowZ;
nvmath::mat4f proj{}; // Perspective matrix
float nearZ{}; // Near plane used to create projection matrix.
glm::mat4 proj{}; // Perspective matrix
float nearZ{}; // Near plane used to create projection matrix.
// Pixel dimensions of output image (needed to scale NDC to screen coordinates).
int32_t screenX{};

View file

@ -95,7 +95,7 @@ int main(int argc, char** argv)
// Setup camera
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
CameraManip.setLookat(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0));
// Setup Vulkan
if(!glfwVulkanSupported())
@ -197,8 +197,8 @@ int main(int argc, char** argv)
helloVk.updatePostDescriptorSet();
nvmath::vec4f clearColor = nvmath::vec4f(1, 1, 1, 1.00f);
bool useRaytracer = true;
glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f);
bool useRaytracer = true;
helloVk.setupGlfwCallbacks(window);

View file

@ -22,12 +22,12 @@
#define COMMON_HOST_DEVICE
#ifdef __cplusplus
#include "nvmath/nvmath.h"
#include <glm/glm.hpp>
// GLSL Type
using vec2 = nvmath::vec2f;
using vec3 = nvmath::vec3f;
using vec4 = nvmath::vec4f;
using mat4 = nvmath::mat4f;
using vec2 = glm::vec2;
using vec3 = glm::vec3;
using vec4 = glm::vec4;
using mat4 = glm::mat4;
using uint = unsigned int;
#endif

View file

@ -16,7 +16,7 @@
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#version 460
#extension GL_GOOGLE_include_directive : enable
@ -32,18 +32,22 @@ layout(local_size_x = LOCAL_SIZE, local_size_y = 1, local_size_z = 1) in;
#include "LanternIndirectEntry.glsl"
layout(binding = 0, set = 0) buffer LanternArray { LanternIndirectEntry lanterns[]; } lanterns;
layout(binding = 0, set = 0) buffer LanternArray
{
LanternIndirectEntry lanterns[];
}
lanterns;
layout(push_constant) uniform Constants
{
vec4 viewRowX;
vec4 viewRowY;
vec4 viewRowZ;
mat4 proj;
vec4 viewRowX;
vec4 viewRowY;
vec4 viewRowZ;
mat4 proj;
float nearZ;
int screenX;
int screenY;
int lanternCount;
int screenX;
int screenY;
int lanternCount;
}
pushC;
@ -60,123 +64,118 @@ void getScreenCoordBox(in LanternIndirectEntry lantern, out ivec2 lower, out ive
void fillIndirectEntry(int i)
{
LanternIndirectEntry lantern = lanterns.lanterns[i];
ivec2 lower, upper;
ivec2 lower, upper;
getScreenCoordBox(lantern, lower, upper);
lanterns.lanterns[i].indirectWidth = max(0, upper.x - lower.x);
lanterns.lanterns[i].indirectHeight = max(0, upper.y - lower.y);
lanterns.lanterns[i].indirectDepth = 1;
lanterns.lanterns[i].offsetX = lower.x;
lanterns.lanterns[i].offsetY = lower.y;
lanterns.lanterns[i].offsetX = lower.x;
lanterns.lanterns[i].offsetY = lower.y;
}
void main()
{
for (int i = int(gl_LocalInvocationID.x); i < pushC.lanternCount; i += LOCAL_SIZE)
for(int i = int(gl_LocalInvocationID.x); i < pushC.lanternCount; i += LOCAL_SIZE)
{
fillIndirectEntry(i);
}
}
// Functions below modified from the paper.
float square(float a) { return a*a; }
float square(float a)
{
return a * a;
}
void getBoundsForAxis(
in bool xAxis,
in vec3 center,
in float radius,
in float nearZ,
in mat4 projMatrix,
out vec3 U,
out vec3 L) {
bool trivialAccept = (center.z + radius) < nearZ; // Entirely in back of nearPlane (Trivial Accept)
vec3 a = xAxis ? vec3(1, 0, 0) : vec3(0, 1, 0);
void getBoundsForAxis(in bool xAxis, in vec3 center, in float radius, in float nearZ, in mat4 projMatrix, out vec3 U, out vec3 L)
{
bool trivialAccept = (center.z + radius) < nearZ; // Entirely in back of nearPlane (Trivial Accept)
vec3 a = xAxis ? vec3(1, 0, 0) : vec3(0, 1, 0);
// given in coordinates (a,z), where a is in the direction of the vector a, and z is in the standard z direction
vec2 projectedCenter = vec2(dot(a, center), center.z);
vec2 bounds_az[2];
float tSquared = dot(projectedCenter, projectedCenter) - square(radius);
float t, cLength, costheta = 0, sintheta = 0;
// given in coordinates (a,z), where a is in the direction of the vector a, and z is in the standard z direction
vec2 projectedCenter = vec2(dot(a, center), center.z);
vec2 bounds_az[2];
float tSquared = dot(projectedCenter, projectedCenter) - square(radius);
float t, cLength, costheta = 0, sintheta = 0;
if(tSquared > 0) { // Camera is outside sphere
// Distance to the tangent points of the sphere (points where a vector from the camera are tangent to the sphere) (calculated a-z space)
t = sqrt(tSquared);
cLength = length(projectedCenter);
if(tSquared > 0)
{ // Camera is outside sphere
// Distance to the tangent points of the sphere (points where a vector from the camera are tangent to the sphere) (calculated a-z space)
t = sqrt(tSquared);
cLength = length(projectedCenter);
// Theta is the angle between the vector from the camera to the center of the sphere and the vectors from the camera to the tangent points
costheta = t / cLength;
sintheta = radius / cLength;
// Theta is the angle between the vector from the camera to the center of the sphere and the vectors from the camera to the tangent points
costheta = t / cLength;
sintheta = radius / cLength;
}
float sqrtPart = 0.0f;
if(!trivialAccept)
sqrtPart = sqrt(square(radius) - square(nearZ - projectedCenter.y));
for(int i = 0; i < 2; ++i)
{
if(tSquared > 0)
{
float x = costheta * projectedCenter.x + -sintheta * projectedCenter.y;
float y = sintheta * projectedCenter.x + costheta * projectedCenter.y;
bounds_az[i] = costheta * vec2(x, y);
}
float sqrtPart = 0.0f;
if(!trivialAccept) sqrtPart = sqrt(square(radius) - square(nearZ - projectedCenter.y));
for(int i = 0; i < 2; ++i){
if(tSquared > 0) {
float x = costheta * projectedCenter.x + -sintheta * projectedCenter.y;
float y = sintheta * projectedCenter.x + costheta * projectedCenter.y;
bounds_az[i] = costheta * vec2(x, y);
}
if(!trivialAccept && (tSquared <= 0 || bounds_az[i].y > nearZ)) {
bounds_az[i].x = projectedCenter.x + sqrtPart;
bounds_az[i].y = nearZ;
}
sintheta *= -1; // negate theta for B
sqrtPart *= -1; // negate sqrtPart for B
if(!trivialAccept && (tSquared <= 0 || bounds_az[i].y > nearZ))
{
bounds_az[i].x = projectedCenter.x + sqrtPart;
bounds_az[i].y = nearZ;
}
U = bounds_az[0].x * a;
U.z = bounds_az[0].y;
L = bounds_az[1].x * a;
L.z = bounds_az[1].y;
sintheta *= -1; // negate theta for B
sqrtPart *= -1; // negate sqrtPart for B
}
U = bounds_az[0].x * a;
U.z = bounds_az[0].y;
L = bounds_az[1].x * a;
L.z = bounds_az[1].y;
}
/** Center is in camera space */
void getBoundingBox(
in vec3 center,
in float radius,
in float nearZ,
in mat4 projMatrix,
out vec2 ndc_low,
out vec2 ndc_high) {
vec3 maxXHomogenous, minXHomogenous, maxYHomogenous, minYHomogenous;
getBoundsForAxis(true, center, radius, nearZ, projMatrix, maxXHomogenous, minXHomogenous);
getBoundsForAxis(false, center, radius, nearZ, projMatrix, maxYHomogenous, minYHomogenous);
void getBoundingBox(in vec3 center, in float radius, in float nearZ, in mat4 projMatrix, out vec2 ndc_low, out vec2 ndc_high)
{
vec3 maxXHomogenous, minXHomogenous, maxYHomogenous, minYHomogenous;
getBoundsForAxis(true, center, radius, nearZ, projMatrix, maxXHomogenous, minXHomogenous);
getBoundsForAxis(false, center, radius, nearZ, projMatrix, maxYHomogenous, minYHomogenous);
vec4 projRow0 = vec4(projMatrix[0][0], projMatrix[1][0], projMatrix[2][0], projMatrix[3][0]);
vec4 projRow1 = vec4(projMatrix[0][1], projMatrix[1][1], projMatrix[2][1], projMatrix[3][1]);
vec4 projRow3 = vec4(projMatrix[0][3], projMatrix[1][3], projMatrix[2][3], projMatrix[3][3]);
vec4 projRow0 = vec4(projMatrix[0][0], projMatrix[1][0], projMatrix[2][0], projMatrix[3][0]);
vec4 projRow1 = vec4(projMatrix[0][1], projMatrix[1][1], projMatrix[2][1], projMatrix[3][1]);
vec4 projRow3 = vec4(projMatrix[0][3], projMatrix[1][3], projMatrix[2][3], projMatrix[3][3]);
// We only need one coordinate for each point, so we save computation by only calculating x(or y) and w
float maxX_w = dot(vec4(maxXHomogenous, 1.0f), projRow3);
float minX_w = dot(vec4(minXHomogenous, 1.0f), projRow3);
float maxY_w = dot(vec4(maxYHomogenous, 1.0f), projRow3);
float minY_w = dot(vec4(minYHomogenous, 1.0f), projRow3);
// We only need one coordinate for each point, so we save computation by only calculating x(or y) and w
float maxX_w = dot(vec4(maxXHomogenous, 1.0f), projRow3);
float minX_w = dot(vec4(minXHomogenous, 1.0f), projRow3);
float maxY_w = dot(vec4(maxYHomogenous, 1.0f), projRow3);
float minY_w = dot(vec4(minYHomogenous, 1.0f), projRow3);
float maxX = dot(vec4(maxXHomogenous, 1.0f), projRow0) / maxX_w;
float minX = dot(vec4(minXHomogenous, 1.0f), projRow0) / minX_w;
float maxY = dot(vec4(maxYHomogenous, 1.0f), projRow1) / maxY_w;
float minY = dot(vec4(minYHomogenous, 1.0f), projRow1) / minY_w;
float maxX = dot(vec4(maxXHomogenous, 1.0f), projRow0) / maxX_w;
float minX = dot(vec4(minXHomogenous, 1.0f), projRow0) / minX_w;
float maxY = dot(vec4(maxYHomogenous, 1.0f), projRow1) / maxY_w;
float minY = dot(vec4(minYHomogenous, 1.0f), projRow1) / minY_w;
// Paper minX, etc. names are misleading, not necessarily min. Fix here.
ndc_low = vec2(min(minX, maxX), min(minY, maxY));
ndc_high = vec2(max(minX, maxX), max(minY, maxY));
// Paper minX, etc. names are misleading, not necessarily min. Fix here.
ndc_low = vec2(min(minX, maxX), min(minY, maxY));
ndc_high = vec2(max(minX, maxX), max(minY, maxY));
}
void getScreenCoordBox(in LanternIndirectEntry lantern, out ivec2 lower, out ivec2 upper)
{
vec4 lanternWorldCenter = vec4(lantern.x, lantern.y, lantern.z, 1);
vec3 center = vec3(
dot(pushC.viewRowX, lanternWorldCenter),
dot(pushC.viewRowY, lanternWorldCenter),
dot(pushC.viewRowZ, lanternWorldCenter));
vec2 ndc_low, ndc_high;
float paperNearZ = -abs(pushC.nearZ); // Paper expected negative nearZ, took 2 days to figure out!
vec4 lanternWorldCenter = vec4(lantern.x, lantern.y, lantern.z, 1);
vec3 center = vec3(dot(pushC.viewRowX, lanternWorldCenter), dot(pushC.viewRowY, lanternWorldCenter),
dot(pushC.viewRowZ, lanternWorldCenter));
vec2 ndc_low, ndc_high;
float paperNearZ = -abs(pushC.nearZ); // Paper expected negative nearZ, took 2 days to figure out!
getBoundingBox(center, lantern.radius, paperNearZ, pushC.proj, ndc_low, ndc_high);
// Convert NDC [-1,+1]^2 coordinates to screen coordinates, and clamp to stay in bounds.
lower.x = clamp(int((ndc_low.x * 0.5 + 0.5) * pushC.screenX), 0, pushC.screenX);
lower.y = clamp(int((ndc_low.y * 0.5 + 0.5) * pushC.screenY), 0, pushC.screenY);
lower.x = clamp(int((ndc_low.x * 0.5 + 0.5) * pushC.screenX), 0, pushC.screenX);
lower.y = clamp(int((ndc_low.y * 0.5 + 0.5) * pushC.screenY), 0, pushC.screenY);
upper.x = clamp(int((ndc_high.x * 0.5 + 0.5) * pushC.screenX), 0, pushC.screenX);
upper.y = clamp(int((ndc_high.y * 0.5 + 0.5) * pushC.screenY), 0, pushC.screenY);
}