CSharpGL带初始数据创建Vertex Buffer Object的情形汇总

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

CSharpGL带初始数据创建Vertex Buffer Object的情形汇总
CSharpGL(38)带初始数据创建Vertex Buffer Object的情形汇总
回到顶部(go to top)
开始
总的来说,OpenGL应用开发者会遇到为如下三种数据创建Vertex Buffer Object的情形:
任意一个struct类型T data;
任意一个元素类型为struct的数组T[] array;
任意一个非托管数组UnmanagedArray<T> array;
而可创建的Vertex Buffer Object也分为如下的类别:
描述顶点属性(位置、颜色、法线等)的VertexBuffer;
描述索引的IndexBuffer;
描述其他自定义内容的各种Buffer;
本文介绍用C#如何实现上述功能。

回到顶部(go to top)
非托管数组->VertexBuffer
最基本的功能是通过非托管数组UnmanagedArrayBase创建一个VBO,我们首先实现这个功能。

复制代码
1 public static VertexBuffer GetVertexBuffer(this UnmanagedArrayBase array, VBOConfig config, string varNameInVertexShader, BufferUsage usage, uint instancedDivisor = 0, int patchVertexes = 0)
2 {
3 uint[] buffers = new uint[1];
4 glGenBuffers(1, buffers);
5 const uint target = OpenGL.GL_ARRAY_BUFFER;
6 glBindBuffer(target, buffers[0]);
7 glBufferData(target, array.ByteLength, array.Header, (uint)usage);
8 glBindBuffer(target, 0);
9
10 var buffer = new VertexBuffer(
11 varNameInVertexShader, buffers[0], config, array.Length, array.ByteLength, instancedDivisor, patchVertexes);
12
13 return buffer;
14 }
复制代码
T[] -> VertexBuffer
很多时候,大家都是在用习惯了的托管数组(int[]、Point[]、vec3[]等)。

那么能不能直接用托管数组创建VBO呢?当然可以。

虽然是托管数组,但是在内存中毕竟也还是连续存放的一块内存。

我们只需找到它的地址就可以了。

找地址这件事通过Marshal.UnsafeAddrOfPinnedArrayElement(); 就可以做到。

复制代码
1 public static VertexBuffer GetVertexBuffer<T>(this T[] array, VBOConfig config, string varNameInVertexShader, BufferUsage usage, uint instancedDivisor = 0, int patchVertexes = 0) where T : struct
2 {
3 GCHandle pinned = GCHandle.Alloc(array, GCHandleType.Pinned);
4 IntPtr header = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0);
5 UnmanagedArrayBase unmanagedArray = new UnmanagedArray<T>(header, array.Length);// It's not neecessary to call Dispose() for this unmanaged array.
6 VertexBuffer buffer = GetVertexBuffer(unmanagedArray, config, varNameInVertexShader, usage, instancedDivisor, patchVertexes);
7 pinned.Free();
8
9 return buffer;
10 }
复制代码
T -> VertexBuffer
那么单独的一个struct变量,如何为之创建VBO?只需用一个var array = new T[1]{ data }; 将其封装起来,就可以用上面的方法了。

复制代码
1 public static VertexBuffer GetVertexBuffer<T>(this T data, VBOConfig config, string varNameInVertexShader, BufferUsage usage, uint instancedDivisor = 0, int patchVertexes = 0) where T : struct
2 {
3 var array = new T[] { data };
4 return GetVertexBuffer(array, config, varNameInVertexShader, usage, instancedDivisor, patchVertexes);
5 // another way to do this:
6 //using (UnmanagedArrayBase unmanagedArray = new UnmanagedArray<T>(1))
7 //{
8 // Marshal.StructureToPtr(data, unmanagedArray.Header, false);
9 // VertexBuffer buffer = GetVertexBufferObject(unmanagedArray, config, varNameInVertexShader, usage, instancedDivisor, patchVertexes);
10 // return buffer;
11 //}
12 }
复制代码
回到顶部(go to top)
非托管数组->IndexBuffer
非托管数组->OneIndexBuffer
从非托管数组到OneIndexBuffer的思路和上面一致。

要注意的是,OneIndexBuffer能接受的元素类型只能是byte、ushort、uint三者之一。

