diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 4ce469deba..da4931a91e 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -123,6 +123,38 @@ ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { return ivec3(gridPos); } +int frustumGrid_eyeToClusterDirH(vec3 eyeDir) { + if (eyeDir.z >= 0.0) { + return (eyeDir.x > 0 ? frustumGrid.dims.x : -1); + } + + float eyeDepth = -eyeDir.z; + float nclipDir = eyeDir.x / eyeDepth; + float ndcDir = nclipDir * frustumGrid.eyeToGridProj[0][0] - frustumGrid.eyeToGridProj[2][0]; + float volumeDir = 0.5 * (ndcDir + 1.0); + float gridPos = volumeDir * float(frustumGrid.dims.x); + + return int(gridPos); +} + +int frustumGrid_eyeToClusterDirV(vec3 eyeDir) { + if (eyeDir.z >= 0.0) { + return (eyeDir.y > 0 ? frustumGrid.dims.y : -1); + } + + float eyeDepth = -eyeDir.z; + float nclipDir = eyeDir.y / eyeDepth; + float ndcDir = nclipDir * frustumGrid.eyeToGridProj[1][1] - frustumGrid.eyeToGridProj[2][1]; + float volumeDir = 0.5 * (ndcDir + 1.0); + float gridPos = volumeDir * float(frustumGrid.dims.y); + + return int(gridPos); +} + +ivec2 frustumGrid_eyeToClusterDir(vec3 eyeDir) { + return ivec2(frustumGrid_eyeToClusterDirH(eyeDir), frustumGrid_eyeToClusterDirV(eyeDir)); +} + vec4 frustumGrid_eyeToWorld(vec4 eyePos) { return frustumGrid.eyeToWorldMat * eyePos; } diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index ef584ae104..707e82ae2f 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -124,6 +124,27 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p _lightIndicesBuffer._size = _visibleLightIndices.size() * sizeof(int); } +bool scanLightVolume(FrustumGrid& grid, int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, + uint32_t& numClustersTouched, int maxNumIndices, std::vector< std::vector>& clusterGrid) { + glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); + + 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); + numClustersTouched++; + if (numClustersTouched >= maxNumIndices) { + hasBudget = false; + } + } + } + } + + return hasBudget; +} + void LightClusters::updateClusters() { // Clean up last info std::vector< std::vector< LightID > > clusterGrid(_numClusters); @@ -167,7 +188,8 @@ void LightClusters::updateClusters() { continue; } - + // is it a light whose origin is behind the near ? + bool behindLight = (eyeOri.z >= -theFrustumGrid.rangeNear); // float eyeOriLen2 = glm::length2(eyeOri); @@ -199,8 +221,6 @@ void LightClusters::updateClusters() { float eyeToTangentCircleLenH = sqrt(eyeOriLen2H - radius2); - float eyeToTangentCircleTanH = radius / eyeToTangentCircleLenH; - float eyeToTangentCircleCosH = eyeToTangentCircleLenH / eyeOriLenH; float eyeToTangentCircleSinH = radius / eyeOriLenH; @@ -210,15 +230,11 @@ void LightClusters::updateClusters() { glm::vec3 leftDir(eyeOriDirH.x * eyeToTangentCircleCosH + eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * -eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); glm::vec3 rightDir(eyeOriDirH.x * eyeToTangentCircleCosH - eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); + auto lc = theFrustumGrid.frustumGrid_eyeToClusterDirH(leftDir); + auto rc = theFrustumGrid.frustumGrid_eyeToClusterDirH(rightDir); - glm::vec3 leftPosAtNear = leftDir * theFrustumGrid.rangeNear * 2.0f; - glm::vec3 rightPosAtNear = rightDir * theFrustumGrid.rangeNear * 2.0f; - - auto lc = theFrustumGrid.frustumGrid_eyeToClusterPos(leftPosAtNear); - auto rc = theFrustumGrid.frustumGrid_eyeToClusterPos(rightPosAtNear); - - xMin = std::max(0, lc.x); - xMax = std::max(0, std::min(rc.x, xMax)); + xMin = std::max(xMin, lc); + xMax = std::max(0, std::min(rc, xMax)); } if ((eyeOriLen2V > radius2)) { @@ -226,12 +242,8 @@ void LightClusters::updateClusters() { auto eyeOriDirV = glm::vec3(eyeOriV) / eyeOriLenV; - - float eyeToTangentCircleLenV = sqrt(eyeOriLen2V - radius2); - float eyeToTangentCircleTanV = radius / eyeToTangentCircleLenV; - float eyeToTangentCircleCosV = eyeToTangentCircleLenV / eyeOriLenV; float eyeToTangentCircleSinV = radius / eyeOriLenV; @@ -241,29 +253,17 @@ void LightClusters::updateClusters() { glm::vec3 bottomDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV + eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * -eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); glm::vec3 topDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV - eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); + auto bc = theFrustumGrid.frustumGrid_eyeToClusterDirV(bottomDir); + auto tc = theFrustumGrid.frustumGrid_eyeToClusterDirV(topDir); - glm::vec3 bottomPosAtNear = bottomDir * theFrustumGrid.rangeNear * 2.0f; - glm::vec3 topPosAtNear = topDir * theFrustumGrid.rangeNear * 2.0f; - - auto bc = theFrustumGrid.frustumGrid_eyeToClusterPos(bottomPosAtNear); - auto tc = theFrustumGrid.frustumGrid_eyeToClusterPos(topPosAtNear); - - yMin = std::max(0, bc.y); - yMax = std::max(0, std::min(tc.y, yMax)); + yMin = std::max(yMin, bc); + yMax = std::max(yMin, std::min(tc, yMax)); } // now voxelize - for (auto z = zMin; z <= zMax; z++) { - for (auto y = yMin; y <= yMax; y++) { - for (auto x = xMin; x <= xMax; x++) { - auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; - clusterGrid[index].emplace_back(lightId); - numClusterTouched++; - } - } - } + bool hasBudget = scanLightVolume(theFrustumGrid, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), numClusterTouched, maxNumIndices, clusterGrid); - if (numClusterTouched >= maxNumIndices) { + if (!hasBudget) { break; } } @@ -486,6 +486,7 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co } if (doDrawContent) { + // bind the one gpu::Pipeline we need batch.setPipeline(getDrawClusterContentPipeline()); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 5d64b17ca1..e5d0275d85 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -74,7 +74,7 @@ public: LightStagePointer _lightStage; - + gpu::StructBuffer _frustumGridBuffer; diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index af3cf3e3ac..d146d8b691 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -1,4 +1,4 @@ -<@include gpu/Config.slh@> +<@include gpu / Config.slh@> <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // @@ -12,17 +12,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include gpu/Transform.slh@> +<@include gpu / Transform.slh@> <$declareStandardTransform()$> <@include LightClusterGrid.slh@> -<@include gpu/Color.slh@> +<@include gpu / Color.slh@> <$declareColorWheel()$> - - out vec4 varColor; diff --git a/libraries/render-utils/src/lightClusters_drawGrid.slv b/libraries/render-utils/src/lightClusters_drawGrid.slv index 9eb80cb28e..0eec0d04ee 100644 --- a/libraries/render-utils/src/lightClusters_drawGrid.slv +++ b/libraries/render-utils/src/lightClusters_drawGrid.slv @@ -53,16 +53,15 @@ 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); + ivec2 cluster = clusterGrid_getCluster(gl_InstanceID); + int numLights = cluster.x; - int layer = gl_InstanceID / summedDims.x; - int offsetInLayer = gl_InstanceID % summedDims.x; - ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); + ivec3 clusterPos = clusterGrid_indexToCluster(gl_InstanceID); - vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz); + float boxScale = 1.0; + vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(1.0 - boxScale) * 0.5 + boxScale * pos.xyz); vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0)); @@ -70,5 +69,5 @@ void main(void) { TransformCamera cam = getTransformCamera(); <$transformWorldToClipPos(cam, worldPos, gl_Position)$> - varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), 0.9); + varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), (numLights > 0 ? 0.9 : 0.0)); } \ No newline at end of file