From a0862820e692f80420191812af4c61ad094d64fc Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 27 Sep 2016 18:38:15 -0700 Subject: [PATCH] MOre refinements? --- .../render-utils/src/LightClusterGrid.slh | 11 -- .../src/LightClusterGrid_shared.slh | 43 ++++-- libraries/render-utils/src/LightClusters.cpp | 122 +++++++++++------- libraries/render-utils/src/LightClusters.h | 8 +- .../src/lightClusters_drawClusterContent.slv | 2 +- .../lightClusters_drawClusterFromDepth.slf | 2 +- .../lightClusters_drawClusterFromDepth.slv | 10 +- .../src/lightClusters_drawGrid.slv | 2 +- .../render-utils/src/local_lights_shading.slf | 2 +- 9 files changed, 116 insertions(+), 86 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index cd94b49ddd..7964d09142 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -55,17 +55,6 @@ uniform clusterContentBuffer { int _clusterGridContent[16384]; }; -int clusterGrid_clusterToIndex(ivec3 pos) { - return pos.x + (pos.y + pos.z * frustumGrid.dims.y) * frustumGrid.dims.x; -} -ivec3 clusterGrid_indexToCluster(int index) { - ivec3 summedDims = ivec3(frustumGrid.dims.x * frustumGrid.dims.y, frustumGrid.dims.x, 1); - int layer = index / summedDims.x; - int offsetInLayer = index % summedDims.x; - ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); - return clusterPos; -} - ivec2 clusterGrid_getCluster(int index) { int clusterDesc = _clusterGridTable[index]; int numLights = 0xFFFF & (clusterDesc >> 16); diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index b124798131..54281d010e 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -1,27 +1,33 @@ // glsl / C++ compatible source as interface for FrustrumGrid -float frustumGrid_depthRamp(float linear) { - // return linear; - return linear * linear; +float frustumGrid_depthRampGridToVolume(float ngrid) { + if (ngrid < 0.0) + return ngrid; + // return ngrid; + // return sqrt(ngrid); + return exp2(ngrid) - 1.0; } -float frustumGrid_depthRampInverse(float volume) { - // return volume; - return sqrt(volume); +float frustumGrid_depthRampInverseVolumeToGrid(float nvolume) { + if (nvolume < 0.0) + return nvolume; + // return nvolume; + // return nvolume * nvolume; + return log2(nvolume + 1.0); } vec3 frustumGrid_gridToVolume(vec3 pos, ivec3 dims) { vec3 gridScale = vec3(1.0, 1.0, 1.0) / vec3(dims); vec3 volumePos = pos * gridScale; - volumePos.z = frustumGrid_depthRamp(volumePos.z); + volumePos.z = frustumGrid_depthRampGridToVolume(volumePos.z); return volumePos; } float frustumGrid_volumeToGridDepth(float vposZ, ivec3 dims) { - return frustumGrid_depthRampInverse(vposZ) * float(dims.z); + return frustumGrid_depthRampInverseVolumeToGrid(vposZ) * float(dims.z); } vec3 frustumGrid_volumeToGrid(vec3 vpos, ivec3 dims) { - vec3 gridPos = vec3(vpos.x, vpos.y, frustumGrid_depthRampInverse(vpos.z)) * vec3(dims); + vec3 gridPos = vec3(vpos.x, vpos.y, frustumGrid_depthRampInverseVolumeToGrid(vpos.z)) * vec3(dims); return gridPos; } @@ -68,6 +74,21 @@ int frustumGrid_numClusters() { return frustumGrid.dims.x * frustumGrid.dims.y * (frustumGrid.dims.z + 1); } +int frustumGrid_clusterToIndex(ivec3 pos) { + return pos.x + (pos.y + pos.z * frustumGrid.dims.y) * frustumGrid.dims.x; +} +ivec3 frustumGrid_indexToCluster(int index) { + if (index <= 0) { + return ivec3(0, 0, -1); + } + index -= 1; + ivec3 summedDims = ivec3(frustumGrid.dims.x * frustumGrid.dims.y, frustumGrid.dims.x, 1); + int layer = index / summedDims.x; + int offsetInLayer = index % summedDims.x; + ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); + return clusterPos; +} + vec3 frustumGrid_clusterPosToEye(vec3 clusterPos) { vec3 cvpos = clusterPos; @@ -87,7 +108,7 @@ vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) { int frustumGrid_eyeDepthToClusterLayer(float eyeZ) { if ((eyeZ > -frustumGrid.frustumNear) || (eyeZ < -frustumGrid.frustumFar)) { - return -1; + return -2; } if (eyeZ > -frustumGrid.rangeNear) { @@ -108,7 +129,7 @@ int frustumGrid_eyeDepthToClusterLayer(float eyeZ) { ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { if ((eyePos.z > -frustumGrid.frustumNear) || (eyePos.z < -frustumGrid.frustumFar)) { - return ivec3(-1); + return ivec3(-2); } if (eyePos.z > -frustumGrid.rangeNear) { diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 362e6c3665..651ba4957d 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -49,18 +49,18 @@ void FrustumGrid::generateGridPlanes(Planes& xPlanes, Planes& yPlanes, Planes& z float centerY = float(dims.y) * 0.5; float centerX = float(dims.x) * 0.5; - for (int z = 0; z < zPlanes.size(); z++) { + for (int z = 0; z < (int) zPlanes.size(); z++) { ivec3 pos(0, 0, z); zPlanes[z] = glm::vec4(0.0f, 0.0f, 1.0f, -frustumGrid_clusterPosToEye(pos, vec3(0.0)).z); } - for (int x = 0; x < xPlanes.size(); x++) { + for (int x = 0; x < (int) xPlanes.size(); x++) { auto slicePos = frustumGrid_clusterPosToEye(glm::vec3((float)x, centerY, 0.0)); auto sliceDir = glm::normalize(slicePos); xPlanes[x] = glm::vec4(sliceDir.z, 0.0, -sliceDir.x, 0.0); } - for (int y = 0; y < yPlanes.size(); y++) { + for (int y = 0; y < (int) yPlanes.size(); y++) { auto slicePos = frustumGrid_clusterPosToEye(glm::vec3(centerX, (float)y, 0.0)); auto sliceDir = glm::normalize(slicePos); yPlanes[y] = glm::vec4(0.0, sliceDir.z, -sliceDir.y, 0.0); @@ -177,72 +177,95 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p } float distanceToPlane(const glm::vec3& point, const glm::vec4& plane) { - return glm::dot(plane, glm::vec4(point.x, point.y, point.z, -1.0)); + return plane.x * point.x + plane.y * point.y + plane.z * point.z + plane.w; } -glm::vec4 projectToPlane(glm::vec4& sphere, const glm::vec4& plane) { +bool reduceSphereToPlane(const glm::vec4& sphere, const glm::vec4& plane, glm::vec4& reducedSphere) { float distance = distanceToPlane(glm::vec3(sphere), plane); - if (distance < sphere.w) { - return glm::vec4(sphere.x - distance * plane.x, sphere.y - distance * plane.y, sphere.z - distance * plane.z, sqrt(sphere.w * sphere.w - distance * distance)); - } else { - return sphere; + if (abs(distance) <= sphere.w) { + reducedSphere = glm::vec4(sphere.x - distance * plane.x, sphere.y - distance * plane.y, sphere.z - distance * plane.z, sqrt(sphere.w * sphere.w - distance * distance)); + return true; } + + return false; } -bool scanLightVolume(const FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, - uint32_t& numClustersTouched, uint32_t maxNumIndices, std::vector< std::vector>& clusterGrid) { +uint32_t scanLightVolumeBox(FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, + std::vector< std::vector>& clusterGrid) { glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); + uint32_t numClustersTouched = 0; + for (auto z = zMin; (z <= zMax); z++) { + for (auto y = yMin; (y <= yMax); y++) { + for (auto x = xMin; (x <= xMax); x++) { + auto index = 1 + x + gridPosToOffset.y * y + gridPosToOffset.z * z; + clusterGrid[index].emplace_back(lightId); + numClustersTouched++; + } + } + } + + return numClustersTouched; +} + +uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, + std::vector< std::vector>& clusterGrid) { + glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); + uint32_t numClustersTouched = 0; const auto& xPlanes = planes[0]; const auto& yPlanes = planes[1]; const auto& zPlanes = planes[2]; - int center_z = (zMax + zMin) >> 1; + int center_z = grid.frustumGrid_eyeDepthToClusterLayer(eyePosRadius.z); int center_y = (yMax + yMin) >> 1; - bool hasBudget = true; - for (auto z = zMin; (z <= zMax) && hasBudget; z++) { + for (auto z = zMin; (z <= zMax); z++) { auto zSphere = eyePosRadius; if (z != center_z) { auto& plane = (z < center_z) ? zPlanes[z + 1] : -zPlanes[z]; - zSphere = projectToPlane(zSphere, plane); + if (!reduceSphereToPlane(zSphere, plane, zSphere)) { + // pass this slice! + continue; + } } - for (auto y = yMin; (y <= yMax) && hasBudget; y++) { + for (auto y = yMin; (y <= yMax); y++) { auto ySphere = zSphere; if (y != center_y) { auto& plane = (y < center_y) ? yPlanes[y + 1] : -yPlanes[y]; - ySphere = projectToPlane(ySphere, plane); + if (!reduceSphereToPlane(ySphere, plane, ySphere)) { + // pass this slice! + continue; + } } + glm::vec3 spherePoint(ySphere); + auto x = xMin; for (; (x < xMax); ++x) { auto& plane = xPlanes[x + 1]; - auto testDistance = glm::dot(plane, glm::vec4(ySphere.x, ySphere.y, ySphere.z, -1.0)) + ySphere.w; - if (testDistance >= 0.0f ) { + auto testDistance = distanceToPlane(spherePoint, plane) + ySphere.w; + if (testDistance >= 0.0f) { break; } } auto xs = xMax; for (; (xs >= x); --xs) { auto& plane = -xPlanes[xs]; - auto testDistance = glm::dot(plane, glm::vec4(ySphere.x, ySphere.y, ySphere.z, -1.0)) + ySphere.w; + auto testDistance = distanceToPlane(spherePoint, plane) + ySphere.w; if (testDistance >= 0.0f) { break; } } - for (; (x <= xs) && hasBudget; x++) { - auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; + for (; (x <= xs); x++) { + auto index = grid.frustumGrid_clusterToIndex(ivec3(x, y, z)); clusterGrid[index].emplace_back(lightId); numClustersTouched++; - if (numClustersTouched >= maxNumIndices) { - hasBudget = false; - } } } } - return hasBudget; + return numClustersTouched; } void LightClusters::updateClusters() { @@ -284,7 +307,18 @@ void LightClusters::updateClusters() { int zMin = theFrustumGrid.frustumGrid_eyeDepthToClusterLayer(eyeZMin); int zMax = theFrustumGrid.frustumGrid_eyeDepthToClusterLayer(eyeZMax); // That should never happen - if (zMin == -1 && zMax == -1) { + if (zMin == -2 && zMax == -2) { + continue; + } + + // Firt slice volume ? + /* if (zMin == -1) { + clusterGrid[0].emplace_back(lightId); + numClusterTouched++; + } */ + + // Stop there with this light if zmax is in near range + if (zMax == -1) { continue; } @@ -361,37 +395,31 @@ void LightClusters::updateClusters() { } // now voxelize - bool hasBudget = scanLightVolume(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), numClusterTouched, maxNumIndices, clusterGrid); - - /* bool hasBudget = true; - for (auto z = zMin; (z <= zMax) && hasBudget; z++) { - for (auto y = yMin; (y <= yMax) && hasBudget; y++) { - for (auto x = xMin; (x <= xMax) && hasBudget; x++) { - auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; - clusterGrid[index].emplace_back(lightId); - numClusterTouched++; - if (numClusterTouched >= maxNumIndices) { - hasBudget = false; - } - } - } - }*/ - - if (!hasBudget) { - break; - } + numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); } // Lights have been gathered now reexpress in terms of 2 sequential buffers - + // Start filling from near to far and stops if it overflows + bool checkBudget = false; + if (numClusterTouched > maxNumIndices) { + checkBudget = true; + } uint16_t indexOffset = 0; for (int i = 0; i < clusterGrid.size(); i++) { auto& cluster = clusterGrid[i]; uint16_t numLights = ((uint16_t)cluster.size()); uint16_t offset = indexOffset; + // Check for overflow + if (checkBudget) { + if (indexOffset + numLights > maxNumIndices) { + break; + } + } + _clusterGrid[i] = (uint32_t)((numLights << 16) | offset); + if (numLights) { memcpy(_clusterContent.data() + indexOffset, cluster.data(), numLights * sizeof(LightIndex)); } diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 88583da31e..02ea436718 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -89,7 +89,7 @@ public: LightStage::LightIndices _visibleLightIndices; gpu::BufferView _lightIndicesBuffer; - uint32_t _numClusters { 0 }; + int32_t _numClusters { 0 }; const uint32_t EMPTY_CLUSTER { 0x0000FFFF }; const LightID INVALID_LIGHT { LightStage::INVALID_INDEX }; @@ -124,9 +124,9 @@ public: float rangeNear{ 1.0f }; float rangeFar{ 512.0f }; - int dimX { 8 }; - int dimY { 8 }; - int dimZ { 12 }; + int dimX { 16 }; + int dimY { 16 }; + int dimZ { 16 }; bool freeze{ false }; diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index 616171b775..5bf6a0bf18 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -58,7 +58,7 @@ void main(void) { float numLightsScale = clamp(numLights * 0.1, 0.0, 1.0); - ivec3 clusterPos = clusterGrid_indexToCluster(gl_InstanceID); + ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID); float boxScale = 0.99; vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3((1.0 - boxScale) * 0.5 + (1.0 - numLightsScale) * boxScale * 0.5) + numLightsScale * boxScale * pos.xyz); diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index e711c6fc64..1820d3113b 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -37,7 +37,7 @@ void main(void) { ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); - ivec2 cluster = clusterGrid_getCluster(clusterGrid_clusterToIndex(clusterPos)); + ivec2 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); int numLights = cluster.x; float numLightsScale = clamp(numLights * 0.1, 0.01, 1.0); diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv index fa082d880f..93fd13b2f5 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv @@ -53,15 +53,7 @@ void main(void) { ); vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - ivec3 dims = frustumGrid.dims.xyz; - - ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); - - int layer = gl_InstanceID / summedDims.x; - int offsetInLayer = gl_InstanceID % summedDims.x; - ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); - - + ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID); vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz); vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0)); diff --git a/libraries/render-utils/src/lightClusters_drawGrid.slv b/libraries/render-utils/src/lightClusters_drawGrid.slv index 0eec0d04ee..15fa8ac38a 100644 --- a/libraries/render-utils/src/lightClusters_drawGrid.slv +++ b/libraries/render-utils/src/lightClusters_drawGrid.slv @@ -57,7 +57,7 @@ void main(void) { ivec2 cluster = clusterGrid_getCluster(gl_InstanceID); int numLights = cluster.x; - ivec3 clusterPos = clusterGrid_indexToCluster(gl_InstanceID); + ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID); float boxScale = 1.0; diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index 2b8beb67c3..eba65c39af 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -61,7 +61,7 @@ void main(void) { ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); - ivec2 cluster = clusterGrid_getCluster(clusterGrid_clusterToIndex(clusterPos)); + ivec2 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); int numLights = cluster.x; if (numLights <= 0) { discard;