复制代码
1 public static OneIndexBuffer GetOneIndexBuffer(this UnmanagedArray<byte> array, DrawMode mode, BufferUsage usage, int primCount = 1)
2 {
3 return GetOneIndexBuffer(array, mode, usage, IndexElementType.UByte, primCount);
4 }
5
6 public static OneIndexBuffer GetOneIndexBuffer(this UnmanagedArray<ushort> array, DrawMode mode, BufferUsage usage, int primCount = 1)
7 {
8 return GetOneIndexBuffer(array, mode, usage, hort, primCount);
9 }
10
11 public static OneIndexBuffer GetOneIndexBuffer(this UnmanagedArray<uint> array, DrawMode mode, BufferUsage usage, int primCount = 1)
12 {
13 return GetOneIndexBuffer(array, mode, usage, IndexElementType.UInt, primCount);
14 }
15
16 private static OneIndexBuffer GetOneIndexBuffer(this UnmanagedArrayBase array, DrawMode mode, BufferUsage usage, IndexElementType elementType, int primCount = 1)
17 {
18 if (glGenBuffers == null)
19 {
20 InitFunctions();
21 }
22
23 uint[] buffers = new uint[1];
24 glGenBuffers(1, buffers);
25 const uint target = OpenGL.GL_ELEMENT_ARRAY_BUFFER;
26 glBindBuffer(target, buffers[0]);
27 glBufferData(target, array.ByteLength, array.Header, (uint)usage);
28 glBindBuffer(target, 0);
29
30 var buffer = new OneIndexBuffer(buffers[0], mode, elementType, array.Length, array.ByteLength, primCount);
31
32 return buffer;
33 }
复制代码
T[] -> OneIndexBuffer
思路同上。

复制代码
1 public static OneIndexBuffer GetOneIndexBuffer(this byte[] array, DrawMode mode, BufferUsage usage, int primCount = 1)
2 {
3 GCHandle pinned = GCHandle.Alloc(array, GCHandleType.Pinned);
4 IntPtr header = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0);
5 var unmanagedArray = new UnmanagedArray<byte>(header, array.Length);// It's not neecessary to call Dispose() for this unmanaged array.
6 OneIndexBuffer buffer = GetOneIndexBuffer(unmanagedArray, mode, usage, IndexElementType.UByte, primCount);
7 pinned.Free();
8
9 return buffer;
10 }
11
12 public static OneIndexBuffer GetOneIndexBuffer(this ushort[] array, DrawMode mode, BufferUsage usage, int primCount = 1)
13 {
14 GCHandle pinned = GCHandle.Alloc(array, GCHandleType.Pinned);
15 IntPtr header = Marshal.UnsafeAddrOfPinnedArrayElement(array, 0);
16 var unmanagedArray = new UnmanagedArray<ushort>(header, array.Length);// It's not neecessary to call Dispose() for this unmanaged array.
17 OneIndexBuffer buffer = GetOneIndexBuffer(unmanagedArray, mode, usage, hort, primCount);
18 pinned.Free();
19
20 return buffer;
21 }
22
23 public static OneIndexBuffer GetOneIndexBuffer(this uint[] array, DrawMode mode, BufferUsage usage, int primCount = 1)
24 {
25 GCHandle pinned = GCHandle.Alloc(array, GCHandleType.Pinned);
26 IntPtr header = PinnedArrayElement(array, 0);
27 var unmanagedArray = new UnmanagedArray<uint>(header, array.Length);// It's not neecessary to call Dispose() for this unmanaged array.
28 OneIndexBuffer buffer = GetOneIndexBuffer(unmanagedArray, mode, usage, IndexElementType.UInt, primCount);
29 pinned.Free();
30
31 return buffer;
32 }
复制代码
T -> OneIndexBuffer
只有1个元素的索引数组,比较奇葩,不过也是可以实现的。

复制代码
1 public static OneIndexBuffer GetOneIndexBuffer(this byte data, DrawMode mode, BufferUsage usage, int primCount = 1)
2 {
3 var array = new byte[] { data };
4 return GetOneIndexBuffer(array, mode, usage, primCount);
5 }
6
7 public static OneIndexBuffer GetOneIndexBuffer(this ushort data, DrawMode mode, BufferUsage usage, int primCount = 1)
8 {
9 var array = new ushort[] { data };
10 return GetOneIndexBuffer(array, mode, usage, primCount);
11 }
12
13 public static OneIndexBuffer GetOneIndexBuffer(this uint data, DrawMode mode, BufferUsage usage, int primCount = 1)
14 {
15 var array = new uint[] { data };
16 return GetOneIndexBuffer(array, mode, usage, primCount);
17 }
复制代码
ZeroIndexBuffer
这事一个特殊的Buffer,因为实际上在OpenGL的server端并没有真正创建一个Buffer。

但是逻辑上把它也视作一个Buffer是方便合理的。

既然没有真正创建Buffer,那么也就不存在用非托管数组创建ZeroIndexBuffer的情形了。

回到顶部(go to top)
非托管数组->自定义Buffer
自定义Buffer都有哪些
所谓自定义Buffer,是那些用途各异的特殊Buffer,目前CSharpGL包含了:
复制代码
1 AtomicCounterBuffer
2 PixelPackBuffer
3 PixelUnpackBuffer
4 ShaderStorageBuffer
5 TextureBuffer
6 UniformBuffer
复制代码
下面以AtomicCounterBuffer 为例,其他雷同。

非托管数组->自定义Buffer
思路同上。

