MOre refinements?

This commit is contained in:
samcake 2016-09-27 18:38:15 -07:00
parent 9b94a025fc
commit a0862820e6
9 changed files with 116 additions and 86 deletions

View file

@ -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);

View file

@ -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) {

View file

@ -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<LightClusters::LightIndex>>& 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<LightClusters::LightIndex>>& 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<LightClusters::LightIndex>>& 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));
}

View file

@ -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 };

View file

@ -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);

View file

@ -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);

View file

@ -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));

View file

@ -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;

View file

@ -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;