Debugging the grid content

This commit is contained in:
samcake 2016-09-12 19:46:18 -07:00
parent 821072bb76
commit efc4406b47
12 changed files with 379 additions and 22 deletions

View file

@ -391,11 +391,14 @@ public:
~StructBuffer<T>() {};
StructBuffer<T>() : gpu::BufferView(makeBuffer()) {}
const T* operator ->() const { return &get<T>(); }
T& edit() {
return BufferView::edit<T>(0);
}
const T& get() const {
return BufferView::get<T>(0);
}
const T* operator ->() const { return &get(); }
};
};

View file

@ -18,6 +18,7 @@ const Element Element::VEC2F_UV{ VEC2, FLOAT, UV };
const Element Element::VEC2F_XY{ VEC2, FLOAT, XY };
const Element Element::VEC3F_XYZ{ VEC3, FLOAT, XYZ };
const Element Element::VEC4F_XYZW{ VEC4, FLOAT, XYZW };
const Element Element::INDEX_UINT16{ SCALAR, UINT16, INDEX };
const Element Element::INDEX_UINT16 { SCALAR, UINT16, INDEX };
const Element Element::INDEX_INT32 { SCALAR, INT32, INDEX };
const Element Element::PART_DRAWCALL{ VEC4, UINT32, PART };

View file

@ -236,6 +236,7 @@ public:
static const Element VEC3F_XYZ;
static const Element VEC4F_XYZW;
static const Element INDEX_UINT16;
static const Element INDEX_INT32;
static const Element PART_DRAWCALL;
protected:

View file