复制代码
public static AtomicCounterBuffer GetAtomicCounterBuffer(this UnmanagedArrayBase array, BufferUsage usage)
{
return GetIndependentBuffer(array, IndependentBufferTarget.AtomicCounterBuffer, usage) as AtomicCounterBuffer;
private static Buffer GetIndependentBuffer(this UnmanagedArrayBase array, IndependentBufferTarget bufferTarget, BufferUsage usage) {
uint[] buffers = new uint[1];
glGenBuffers(1, buffers);
var target = (uint)bufferTarget;
glBindBuffer(target, buffers[0]);
glBufferData(target, array.ByteLength, array.Header, (uint)usage);
glBindBuffer(target, 0);
Buffer buffer = null;
switch (bufferTarget)
{
case IndependentBufferTarget.AtomicCounterBuffer:
buffer = new AtomicCounterBuffer(buffers[0], array.Length, array.ByteLength);
break;
case IndependentBufferTarget.PixelPackBuffer:
buffer = new PixelPackBuffer(buffers[0], array.Length, array.ByteLength);
break;
case IndependentBufferTarget.PixelUnpackBuffer:
buffer = new PixelUnpackBuffer(buffers[0], array.Length, array.ByteLength);
break;
case IndependentBufferTarget.ShaderStorageBuffer:
buffer = new ShaderStorageBuffer(buffers[0], array.Length, array.ByteLength);
break;
case IndependentBufferTarget.TextureBuffer:
buffer = new TextureBuffer(buffers[0], array.Length, array.ByteLength);
break;
case IndependentBufferTarget.UniformBuffer:
buffer = new UniformBuffer(buffers[0], array.Length, array.ByteLength);
break;
default:
throw new NotImplementedException();
}
return buffer;
}
T[] –> 自定义Buffer
思路同上。

复制代码
1 public static AtomicCounterBuffer GetAtomicCounterBuffer<T>(this T[] array, BufferUsage usage) where T : struct
2 {
3 GCHandle pinned = GCHandle.Alloc(array, GCHandleType.Pinned);
4 IntPtr header = PinnedArrayElement(array, 0);
5 var unmanagedArray = new UnmanagedArray<T>(header, array.Length);// It's not neecessary to call Dispose() for this unmanaged array.
6 AtomicCounterBuffer buffer = GetIndependentBuffer(unmanagedArray, IndependentBufferTarget.AtomicCounterBuffer, usage) as AtomicCounterBuffer;
7 pinned.Free();
8
9 return buffer;
10 }
复制代码
T -> 自定义Buffer
思路同上。

这个方式还是比较常见的一种用法。

1 public static AtomicCounterBuffer GetAtomicCounterBuffer<T>(this T data, BufferUsage usage) where T : struct
2 {
3 var array = new T[] { data };
4 return GetAtomicCounterBuffer(array, usage);
5 }
回到顶部(go to top)
如何使用
实现了上面那些看起来比较啰嗦的功能,现在来看看使用的时候是什么情形。

-> VertexBuffer
最基本的功能是通过数组UnmanagedArrayBase或T[]创建一个VBO,我们首先使用这个功能。

可见只需一行代码即可实现,且调用方式也相同。

复制代码
1 vec3 position = GetPositions();
2 VertexBuffer buffer = position.GetVertexBuffer(VBOConfig.Vec3, varNameInShader, BufferUsage.StaticDraw);
3 //
4 vec3[] positions = GetPositions();
5 VertexBuffer buffer = positions.GetVertexBuffer(VBOConfig.Vec3, varNameInShader, BufferUsage.StaticDraw);
6 //
7 UnmanagedArray<vec3> positions = GetPositions();
8 VertexBuffer buffer = positions.GetVertexBuffer(VBOConfig.Vec3, varNameInShader, BufferUsage.StaticDraw);
-> OneIndexBuffer
同上,不解释。

复制代码
1 uint position = GetIndexes();
2 VertexBuffer buffer = position.GetOneIndexBuffer(DrawMode.Triangles, BufferUsage.StaticDraw);
3 //
4 uint[] positions = GetIndexes();
5 VertexBuffer buffer = positions.GetOneIndexBuffer(DrawMode.Triangles, BufferUsage.StaticDraw);
6 //
7 UnmanagedArray<uint> positions = GetIndexes();
8 VertexBuffer buffer = positions.GetOneIndexBuffer(DrawMode.Triangles, BufferUsage.StaticDraw); 复制代码
-> 自定义Buffer
同上,不解释。

复制代码
1 SomeStruct data = GetIndexes();
2 VertexBuffer buffer = position.GetUniformBuffer(BufferUsage.StaticDraw);
3 //
4 SomeStruct[] data = GetIndexes();
5 VertexBuffer buffer = data.GetUniformBuffer(BufferUsage.StaticDraw);
6 //
7 UnmanagedArray<SomeStruct> data = GetIndexes();
8 VertexBuffer buffer = data.GetUniformBuffer(BufferUsage.StaticDraw);。

相关文档
最新文档