CSharpGL(37)创建和使用VBO的最佳方式
CSharpGL(37)创建和使用VBO的最佳方式
开始
近日在OpenGL红宝书上看到这样的讲解。
其核心意思是,在创建VBO时用
- glBufferData(GL_ARRAY_BUFFER, length, NULL, GL_STATIC_DRAW);
来初始化buffer占用的内存(此内存在GPU端),其中的 NULL 表示并未初始化数据(即此buffer中的数据是随机值,类似在C语言中刚刚创建一个数组 int x[]; 的情况)。
这样,就不必在CPU端申请大量内存了。接下来需要初始化buffer数据时,用
- IntPtr pointer = buffer.MapBuffer(MapBufferAccess.WriteOnly);
- var array = (vec3*)pointer.ToPointer();
- for (int i = ; i < length; i++)
- {
- array[i] = this.model.positions[i];
- }
- ptr.UnmapBuffer();
来直接操作GPU上的数据即可。
使用这种方式,省去了在CPU端创建大规模非托管数组并上传到GPU端的步骤,直接在GPU端创建了buffer,且所需代码更少,可以说是目前我找到的最佳方式。
因此我在CSharpGL中集成并使用了这种方式。
顶点属性buffer
CSharpGL中,用于描述顶点属性数组(Vertex Buffer Object)的类型是 VertexAttributeBufferPtr 。以前,我们可以通过如下的方式创建 VertexAttributeBufferPtr 。
- // 先在CPU端创建非托管数组VertexAttributeBuffer<vec3>对象
- using (var buffer = new VertexAttributeBuffer<vec3>(
- varNameInShader, VertexAttributeConfig.Vec3, BufferUsage.StaticDraw))
- {
- buffer.Alloc(this.model.positions.Length);// 在CPU端申请内存
- unsafe// 使用指针快速初始化
- {
- var array = (vec3*)buffer.Header.ToPointer();
- for (int i = ; i < this.model.positions.Length; i++)
- {
- array[i] = this.model.positions[i];
- }
- }
- // 将CPU端的VertexAttributeBuffer<vec3>上传到GPU,获得我们需要的buffer对象。
- positionBufferPtr = buffer.GetBufferPtr();
- }// using结束,释放VertexAttributeBuffer<vec3>申请的非托管内存。
- return positionBufferPtr;
可见,这种方式实际上是按下面的步骤创建VBO的。注意其中的data不是 NULL 。
- uint[] buffers = new uint[];
- glGenBuffers(, buffers);
- const uint target = OpenGL.GL_ARRAY_BUFFER;
- glBindBuffer(target, buffers[]);
- glBufferData(target, length, data, usage);
- glBindBuffer(target, );
这种方式需要先在CPU端申请一块内存,初始化数据,之后才能上传到GPU端。现在我们用新的方式创建buffer,就不需要在CPU端申请内存了。
下面是创建buffer的方法。
- /// <summary>
- /// Creates a <see cref="VertexAttributeBufferPtr"/> object(actually an array) directly in server side(GPU) without initializing its value.
- /// </summary>
- /// <param name="elementType">element's type of this 'array'.</param>
- /// <param name="length">How many elements are there?</param>
- /// <param name="config">mapping to vertex shader's 'in' type.</param>
- /// <param name="usage"></param>
- /// <param name="varNameInVertexShader">mapping to vertex shader's 'in' name.</param>
- /// <param name="instanceDivisor"></param>
- /// <param name="patchVertexes"></param>
- /// <returns></returns>
- public static VertexAttributeBufferPtr Create(Type elementType, int length, VertexAttributeConfig config, BufferUsage usage, string varNameInVertexShader, uint instanceDivisor = , int patchVertexes = )
- {
- if (!elementType.IsValueType) { throw new ArgumentException(string.Format("{0} must be a value type!", elementType)); }
- int byteLength = Marshal.SizeOf(elementType) * length;
- uint[] buffers = new uint[];
- glGenBuffers(, buffers);
- const uint target = OpenGL.GL_ARRAY_BUFFER;
- glBindBuffer(target, buffers[]);
- glBufferData(target, byteLength, IntPtr.Zero, (uint)usage);
- glBindBuffer(target, );
- var bufferPtr = new VertexAttributeBufferPtr(
- varNameInVertexShader, buffers[], config, length, byteLength, instanceDivisor, patchVertexes);
- return bufferPtr;
- }
使用这样的方式创建了buffer,之后在初始化数据时,就得用glMapBuffer/glUnmapBuffer了。
- int length = this.model.positions.Length;
- // 创建buffer
- VertexAttributeBufferPtr buffer = VertexAttributeBufferPtr.Create(typeof(vec3), length, VertexAttributeConfig.Vec3, BufferUsage.StaticDraw, varNameInShader);
- unsafe
- {
- IntPtr pointer = buffer.MapBuffer(MapBufferAccess.WriteOnly);// 获取指针
- var array = (vec3*)pointer.ToPointer();// 强制类型转换
- // 初始化数据
- for (int i = ; i < length; i++)
- {
- array[i] = this.model.positions[i];
- }
- buffer.UnmapBuffer();// 完成,上传到GPU端。
- }
对比来看,在内存上,新的方式省略了在CPU端申请非托管数组的开销;在代码上,新的方式也省去了对 VertexAttributeBuffer<vec3> 对象的使用( VertexAttributeBuffer<vec3> 类型完全可以不用了)。
索引buffer
OneIndexBufferPtr
对于使用 glDrawElements() 的索引对象,创建索引buffer就与上面雷同了。
- /// <summary>
- /// Creates a <see cref="OneIndexBufferPtr"/> object directly in server side(GPU) without initializing its value.
- /// </summary>
- /// <param name="byteLength"></param>
- /// <param name="usage"></param>
- /// <param name="mode"></param>
- /// <param name="type"></param>
- /// <param name="length"></param>
- /// <returns></returns>
- public static OneIndexBufferPtr Create(int byteLength, BufferUsage usage, DrawMode mode, IndexElementType type, int length)
- {
- uint[] buffers = new uint[];
- glGenBuffers(, buffers);
- const uint target = OpenGL.GL_ELEMENT_ARRAY_BUFFER;
- glBindBuffer(target, buffers[]);
- glBufferData(target, byteLength, IntPtr.Zero, (uint)usage);
- glBindBuffer(target, );
- var bufferPtr = new OneIndexBufferPtr(
- buffers[], mode, type, length, byteLength);
- return bufferPtr;
- }
ZeroIndexBufferPtr
对于使用 glDrawArrays() 的索引,则更简单。
- /// <summary>
- /// Creates a <see cref="ZeroIndexBufferPtr"/> object directly in server side(GPU) without initializing its value.
- /// </summary>
- /// <param name="mode"></param>
- /// <param name="firstVertex"></param>
- /// <param name="vertexCount"></param>
- /// <returns></returns>
- public static ZeroIndexBufferPtr Create(DrawMode mode, int firstVertex, int vertexCount)
- {
- ZeroIndexBufferPtr bufferPtr = new ZeroIndexBufferPtr(
- mode, firstVertex, vertexCount);
- return bufferPtr;
- }
使用方法也与上面雷同。
独立buffer
对于AtomicCounterBuffer、PixelPackBuffer、PixelUnpackBuffer、ShaderStorageBuffer、TextureBuffer、UniformBuffer这些,我统称为IndependentBuffer。他们当然也可以用新方法创建和使用。
- /// <summary>
- /// Creates a sub-type of <see cref="IndependentBufferPtr"/> object directly in server side(GPU) without initializing its value.
- /// </summary>
- /// <param name="target"></param>
- /// <param name="byteLength"></param>
- /// <param name="usage"></param>
- /// <param name="length"></param>
- /// <returns></returns>
- public static IndependentBufferPtr Create(IndependentBufferTarget target, int byteLength, BufferUsage usage, int length)
- {
- uint bufferTarget = ;
- switch (target)
- {
- case IndependentBufferTarget.AtomicCounterBuffer:
- bufferTarget = OpenGL.GL_ATOMIC_COUNTER_BUFFER;
- break;
- case IndependentBufferTarget.PixelPackBuffer:
- bufferTarget = OpenGL.GL_PIXEL_PACK_BUFFER;
- break;
- case IndependentBufferTarget.PixelUnpackBuffer:
- bufferTarget = OpenGL.GL_PIXEL_UNPACK_BUFFER;
- break;
- case IndependentBufferTarget.ShaderStorageBuffer:
- bufferTarget = OpenGL.GL_SHADER_STORAGE_BUFFER;
- break;
- case IndependentBufferTarget.TextureBuffer:
- bufferTarget = OpenGL.GL_TEXTURE_BUFFER;
- break;
- case IndependentBufferTarget.UniformBuffer:
- bufferTarget = OpenGL.GL_UNIFORM_BUFFER;
- break;
- default:
- throw new NotImplementedException();
- }
- uint[] buffers = new uint[];
- glGenBuffers(, buffers);
- glBindBuffer(bufferTarget, buffers[]);
- glBufferData(bufferTarget, byteLength, IntPtr.Zero, (uint)usage);
- glBindBuffer(bufferTarget, );
- IndependentBufferPtr bufferPtr;
- switch (target)
- {
- case IndependentBufferTarget.AtomicCounterBuffer:
- bufferPtr = new AtomicCounterBufferPtr(buffers[], length, byteLength);
- break;
- case IndependentBufferTarget.PixelPackBuffer:
- bufferPtr = new PixelPackBufferPtr(buffers[], length, byteLength);
- break;
- case IndependentBufferTarget.PixelUnpackBuffer:
- bufferPtr = new PixelUnpackBufferPtr(buffers[], length, byteLength);
- break;
- case IndependentBufferTarget.ShaderStorageBuffer:
- bufferPtr = new ShaderStorageBufferPtr(buffers[], length, byteLength);
- break;
- case IndependentBufferTarget.TextureBuffer:
- bufferPtr = new TextureBufferPtr(buffers[], length, byteLength);
- break;
- case IndependentBufferTarget.UniformBuffer:
- bufferPtr = new UniformBufferPtr(buffers[], length, byteLength);
- break;
- default:
- throw new NotImplementedException();
- }
- return bufferPtr;
- }
public static IndependentBufferPtr Create(IndependentBufferTarget target, int byteLength, BufferUsage usage, int length)
总结
现在CSharpGL已经有点深度,所以笔记很难写出让人直接就能眼前一亮的感觉了。
目前CSharpGL中已经涵盖了我所知的所有OpenGL知识点。下一步就是精心读书,继续深挖。
CSharpGL(37)创建和使用VBO的最佳方式的更多相关文章
- CSharpGL(7)对VAO和VBO的封装
CSharpGL(7)对VAO和VBO的封装 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo,更适合入门参考 ...
- Oracle创建新undo表空间最佳实践(包含段检查)
在处理一则ORA-600 [4194]案例时,参考MOS文档:Step by step to resolve ORA-600 4194 4193 4197 on database crash (文档 ...
- 4.3.6 对象的界定通过编写接口来访问带这类命名结构的表会出问题。如前所述,SQL Server的灵活性不应用作编写错误代码或创建问题对象的借口。 注意在使用Management Studio的脚本工具时,SQL Server会界定所有的对象。这不是因为这么做是必须的,也不是编写代码的最佳方式,而是因为在界定符中封装所有的对象,比编写脚本引擎来查找需要界定的对象更容易。
如前所述,在创建对象时,最好避免使用内嵌的空格或保留字作为对象名,但设计人员可能并没有遵守这个最佳实践原则.例如,我当前使用的数据库中有一个审核表名为Transaction,但是Transaction ...
- js创建对象的最佳方式
1.对象的定义 ECMAScript中,对象是一个无序属性集,这里的“属性”可以是基本值.对象或者函数 2.数据属性与访问器属性 数据属性即有值的属性,可以设置属性只读.不可删除.不可枚举等等 访问器 ...
- vue父子组件状态同步的最佳方式续章(v-model篇)
大家好!我是木瓜太香!一名前端工程师,之前写过一篇<vue父子组件状态同步的最佳方式>,这篇文章描述了大多数情况下的父子组件同步的最佳方式,也是被开源中国官方推荐了,在这里表示感谢! 这次 ...
- java核心知识点学习----创建线程的第三种方式Callable和Future CompletionService
前面已经指出通过实现Runnable时,Thread类的作用就是将run()方法包装成线程执行体,那么是否可以直接把任意方法都包装成线程执行体呢?Java目前不行,但其模仿者C#中是可以的. Call ...
- Java反射机制(创建Class对象的三种方式)
1:了解什么是反射机制? 在通常情况下,如果有一个类,可以通过类创建对象:但是反射就是要求通过一个对象找到一个类的名称: 2:在反射操作中,握住一个核心概念: 一切操作都将使用Object完成,类 ...
- JDBC 创建连接对象的三种方式 、 properties文件的建立、编辑和信息获取
创建连接对象的三种方式 //第一种方式 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/ ...
- python中逐行读取文件的最佳方式_Drupal_新浪博客
python中逐行读取文件的最佳方式_Drupal_新浪博客 python中逐行读取文件的最佳方式 (2010-08-18 15:59:28) 转载▼ 标签: python ...
随机推荐
- 【每日一linux命令3】参数(或称选项)顺序
一般除了特殊情况,参数是没有顺序的.举例而言,输入"–a –v"与输入"–v –a"以及"–av" 的执行效果是相同的.但若该参数后指定了要 ...
- [C#] 进阶 - LINQ 标准查询操作概述
LINQ 标准查询操作概述 序 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> ...
- Mac OS 使用 Vagrant 管理虚拟机(VirtualBox)
Vagrant(官网.github)是一款构建虚拟开发环境的工具,支持 Window,Linux,Mac OS,Vagrant 中的 Boxes 概念类似于 Docker(实质是不同的),你可以把它看 ...
- 代码的坏味道(18)——依恋情结(Feature Envy)
坏味道--依恋情结(Feature Envy) 特征 一个函数访问其它对象的数据比访问自己的数据更多. 问题原因 这种气味可能发生在字段移动到数据类之后.如果是这种情况,你可能想将数据类的操作移动到这 ...
- PHP设计模式(八)桥接模式(Bridge For PHP)
一.概述 桥接模式:将两个原本不相关的类结合在一起,然后利用两个类中的方法和属性,输出一份新的结果. 二.案例 1.模拟毛笔(转) 需求:现在需要准备三种粗细(大中小),并且有五种颜色的比 如果使用蜡 ...
- Unity C#最佳实践(上)
本文为<effective c#>的读书笔记,此书类似于大名鼎鼎的<effective c++>,是入门后提高水平的进阶读物,此书提出了50个改进c#代码的原则,但是由于主要针 ...
- Apache2.4:AH01630 client denied by server configuration
问题说明:Apache服务总共有4个,是为了防止单点故障和负载均衡,负载均衡控制由局方的F5提供. 访问的内容在NAS存储上,现象是直接访问每个apache的服务内容都是没有问题,但是从负载地址过来的 ...
- CacheManager:–个通用缓存接口抽象类库
CacheManager是–个缓存通用接口抽象类库,它支持各种高速缓存提供者,例如Memcache,Redis,并且有许多先进的功能特性.具体可以访问官方网站 http://cachemanager ...
- Team Leader 你不再只是编码, 来炖一锅石头汤吧
h3{ color: #000; padding: 5px; margin-bottom: 10px; font-weight: bolder; background-color: #ccc; } h ...
- Android开发学习之路-机器学习库(图像识别)、百度翻译
对于机器学习也不是了解的很深入,今天无意中在GitHub看到一个star的比较多的库,就用着试一试,效果也还行.比是可能比不上TensorFlow的,但是在Android上用起来比较简单,毕竟Tens ...