hi,
i’ve created an OIT renderer. all looks fine so far, it appears correctly onscreen. he problem appears when i zoom into the “cube of cubes”, that means when some vetices are clipped away. then a part of the scene just disappears.
the complete code can be found here:
https://sites.google.com/site/john87connor/indirect-rendering-1/order-independent-transparency
the rendering part:
// render
//----------------------------------------
CheckForGLErrors;
// initialize fragment start index texture (each r32ui texel = 0xFFFFFFFF)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, fragmentstartindexinitializerbuffer);
glTextureSubImage2D(
fragmentstartindextexture,
0, 0, 0, framebuffersize.x, framebuffersize.y,
GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// initialize fragment index buffer
uint atomic_fragment_index = 0;
glNamedBufferSubData(fragmentindexbuffer, 0, sizeof(uint), &atomic_fragment_index);
//glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
// first render pass: collect fragments into buffer
glUseProgram(program_collect_fragments);
glBindVertexArray(vertexarray);
glUniformMatrix4fv(0, 1, false, value_ptr(projection));
glUniform3fv(4, 1, value_ptr(light_intensity));
glUniform3fv(5, 1, value_ptr(light_direction_eyespace));
glUniform1f(6, light_ambient);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectbuffer);
// one draw call, rendering all the draw commands contained in "indirectbuffer"
glMultiDrawElementsIndirect(
GL_TRIANGLES,
GL_UNSIGNED_INT,
nullptr,
instance_count,
sizeof(DrawElementsIndirectCommand));
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
glBindVertexArray(0);
glUseProgram(0);
//glDisable(GL_DEPTH_TEST);
//glDisable(GL_CULL_FACE);
//----------------------------------------
// second render pass:
// render screen rectangle, present collected fragments in correct order
//----------------------------------------
glMemoryBarrier(GL_ALL_BARRIER_BITS);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glUseProgram(program_present_fragments);
glBindVertexArray(vertexarray);
vec4 clear_color = { 0.2f, 0.3f, 0.4f, 0.0f };
glUniform4fv(0, 1, value_ptr(clear_color));
auto screen_rectangle = mesh_references.at(0);
glDrawElementsBaseVertex(
GL_TRIANGLES,
screen_rectangle.IndexCount,
GL_UNSIGNED_INT,
reinterpret_cast<GLvoid*>(sizeof(GLuint) * screen_rectangle.BaseIndex),
screen_rectangle.BaseVertex);
glBindVertexArray(0);
glUseProgram(0);
//----------------------------------------
the shaders:
phase 1: collecting the fragments:
vertexshader
#version 460 core
// camera perspective
layout (location = 0) uniform mat4 projection = mat4(1);
// per-vertex attributes
layout (location = 0) in vec3 in_position;
layout (location = 1) in vec3 in_normal;
layout (location = 2) in vec2 in_texcoord;
// per-instance attributes
layout (location = 3) in mat4 in_mv;
// interface vertex shader --> fragment shader
out VS_FS {
smooth vec3 position;
smooth vec3 normal;
smooth vec2 texcoord;
flat uint drawID;
} vs_out;
void main()
{
// vertex position
gl_Position = projection * in_mv * vec4(in_position, 1);
// position and normal in eye-space
vs_out.position = (in_mv * vec4(in_position, 1)).xyz;
vs_out.normal = (in_mv * vec4(in_normal, 0)).xyz;
// texture coordinate
vs_out.texcoord = in_texcoord;
// draw command index [ 0 ; instancecount )
vs_out.drawID = gl_DrawID;
}
fragment shader:
#version 460 core
#extension GL_ARB_bindless_texture : enable
layout (early_fragment_tests) in;
struct Fragment {
uint NextIndex;
uint Color;
float Depth;
float _pad;
};
// material definition
struct Material {
uint Kd;
uint Ks;
float Ns;
float d;
uint MapKd;
};
// array containing all materials
layout (std430, binding = 1) buffer MaterialBlock {
Material materials[];
};
// array containing material index for current draw command (size = instancecount)
layout (std430, binding = 2) buffer MaterialIndicesBlock {
uint material_indices[];
};
// array containing texture handles
layout (std430, binding = 3) buffer TextureHandleBlock {
uvec2 texture_handles[];
};
// array containing fragments
layout (std430, binding = 4) buffer FragmentBlock {
Fragment fragments[];
};
// fragment index to array of fragments
layout (binding = 1) uniform atomic_uint atomic_fragment_index;
// start index to array of fragments
layout (binding = 1, r32ui) uniform coherent uimage2D fragment_start_indices;
// light parameters
layout (location = 4) uniform vec3 light_intensity = vec3(0, 0, 0);
layout (location = 5) uniform vec3 light_direction = vec3(0, 0, 0);
layout (location = 6) uniform float light_ambient = 0.0f;
// interface vertex shader --> fragment shader
in VS_FS {
smooth vec3 position;
smooth vec3 normal;
smooth vec2 texcoord;
flat uint drawID;
} fs_in;
// fragment color
//layout (location = 0) out vec4 out_color;
vec4 ShadeFragment()
{
// get material index
uint material_index = material_indices[fs_in.drawID];
// get material data
vec3 Kd = unpackUnorm4x8(materials[material_index].Kd).rgb;
vec3 Ks = unpackUnorm4x8(materials[material_index].Ks).rgb;
float Ns = clamp(materials[material_index].Ns, 1, 1000);
float d = clamp(materials[material_index].d, 0, 1);
// get texture data
sampler2D MapKd = sampler2D(texture_handles[ materials[material_index].MapKd ]);
Kd = Kd * texture(MapKd, fs_in.texcoord).rgb;
// directions (eye-space)
vec3 N = normalize(fs_in.normal);
vec3 L = normalize(-light_direction);
vec3 R = reflect(-L, N);
vec3 V = normalize(-fs_in.position);
// light data
vec3 Ia = light_intensity * clamp(light_ambient, 0, 1);
vec3 Id = light_intensity * max(0, dot(N, L));
vec3 Is = light_intensity * max(0, pow(max(0, dot(R, V)), Ns));
// color
vec3 color = (Ia + Id) * Kd + Is * Ks;
return vec4(color, d);
}
void main()
{
// fragment color
vec4 color = ShadeFragment();
// fragment index
uint fragment_index = atomicCounterAdd(atomic_fragment_index, 1);
// create fragment
Fragment fragment;
fragment.NextIndex = imageAtomicExchange(fragment_start_indices, ivec2(gl_FragCoord.xy), fragment_index);
fragment.Color = packUnorm4x8(color);
fragment.Depth = gl_FragCoord.z;
fragment._pad = 0; // unused
// save fragment in fragment buffer
fragments[fragment_index] = fragment;
}
phase 2: sorting and blending the fragments
(screen-wide rectangle is rendered)
vertexshader:
#version 460 core
// per-vertex attributes
layout (location = 0) in vec3 in_position;
void main()
{
// vertex position
gl_Position = vec4(in_position, 1);
}
fragmentshader:
#version 460 core
struct Fragment {
uint NextIndex;
uint Color;
float Depth;
float _pad;
};
#define MAX_FRAGMENTS 30
Fragment local_fragments[MAX_FRAGMENTS];
// array containing fragments
layout (std430, binding = 4) buffer FragmentBlock {
Fragment fragments[];
};
// fragment index to array of fragments
//layout (binding = 1) uniform atomic_uint atomic_fragment_index;
// start index to array of fragments
layout (binding = 1, r32ui) uniform coherent uimage2D fragment_start_indices;
// clear color
layout (location = 0) uniform vec4 clear_color = vec4(0, 0, 0, 0);
// fragment color
layout (location = 0) out vec4 out_color;
uint BuildFragmentArray()
{
uint fragment_count = 0;
uint fragment_index = imageLoad(fragment_start_indices, ivec2(gl_FragCoord.xy)).r;
while (fragment_count < MAX_FRAGMENTS && fragment_index < fragments.length())
{
Fragment fragment = fragments[fragment_index];
local_fragments[fragment_count] = fragment;
fragment_index = fragment.NextIndex;
fragment_count++;
}
return fragment_count;
}
void SortFragmentsByDepth(uint fragment_count)
{
for (uint i = 0; i < fragment_count - 1; i++)
{
for (uint j = i + 1; j < fragment_count; j++)
{
if (local_fragments[i].Depth < local_fragments[j].Depth)
{
Fragment swap = local_fragments[i];
local_fragments[i] = local_fragments[j];
local_fragments[j] = swap;
}
}
}
}
vec4 BlendFragments(uint fragment_count)
{
vec4 destination_color = clear_color;
for (uint i = 0; i < fragment_count; i++)
{
vec4 source_color = unpackUnorm4x8(local_fragments[i].Color);
destination_color = mix(destination_color, source_color, source_color.a);
}
return destination_color;
}
void main()
{
// get local fragments
uint fragment_count = BuildFragmentArray();
if (fragment_count > 0)
{
// sort local fragments
SortFragmentsByDepth(fragment_count);
// calculate color
out_color = BlendFragments(fragment_count);
}
else
// no fragments here, set clear color
out_color = clear_color;
}