Looking at Crassin's video of the animated hand in the Sponza scene, I see that he was able to move this hand without any of the artifacts present in my engine. Even if I turn up my voxelization to 256x256x256 (which for my small scene, it would be a much higher resolution than the 512x512x512 that Crassin uses in the large Sponza scene), I still get the flickering artifacts in parts of my models when different voxels are being interchanged due to the change in location of each poly. This is most apparent with the Buddha model, where flickering between light and dark occurs most at the hands.
I found a clue on this site of how to possibly solve this problem: http://realtimevoxels.blogspot.com.au/
The author mentions a similar problem when he tries to implement a cascaded view-centred voxel approach, as an alternative to octrees. His solution is:
"Any slight movement of the camera causes different fragments to be rendered, which causes different voxels to be created. We can fix this by clamping the axis-aligned orthographic projections to world-space voxel-sized increments."
Here is how I apply my orthographic projections in the geometry shader:
#version 430
layout(triangles) in;
layout(triangle_strip, max_vertices=3) out;
in VSOutput
{
vec4 ndcPos;
vec4 fNorm;
vec2 fTexCoord;
vec4 worldPos;
vec4 shadowCoord;
} vsout[];
out GSOutput
{
vec4 ndcPos;
vec4 fNorm;
vec2 fTexCoord;
vec4 worldPos;
vec4 shadowCoord;
mat4 oProj;
} gsout;
uniform mat4 voxSpace;
void main()
{
gsout.oProj = mat4(0);
vec4 n = normalize(vsout[0].fNorm);
for(int i = 0; i<gl_in.length(); i++)
{
gsout.fNorm = n;
float maxC = max(abs(n.x), max(abs(n.y), abs(n.z)));
float x,y,z;
x = abs(n.x) < maxC ? 0 : 1;
y = abs(n.y) < maxC ? 0 : 1;
z = abs(n.z) < maxC ? 0 : 1;
vec4 axis = vec4(x,y,z,1);
if(axis == vec4(1,0,0,1))
{
gsout.oProj[0] = vec4(0,0,-1,0);
gsout.oProj[1] = vec4(0,-1,0,0);
gsout.oProj[2] = vec4(-1,0,0,0);
gsout.oProj[3] = vec4(0,0,0,1);
}
else if(axis == vec4(0,1,0,1))
{
gsout.oProj[0] = vec4(1,0,0,0);
gsout.oProj[1] = vec4(0,0,1,0);
gsout.oProj[2] = vec4(0,-1,0,0);
gsout.oProj[3] = vec4(0,0,0,1);
}
else if(axis == vec4(0,0,1,1))
{
gsout.oProj[0] = vec4(1,0,0,0);
gsout.oProj[1] = vec4(0,-1,0,0);
gsout.oProj[2] = vec4(0,0,-1,0);
gsout.oProj[3] = vec4(0,0,0,1);
}
gl_Position = gsout.oProj*voxSpace*gl_in.gl_Position;
gsout.ndcPos = gsout.oProj*voxSpace*vsout.ndcPos;
gsout.fTexCoord = vsout.fTexCoord;
gsout.worldPos = vsout.worldPos;
gsout.shadowCoord = vsout.shadowCoord;
EmitVertex();
}
}
Where vsout.ndcPos is worldSpace*vPos from the vertex shader and the "voxSpace" world to voxel space transformation is obtained from:
sceneBounds[0] = glm::vec3(-2.5f, -0.005f, -3);
sceneBounds[1] = glm::vec3(2.5f, 2, 2);
glm::vec3 sceneScale = 1.0f/(sceneBounds[1] - sceneBounds[0]);
voxScale = min(sceneScale.x, min(sceneScale.y, sceneScale.z));
voxOff = -sceneBounds[0];
models->voxSpace = glm::translate(glm::mat4(1.0f), glm::vec3(-1.0f, -1.0f, -1.0f))*glm::scale(glm::mat4(1.0f), glm::vec3(2.0f))*glm::scale(glm::mat4(1.0f), glm::vec3(voxScale))*glm::translate(glm::mat4(1.0f), voxOff);
So I've done the transformation of gsout.oProj*voxSpace*vsout.ndcPos, so can anyone elaborate on what "clamping to world-space voxel-sized increments" actually means?