@ -46,4 +46,13 @@ float projection_getFar(mat4 projection) {
// end of hybrid include
uniform clusterGridBuffer {
int _clusterGridTable[10000];
};
uniform clusterContentBuffer {
int _clusterGridContent[10000];
};
<@endif@>

View file

@ -17,11 +17,16 @@ vec3 frustumGrid_gridToVolume(vec3 pos, ivec3 dims) {
}
float frustumGrid_volumeToGridDepth(float vposZ, ivec3 dims) {
return frustumGrid_depthRampInverse(vposZ) * float(dims.z);
}
vec3 frustumGrid_volumeToGrid(vec3 vpos, ivec3 dims) {
vec3 gridPos = vec3(vpos.x, vpos.y, frustumGrid_depthRampInverse(vpos.z)) * vec3(dims);
return gridPos;
}
vec4 frustumGrid_volumeToClip(vec3 vpos, float rangeNear, float rangeFar) {
vec3 ndcPos = vec3(-1.0 + 2.0 * vpos.x, -1.0 + 2.0 * vpos.y, vpos.z);
float depth = rangeNear * (1 - ndcPos.z) + rangeFar * (ndcPos.z);
@ -42,6 +47,10 @@ vec3 frustumGrid_volumeToEye(vec3 vpos, mat4 projection, float rangeNear, float
return frustumGrid_clipToEye(frustumGrid_volumeToClip(vpos, rangeNear, rangeFar), projection);
}
float frustumGrid_eyeToVolumeDepth(float eposZ, float rangeNear, float rangeFar) {
return (-eposZ - rangeNear) / (rangeFar - rangeNear);
}
vec3 frustumGrid_eyeToVolume(vec3 epos, mat4 projection, float rangeNear, float rangeFar) {
vec4 clipPos = vec4(epos.x * projection[0][0] + epos.z * projection[2][0],
@ -57,7 +66,7 @@ vec3 frustumGrid_eyeToVolume(vec3 epos, mat4 projection, float rangeNear, float
int frustumGrid_numClusters() {
return frustumGrid.dims.x * frustumGrid.dims.y * (frustumGrid.dims.z);
return frustumGrid.dims.x * frustumGrid.dims.y * (frustumGrid.dims.z + 1);
}
vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) {
@ -73,6 +82,27 @@ vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) {
}
int frustumGrid_eyeDepthToClusterLayer(float eyeZ) {
if ((eyeZ > -frustumGrid.frustumNear) || (eyeZ < -frustumGrid.frustumFar)) {
return -1;
}
if (eyeZ > -frustumGrid.rangeNear) {
return -1;
}
float volumeZ = frustumGrid_eyeToVolumeDepth(eyeZ, frustumGrid.rangeNear, frustumGrid.rangeFar);
float gridZ = frustumGrid_volumeToGridDepth(volumeZ, frustumGrid.dims);
if (gridZ >= frustumGrid.dims.z) {
gridZ = frustumGrid.dims.z;
}
return int(gridZ);
}
ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) {
if ((eyePos.z > -frustumGrid.frustumNear) || (eyePos.z < -frustumGrid.frustumFar)) {
return ivec3(-1);

View file

@ -21,6 +21,10 @@
//#include "lightClusters_drawClusterFromDepth_vert.h"
#include "lightClusters_drawClusterFromDepth_frag.h"
#include "lightClusters_drawClusterContent_vert.h"
#include "lightClusters_drawClusterContent_frag.h"
enum LightClusterGridShader_MapSlot {
DEFERRED_BUFFER_LINEAR_DEPTH_UNIT = 0,
};
@ -31,14 +35,32 @@ enum LightClusterGridShader_BufferSlot {
CAMERA_CORRECTION_BUFFER_SLOT,
LIGHT_GPU_SLOT = render::ShapePipeline::Slot::LIGHT,
LIGHT_INDEX_GPU_SLOT,
LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT,
LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT,
};
#include "DeferredLightingEffect.h"
LightClusters::LightClusters() :
_lightIndicesBuffer(std::make_shared<gpu::Buffer>()) {
_lightIndicesBuffer(std::make_shared<gpu::Buffer>()),
_clusterGridBuffer(std::make_shared<gpu::Buffer>(), gpu::Element::INDEX_INT32),
_clusterContentBuffer(std::make_shared<gpu::Buffer>(), gpu::Element::INDEX_INT32) {
setDimensions(_frustumGridBuffer->dims, 10000);
}
void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) {
_frustumGridBuffer.edit().dims = gridDims;
_numClusters = _frustumGridBuffer.edit().frustumGrid_numClusters();
_clusterGridBuffer._size = _clusterGridBuffer._buffer->resize(_numClusters * sizeof(uint32_t));
_clusterContentBuffer._size = _clusterContentBuffer._buffer->resize(listBudget * sizeof(uint32_t));
_clusterGrid.resize(_numClusters, EMPTY_CLUSTER);
_clusterContent.resize(listBudget, INVALID_LIGHT);
}
void LightClusters::updateFrustum(const ViewFrustum& frustum) {
_frustum = frustum;
@ -51,23 +73,23 @@ void LightClusters::updateLightStage(const LightStagePointer& lightStage) {
}
void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool points, bool spots) {
// start fresh
_visibleLightIndices.clear();
// Now gather the lights
// gather lights
auto& srcPointLights = lightFrame._pointLights;
auto& srcSpotLights = lightFrame._spotLights;
int numPointLights = (int) srcPointLights.size();
// int offsetPointLights = 0;
int numSpotLights = (int) srcSpotLights.size();
// int offsetSpotLights = numPointLights;
int numPointLights = (int)srcPointLights.size();
// int offsetPointLights = 0;
int numSpotLights = (int)srcSpotLights.size();
// int offsetSpotLights = numPointLights;
_visibleLightIndices.resize(numPointLights + numSpotLights + 1);
_visibleLightIndices[0] = 0;
if (points && !srcPointLights.empty()) {
memcpy(_visibleLightIndices.data() + (_visibleLightIndices[0] + 1), srcPointLights.data(), srcPointLights.size() * sizeof(int));
_visibleLightIndices[0] += (int)srcPointLights.size();
@ -76,11 +98,144 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p
memcpy(_visibleLightIndices.data() + (_visibleLightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int));
_visibleLightIndices[0] += (int)srcSpotLights.size();
}
_lightIndicesBuffer._buffer->setData(_visibleLightIndices.size() * sizeof(int), (const gpu::Byte*) _visibleLightIndices.data());
_lightIndicesBuffer._size = _visibleLightIndices.size() * sizeof(int);
}
void LightClusters::updateClusters() {
// Clean up last info
std::vector< std::vector< uint32_t > > clusterGrid(_numClusters);
_clusterGrid.resize(_numClusters, EMPTY_CLUSTER);
uint32_t maxNumIndices = _clusterContent.size();
_clusterContent.resize(maxNumIndices, INVALID_LIGHT);
auto theFrustumGrid(_frustumGridBuffer.get());
glm::ivec3 gridPosToOffset(1, theFrustumGrid.dims.x, theFrustumGrid.dims.x * theFrustumGrid.dims.y);
uint32_t numClusterTouched = 0;
for (size_t lightNum = 1; lightNum < _visibleLightIndices.size(); ++lightNum) {
auto lightId = _visibleLightIndices[lightNum];
auto light = _lightStage->getLight(lightId);
if (!light)
continue;
auto worldOri = light->getPosition();
auto radius = light->getMaximumRadius();
// Bring into frustum eye space
auto eyeOri = theFrustumGrid.frustumGrid_worldToEye(glm::vec4(worldOri, 1.0f));
// Remove light that slipped through and is not in the z range
float eyeZMax = eyeOri.z - radius;
if (eyeZMax > -theFrustumGrid.rangeNear) {
continue;
}
float eyeZMin = eyeOri.z + radius;
if (eyeZMin < -theFrustumGrid.rangeFar) {
continue;
}
// Get z slices
int zMin = theFrustumGrid.frustumGrid_eyeDepthToClusterLayer(eyeZMin);
int zMax = theFrustumGrid.frustumGrid_eyeDepthToClusterLayer(eyeZMax);
// That should never happen
if (zMin == -1 && zMax == -1) {
continue;
}
//
float eyeOriLen2 = glm::length2(eyeOri);
// CLamp the z range
zMin = std::max(0, zMin);
// find 2D corners of the sphere in grid
int xMin { 0 };
int xMax { theFrustumGrid.dims.x - 1 };
int yMin { 0 };
int yMax { theFrustumGrid.dims.y - 1 };
float radius2 = radius * radius;
auto eyeOriH = eyeOri;
auto eyeOriV = eyeOri;
eyeOriH.y = 0.0f;
eyeOriV.x = 0.0f;
float eyeOriLen2H = glm::length2(eyeOriH);
float eyeOriLen2V = glm::length2(eyeOriV);
if ((eyeOriLen2H > radius2) && (eyeOriLen2V > radius2)) {
float eyeOriLenH = sqrt(eyeOriLen2H);
float eyeOriLenV = sqrt(eyeOriLen2V);
auto eyeOriDirH = glm::vec3(eyeOriH) / eyeOriLenH;
auto eyeOriDirV = glm::vec3(eyeOriV) / eyeOriLenV;
float eyeToTangentCircleLenH = sqrt(eyeOriLen2H - radius2);
float eyeToTangentCircleLenV = sqrt(eyeOriLen2V - radius2);
float eyeToTangentCircleTanH = radius / eyeToTangentCircleLenH;
float eyeToTangentCircleTanV = radius / eyeToTangentCircleLenV;
float eyeToTangentCircleCosH = eyeToTangentCircleLenH / eyeOriLenH;
float eyeToTangentCircleCosV = eyeToTangentCircleLenV / eyeOriLenV;
float eyeToTangentCircleSinH = radius / eyeOriLenH;
float eyeToTangentCircleSinV = radius / eyeOriLenV;
// rotate the eyeToOriDir (H & V) in both directions
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);
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);
}
// 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++;
}
}
}
}
// Lights have been gathered now reexpress in terms of 2 sequential buffers
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;
_clusterGrid[i] = (uint32_t)((numLights << 16) | offset);
if (numLights) {
memcpy(_clusterContent.data() + indexOffset, cluster.data(), numLights * sizeof(uint32_t));
}
indexOffset += numLights;
}
// update the buffers
_clusterGridBuffer._buffer->setData(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data());
_clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(uint32_t), (gpu::Byte*) _clusterContent.data());
}
LightClusteringPass::LightClusteringPass() {
}
@ -122,6 +277,8 @@ void LightClusteringPass::run(const render::SceneContextPointer& sceneContext, c
_lightClusters->updateLightStage(lightStage);
_lightClusters->updateLightFrame(lightStage->_currentFrame, lightingModel->isPointLightEnabled(), lightingModel->isSpotLightEnabled());
_lightClusters->updateClusters();
output = _lightClusters;
}
@ -190,6 +347,35 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterFromDepthPipeline()
return _drawClusterFromDepth;
}
const gpu::PipelinePointer DebugLightClusters::getDrawClusterContentPipeline() {
if (!_drawClusterContent) {
auto vs = gpu::Shader::createVertex(std::string(lightClusters_drawClusterContent_vert));
auto ps = gpu::Shader::createPixel(std::string(lightClusters_drawClusterContent_frag));
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT));
gpu::Shader::makeProgram(*program, slotBindings);
auto state = std::make_shared<gpu::State>();
state->setDepthTest(true, false, gpu::LESS_EQUAL);
// Blend on transparent
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
// Good to go add the brand new pipeline
_drawClusterContent = gpu::Pipeline::create(program, state);
}
return _drawClusterContent;
}
void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs) {
auto deferredTransform = inputs.get0();
auto deferredFramebuffer = inputs.get1();
@ -232,6 +418,17 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr);
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr);
}
if (doDrawContent) {
// bind the one gpu::Pipeline we need
batch.setPipeline(getDrawClusterContentPipeline());
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer);
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer);
auto dims = lightClusters->_frustumGridBuffer->dims;
glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x);
batch.drawInstanced(summedDims.x, gpu::LINES, 24, 0);
}
if (doDrawGrid) {
// bind the one gpu::Pipeline we need

View file

@ -57,12 +57,16 @@ public:
LightClusters();
void setDimensions(glm::uvec3 gridDims, uint32_t listBudget);
void updateFrustum(const ViewFrustum& frustum);
void updateLightStage(const LightStagePointer& lightStage);
void updateLightFrame(const LightStage::Frame& lightFrame, bool points = true, bool spots = true);
void updateClusters();
ViewFrustum _frustum;
LightStagePointer _lightStage;
@ -72,8 +76,17 @@ public:
gpu::StructBuffer<FrustumGrid> _frustumGridBuffer;
LightStage::LightIndices _visibleLightIndices;
gpu::BufferView _lightIndicesBuffer;
uint32_t _numClusters { 0 };
const uint32_t EMPTY_CLUSTER { 0x0000FFFF };
const uint32_t INVALID_LIGHT { 0xFFFFFFFF };
std::vector<uint32_t> _clusterGrid;
std::vector<uint32_t> _clusterContent;
gpu::BufferView _clusterGridBuffer;
gpu::BufferView _clusterContentBuffer;
};
using LightClustersPointer = std::shared_ptr<LightClusters>;
@ -162,10 +175,13 @@ protected:
gpu::BufferPointer _gridBuffer;
gpu::PipelinePointer _drawClusterGrid;
gpu::PipelinePointer _drawClusterFromDepth;
gpu::PipelinePointer _drawClusterContent;
const gpu::PipelinePointer getDrawClusterGridPipeline();
const gpu::PipelinePointer getDrawClusterFromDepthPipeline();
const gpu::PipelinePointer getDrawClusterContentPipeline();
bool doDrawGrid{ false };
bool doDrawClusterFromDepth{ false };
bool doDrawClusterFromDepth { false };
bool doDrawContent { true };
};
#endif

