I've been having a lot of strange problem's while trying to write a raytracer in an opengl shader. I try to determine if the source of the error is myself, and often this is the case, but I've come to the conclusion that some of these problems may just be bugs in my graphics driver (I'm on ATI). In these cases, I've just implemented workarounds.
But I just ran into something I'm not sure how to work around (At least without really weird code), the fact that I can't switch over some of my data from uniform arrays to texture buffers, because the moment I delete the references to the uniform array (which doesn't do anything anymore; I've removed any actual usage of the data), my shader goes from looking like this:
to this:
And note that moving the camera causes what you see to change erratically as well.
Here is the method I'm changing to get these results: (the lines in question are commented out, they access the uniform array quad_vertex_indices)
bool Collide_KDTree(Ray ray, out Surface surface)
{
float t_entry, t_exit;
if(!RayBox(ray.tail, ray.head, scene_bounds.position, scene_bounds.extent, t_entry, t_exit))
return false;
uint node_indices[TREE_DEPTH];
float node_exits[TREE_DEPTH];
uint top= 0;
node_indices[top]= kd_nodes.length()- 1;
node_exits[top++]= t_exit;
while(top> 0)
{
uint node_index_foo= node_indices[top- 1];
KDNode node= kd_nodes[node_indices[top- 1]];
t_exit= node_exits[top- 1];
top--;
if(node.node_type== NodeType_Parent)
{
uint near_index, far_index;
if(ray.tail[node.split_axis] < node.split)
{
near_index= node.left_index_or_offset+ 1;
far_index= node.right_index_or_count+ 1;
}
else
{
near_index= node.right_index_or_count+ 1;
far_index= node.left_index_or_offset+ 1;
}
float t_intersection;
RayAxisAlignedPlane(ray.tail, ray.head, node.split_axis, node.split, t_intersection);
if(t_intersection> t_exit)
{
node_indices[top]= near_index;
node_exits[top++]= t_exit;
}
else if(t_intersection< t_entry)
{
if(t_intersection< 0)
{
node_indices[top]= near_index;
node_exits[top++]= t_exit;
}
else
{
node_indices[top]= far_index;
node_exits[top++]= t_exit;
}
}
else if(t_intersection> t_entry && t_intersection< t_exit)
{
if(t_intersection< 0)
{
node_indices[top]= near_index;
node_exits[top++]= t_exit;
}
else
{
node_indices[top]= far_index;
node_exits[top++]= t_exit;
node_indices[top]= near_index;
node_exits[top++]= t_intersection;
}
}
}
else
{
float shortest_distance= INFINITY;
bool collision_detected= false;
uint primitive_offset= node.left_index_or_offset;
uint primitive_count= node.right_index_or_count;
for(uint i= primitive_offset; i< (primitive_offset+ primitive_count); i++)
{
uint primitive_index= primitive_indices[i];
if(primitive_index< QUAD_COUNT)
{
uint quad_index= primitive_index;
vec3 intersection;
//uint foo0= quad_vertex_indices[quad_index* 4+ 0];
//uint foo1= quad_vertex_indices[quad_index* 4+ 1];
//uint foo2= quad_vertex_indices[quad_index* 4+ 2];
//uint foo3= quad_vertex_indices[quad_index* 4+ 3];
vec3 vertex0= vertices[texelFetch(test_texture_buffer, int(quad_index* 4+ 0)).r];
vec3 vertex1= vertices[texelFetch(test_texture_buffer, int(quad_index* 4+ 1)).r];
vec3 vertex2= vertices[texelFetch(test_texture_buffer, int(quad_index* 4+ 2)).r];
vec3 vertex3= vertices[texelFetch(test_texture_buffer, int(quad_index* 4+ 3)).r];
if(RayQuad(ray.tail, ray.head, vertex0, vertex1, vertex2, vertex3, quad_normals[quad_index], intersection))
{
float this_distance= distance(ray.tail, intersection);
if(this_distance< shortest_distance)
{
surface.position= intersection;
surface.normal= quad_normals[quad_index];
surface.material= materials[quad_material_indices[quad_index]];
shortest_distance= this_distance;
collision_detected= true;
}
}
}
else
{
uint sphere_index= primitive_index- QUAD_COUNT;
vec3 intersection;
if(RaySphere(ray.tail, ray.head, spheres[sphere_index].position, spheres[sphere_index].radius, intersection))
{
float this_distance= distance(ray.tail, intersection);
if(this_distance< shortest_distance)
{
surface.position= intersection;
surface.normal= normalize(intersection- spheres[sphere_index].position);
surface.material= materials[sphere_material_indices[sphere_index]];
shortest_distance= this_distance;
collision_detected= true;
}
}
}
}
if(collision_detected && (shortest_distance/ length(ray.head))< t_exit)
return true;
t_entry= t_exit;
}
}
return false;
}
It seems to the me that this is simply a compiler issue, but if it isn't, that's great, because it means I can fix it.
Does anyone know what could be causing this, what my options are? I'm under time constraints so I'm considering just doing a hack to get this to work (i.e. just leave the lines in, or something similar)