+BIT祝威+悄悄在此留下版了个权的信息说:

CSharpGL(22)实现顺序无关的半透明渲染(Order-Independent-Transparency)

在 GL.Enable(GL_BLEND); 后渲染半透明物体时,由于顶点被渲染的顺序固定,渲染出来的结果往往很奇怪。红宝书里提到一个OIT(Order-Independent-Transparency)的渲染方法,很好的解决了这个问题。这个功能太有用了。于是我把这个方法加入CSharpGL中。

+BIT祝威+悄悄在此留下版了个权的信息说:

如下图所示,左边是常见的blend方法,右边是OIT渲染的结果。可以看到左边的渲染结果有些诡异,右边的就正常了。

CSharpGL(22)实现顺序无关的半透明渲染(Order-Independent-Transparency)

网络允许的话可以看一下视频,更直观。

或者也可以看红宝书里的例子:左边是常见的blend方法,右边是OIT渲染的结果。

CSharpGL(22)实现顺序无关的半透明渲染(Order-Independent-Transparency)

 

+BIT祝威+悄悄在此留下版了个权的信息说:

下载

CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入(https://github.com/bitzhuwei/CSharpGL

 

+BIT祝威+悄悄在此留下版了个权的信息说:

实现原理

+BIT祝威+悄悄在此留下版了个权的信息说:

源头

为什么通常的blend方式会有问题?因为blend的结果是与source、dest两个颜色的出现顺序相关的。就是说blend(blend(ColorA, ColorB), ColorC)≠blend(ColorA,blend(ColorB, ColorC))。

那么很显然的一个想法是,分两遍渲染,第一遍:把这个位置上的所有Color都存到一个链表里,第二遍:根据每个Color的深度值进行排序,然后进行blend操作。这就解决了blend顺序的问题。

+BIT祝威+悄悄在此留下版了个权的信息说:

W*H个链表

显然,为了对宽度、高度分别为Width、Height的窗口实施OIT渲染,必须为此窗口上的每个像素分别设置一个链表,用于存储投影到此像素上的各个Color。这就是W*H个链表的由来。

当然了,这个链表要由GLSL shader来操作 。shader本身似乎没有操作链表的功能。那么就用一个大大的VBO来代替。这个VBO存储了所有的W*H个链表。

CSharpGL(22)实现顺序无关的半透明渲染(Order-Independent-Transparency)

你可以想象,在第一遍渲染时,这个VBO的第二个位置上可能是第一个像素的第二个Color,也可能是第二个像素的第一个Color。这就意味着我们还需要一个数组来存放W*H个链表的头结点。这个数组我们用一个2DTexture实现,其大小正好等于Width*Height就可以了。

这个Texture不像一般的Texture那样用于给模型贴图,而是用作记录头结点的信息。★

+BIT祝威+悄悄在此留下版了个权的信息说:

初始化

初始化工作主要包含这几项:创建和清空头结点Texture、链表VBO。

 1         protected override void DoInitialize()
 2         {
 3             // Create head pointer texture
 4             GL.GetDelegateFor<GL.glActiveTexture>()(GL.GL_TEXTURE0);
 5             GL.GenTextures(1, head_pointer_texture);
 6             GL.BindTexture(GL.GL_TEXTURE_2D, head_pointer_texture[0]);
 7             GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, (int)GL.GL_NEAREST);
 8             GL.TexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, (int)GL.GL_NEAREST);
 9             GL.TexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_R32UI, MAX_FRAMEBUFFER_WIDTH, MAX_FRAMEBUFFER_HEIGHT, 0, GL.GL_RED_INTEGER, GL.GL_UNSIGNED_INT, IntPtr.Zero);
10             GL.BindTexture(GL.GL_TEXTURE_2D, 0);
11 
12             GL.GetDelegateFor<GL.glBindImageTexture>()(0, head_pointer_texture[0], 0, true, 0, GL.GL_READ_WRITE, GL.GL_R32UI);
13 
14             // Create buffer for clearing the head pointer texture
15             GL.GetDelegateFor<GL.glGenBuffers>()(1, head_pointer_clear_buffer);
16             GL.BindBuffer(BufferTarget.PixelUnpackBuffer, head_pointer_clear_buffer[0]);
17             GL.GetDelegateFor<GL.glBufferData>()(GL.GL_PIXEL_UNPACK_BUFFER, MAX_FRAMEBUFFER_WIDTH * MAX_FRAMEBUFFER_HEIGHT * sizeof(uint), IntPtr.Zero, GL.GL_STATIC_DRAW);
18             IntPtr data = GL.MapBuffer(BufferTarget.PixelUnpackBuffer, MapBufferAccess.WriteOnly);
19             unsafe
20             {
21                 var array = (uint*)data.ToPointer();
22                 for (int i = 0; i < MAX_FRAMEBUFFER_WIDTH * MAX_FRAMEBUFFER_HEIGHT; i++)
23                 {
24                     array[i] = 0;
25                 }
26             }
27             GL.UnmapBuffer(BufferTarget.PixelUnpackBuffer);
28             GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
29 
30             // Create the atomic counter buffer
31             GL.GetDelegateFor<GL.glGenBuffers>()(1, atomic_counter_buffer);
32             GL.BindBuffer(BufferTarget.AtomicCounterBuffer, atomic_counter_buffer[0]);
33             GL.GetDelegateFor<GL.glBufferData>()(GL.GL_ATOMIC_COUNTER_BUFFER, sizeof(uint), IntPtr.Zero, GL.GL_DYNAMIC_COPY);
34             GL.BindBuffer(BufferTarget.AtomicCounterBuffer, 0);
35 
36             // Create the linked list storage buffer
37             GL.GetDelegateFor<GL.glGenBuffers>()(1, linked_list_buffer);
38             GL.BindBuffer(BufferTarget.TextureBuffer, linked_list_buffer[0]);
39             GL.GetDelegateFor<GL.glBufferData>()(GL.GL_TEXTURE_BUFFER, MAX_FRAMEBUFFER_WIDTH * MAX_FRAMEBUFFER_HEIGHT * 3 * Marshal.SizeOf(typeof(vec4)), IntPtr.Zero, GL.GL_DYNAMIC_COPY);
40             GL.BindBuffer(BufferTarget.TextureBuffer, 0);
41 
42             // Bind it to a texture (for use as a TBO)
43             GL.GenTextures(1, linked_list_texture);
44             GL.BindTexture(GL.GL_TEXTURE_BUFFER, linked_list_texture[0]);
45             GL.GetDelegateFor<GL.glTexBuffer>()(GL.GL_TEXTURE_BUFFER, GL.GL_RGBA32UI, linked_list_buffer[0]);
46             GL.BindTexture(GL.GL_TEXTURE_BUFFER, 0);
47 
48             GL.GetDelegateFor<GL.glBindImageTexture>()(1, linked_list_texture[0], 0, false, 0, GL.GL_WRITE_ONLY, GL.GL_RGBA32UI);
49 
50             GL.ClearDepth(1.0f);
51         }
DoInitialize

相关文章:

  • 2021-11-20
  • 2021-10-27
  • 2021-04-12
  • 2021-08-31
  • 2022-12-23
  • 2021-07-22
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-06-21
  • 2021-11-06
  • 2022-12-23
  • 2021-10-30
  • 2021-08-22
  • 2021-11-09
  • 2022-12-23
相关资源
相似解决方案