I have a voxel raytracer that is generating some weird shadows and I want to understand what is the source of the problem.

The image is voxelized, resulting in:

I then generate Hard shadows from the voxels creating the following image:

Up to this point everything works as expected. The voxel map is a 3D image with its associated mipmaps, which have been generated correctly (verified using renderdoc).

So the final step is to sample along the ray accumulating occlusion to generate a final shadow, which results in the following:

In that last image, the shadows of the voxels are very much noticeable and look hard for many of the surfaces.

My main hypothesis as to what could be wrong are, I am using GL_NEAREST for sampling rather than GL_LINEAR. And I may beed more samples, but if I need more samples I am not sure how I should disturb the ray to acquire them.

The shader that generated the last 2 images is:

#version 430

#define PI 3.141592653589793

in vec3 f_pos;
in vec3 f_norm;
in vec3 f_uv;

out vec4 fragment_color;

vec3 light = vec3(-500,640,0);

uniform vec3 camera_position;

uniform float cube_dim;
uniform int voxel_resolution;

uniform layout(binding=0) sampler3D diffuse_map;
uniform layout(binding=1) sampler3D normal_map;

uniform layout(binding=2) sampler2DArray text;
layout(std430, binding = 2) buffer texture_meta_data
{
vec2 stretches[];
};

#define EPSILON 0.01
bool incube(vec3 pos, float size)
{
return
(pos.x >= -size - EPSILON) && (pos.x <= size + EPSILON) &&
(pos.y >= -size - EPSILON) && (pos.y <= size + EPSILON) &&
(pos.z >= -size - EPSILON) && (pos.z <= size + EPSILON);
}

vec4 blinn_phong()
{
vec3 pos = f_pos;

vec4 color = vec4(0);
vec3 l = vec3(light-f_pos);
if(length(l)>0)
l = normalize(l);
int image=int(round(f_uv.z));
float x_stretch = stretches[image].x, y_stretch = stretches[image].y;
float u = mod(f_uv.x*x_stretch, x_stretch);
float v = mod(f_uv.y*y_stretch, y_stretch);
vec3 c = vec3(texture(text, vec3(u,v,image)));

vec3 n = normalize(f_norm);
vec3 e = camera_position-f_pos;
e = normalize(e);
vec3 h = normalize(e+l);

color = vec4(c*(vec3(0.5)+0.5*max(0,dot(n,l))) +
vec3(0.1)*max(0,pow(dot(h,n), 100)), 1);

return color;

}

void main()
{
fragment_color = blinn_phong();

float v_size = cube_dim/voxel_resolution;
vec3 r = f_pos + f_norm*v_size*6;
vec3 dir = normalize(light-r);
vec3 start = r+dir*v_size;

float hit = 1.f;
float l=0;
float acc=0;
vec4 val1, val2;
while(incube(r, cube_dim) && (l<=length(start-light)/5.f) && acc<1)
{
l=length(start-r);
r += dir*v_size*0.2;

val1 = textureLod(normal_map, (r)*0.5/cube_dim+vec3(0.5), l*0.01);

acc += val1.a;
}
acc = min(acc, 1);
fragment_color *= (1-acc)*0.8 + 0.2;
}