View file

@ -55,6 +55,7 @@ void LightPayload::render(RenderArgs* args) {
// Do we need to allocate the light in the stage ?
if (LightStage::isIndexInvalid(_index)) {
_index = _stage->addLight(_light);
_needUpdate = false;
}
// Need an update ?
if (_needUpdate) {

View file

@ -146,8 +146,12 @@ void LightStage::updateLightArrayBuffer(Index lightId) {
}
// lightArray is big enough so we can remap
auto& light = _lights._elements[lightId];
auto lightSchema = light->getSchemaBuffer().get<model::Light::Schema>();
_lightArrayBuffer->setSubData<model::Light::Schema>(lightId, lightSchema);
auto light = _lights._elements[lightId];
if (light) {
auto lightSchema = light->getSchemaBuffer().get<model::Light::Schema>();
_lightArrayBuffer->setSubData<model::Light::Schema>(lightId, lightSchema);
} else {
// this should not happen ?
}
}

View file

@ -192,7 +192,9 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer));
addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
addJob<DebugSubsurfaceScattering>("DebugScattering", deferredLightingInputs);
const auto debugSubsurfaceScatteringInputs = DebugSubsurfaceScattering::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel,
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying();
addJob<DebugSubsurfaceScattering>("DebugScattering", debugSubsurfaceScatteringInputs);
const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying();
addJob<DebugAmbientOcclusion>("DebugAmbientOcclusion", debugAmbientOcclusionInputs);

View file

@ -0,0 +1,19 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// lightClusters_drawClusterContent.slf
//
// Created by Sam Gateau on 9/8/2016.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
in vec4 varColor;
out vec4 outFragColor;
void main(void) {
outFragColor = varColor;
}

View file

@ -0,0 +1,74 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// lightClusters_drawClusterContent.slv
// Vertex shader
//
// Created by Sam Gateau on 9/8/2016
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include LightClusterGrid.slh@>
<@include gpu/Color.slh@>
<$declareColorWheel()$>
out vec4 varColor;
void main(void) {
const vec4 UNIT_BOX[8] = vec4[8](
vec4(0.0, 0.0, 0.0, 1.0),
vec4(1.0, 0.0, 0.0, 1.0),
vec4(0.0, 1.0, 0.0, 1.0),
vec4(1.0, 1.0, 0.0, 1.0),
vec4(0.0, 0.0, 1.0, 1.0),
vec4(1.0, 0.0, 1.0, 1.0),
vec4(0.0, 1.0, 1.0, 1.0),
vec4(1.0, 1.0, 1.0, 1.0)
);
const int UNIT_BOX_LINE_INDICES[24] = int[24](
0, 1,
1, 3,
3, 2,
2, 0,
4, 5,
5, 7,
7, 6,
6, 4,
2, 6,
3, 7,
0, 4,
1, 5
);
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);
vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz);
vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0));
// standard transform
TransformCamera cam = getTransformCamera();
<$transformWorldToClipPos(cam, worldPos, gl_Position)$>
varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), 0.9);
}