问题

每次当你调用device. DrawUserPrimitives方法时,顶点都会从系统内存传递到显卡中。通常,大部分数据没有变化,这意味着每帧重复传递了相同的数据。今天的显卡有容量很大而且很快的显存,所以你可以将顶点数据存储在显存中加速程序。从显存中将顶点数据传递到显卡速度要快得多,因为这些数据只在同一板卡的不同芯片间传输。同样索引数据也能获得加速。

解决方案

通过创建顶点数组的VertexBuffer,你可以将顶点数据复制到显存中。将顶点存储到显存后,就可以调用DrawPrimitives方法 (代替DrawUserPrimitives方法),这个方法从更快的显存中获取顶点。

注意:如果顶点几乎无需更新,那么这个方法可以极大地提高性能。但当处理被称为动态顶点数据(dynamic vertex data)时,这意味着顶点数据更新频繁,你应使用DynamicVertexBuffer,这会在下一个教程介绍。

工作原理

你可以一次性地将数据传递到显卡并把它们存储在显存中,而不是在每次调用DrawUserPrimitives方法时将顶点数组传递到显卡。要实现这个方法,你可以在创建了顶点数组后将它加载到一个VertexBuffer(顶点缓冲)中。在项目中添加VertexBuffer变量:

VertexBuffer vertBuffer; 

然后使用下面的方法生成六个顶点显示两个带纹理的三角形(可见教程5-1)。在这个方法最后,这六个顶点会加载到VertexBuffer并传递到显存中:

private void InitVertices()
{myVertexDeclaration = new VertexDeclaration(device, VertexPositionTexture.VertexElements); VertexPositionTexture[] vertices = new VertexPositionTexture[6]; int i = 0; vertices[i++] = new VertexPositionTexture(new Vector3(-5.0f, new Vector2(-0.5f,1.5f)); vertices[i++] = new VertexPositionTexture(new Vector3(-2.5f, new Vector2(0.5f, -1.5f)); vertices[i++] = new VertexPositionTexture(new Vector3(0, -3, new Vector2(1.5f, 1.5f)); vertices[i++] = new VertexPositionTexture(new Vector3(0, -3, -1), new Vector2(-0.5f, 1.5f)); vertices[i++] = new VertexPositionTexture(new Vector3(2.5f, 5, -1), new Vector2(0.5f, 1.5f));vertices[i++] = new VertexPositionTexture(new Vector3(5.0f, -3, -1), new Vector2(1.5f, 1.5f)); vertBuffer = new VertexBuffer(device, VertexPositionTexture.SizeInBytes * vertices.Length, BufferUsage.WriteOnly);vertBuffer.SetData(vertices, 0, vertices.Length);
} 

当定义了所有顶点后,你需创建一个VertexBuffer。这个VertexBuffer将传递到显卡的保留内存中,由于这个原因,你需要指定对设备的链接和顶点占据的字节数量,这个数量等于 (一个顶点的字节大小)乘以(顶点数量)。

注意:你当然不想每帧都创建一个VertexBuffer,请确保只调用这行代码一次。如果你想覆盖VertexBuffer的数据,不要删除它并重建一个,而是应该使用SetData方法将新数据加载到当前已经存在的VertexBuffer中。只要当你需要增加顶点的数量时才有必要删除VertexBuffer 并重建一个。

创建了VertexBuffer后,你就可以使用SetData方法将顶点数据传递到内存中。显然,SetData方法需要从顶点数组中复制数据。它的一个重载方法可以只写入VertexBuffer的部分数据,在这种情况下,你需指定从哪个顶点开始以及复制多少个顶点。

注意:如果你要频繁地更新VertexBuffer的内容,你应该使用DynamicVertexBufferDynamicVertexBuffer的SetData方法更为强大。

在显卡中存储了顶点数据后就可以绘制三角形了。你可以使用教程5-1中的代码,但有两处变化。

你将使用DrawPrimitive方法表明你将从VertexBuffer中获取数据进行绘制。在这之前首先要激活VertexBuffer。

device.RenderState.CullMode = CullMode.None;
basicEffect.World = Matrix.Identity;
basicEffect.View = fpsCam.ViewMatrix;
basicEffect.Projection = fpsCam.ProjectionMatrix;
basicEffect.Texture = myTexture;
basicEffect.TextureEnabled = true;
basicEffect.Begin();
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{pass.Begin(); device.VertexDeclaration = myVertexDeclaration; device.Vertices[0].SetSource(vertBuffer, 0, VertexPositionTexture.SizeInBytes); device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2); pass.End();
}
basicEffect.End(); 

在pass中,与以前一样需要将VertexDeclaration传递给设备表明顶点存储的数据类型、下一行代码设置VertexBuffer。对每个顶点来说,你可以在不同的VertexBuffers中存储不同的信息。本例中,你只使用了一个VertexBuffer,因此指定索引为0。使用SetSource方法,表明你将激活vertBuffer作为顶点的源。你还要指定第一个顶点的开始位置和一个顶点占据多少个字节(这样显卡才能将字节流裁切成独立的顶点)。激活VertexBuffer后,从第一个顶点开始使用TriangleList进行绘制,这个VertexBuffer 包含两个三角形的数据。

对性能的考虑:VertexBuffer构造函数

VertexBuffer的构造函数可以在最后一个参数中指定一些有用的可选择的标志,显卡的驱动会使用这个标志决定哪种内存是最快的。下面是可以使用的BufferUsages:

  • BufferUsage. None:允许从VertexBuffer中读写。
  • BufferUsage. Points:表示VertexBuffer中的顶点数据是用来绘制点和精灵的。这个与性能无关。
  • BufferUsage. WriteOnly:不从VertexBuffer读取数据。当使用VertexBuffer时,可以将顶点数据放在快得多的显存中。这样,当你想处理顶点数据时,比起将顶点数据在系统内存中存储一个副本,调用VertexBuffers的GetData方法往往更好。

你也可以组合这些标志,用 | 分隔表示OR操作(如果不矛盾,结果是指定选项的AND逻辑)。

IndexBuffer(索引缓冲)

如果你还想将索引存储在显卡中,你应在创建VertexBuffer之后再创建一个IndexBuffer ,所以在项目中添加一个IndexBuffer变量:

IndexBuffer indexBuffer; 

作为一个简单的例子,你将定义两个三角形,因为它们共享一个顶点,所以只需定义5个独立顶点:

private void InitVertices()
{myVertexDeclaration = new VertexDeclaration(device, VertexPositionTexture.VertexElements);VertexPositionTexture[] vertices = new VertexPositionTexture[5]; int i = 0; vertices[i++] = new VertexPositionTexture(new Vector3(-5.0f, -3, -1), new Vector2(-0.5f, 1.5f)); vertices[i++] = new VertexPositionTexture(new Vector3(-2.5f, 5, -1), new Vector2(0.5f, -1.5f)); vertices[i++] = new VertexPositionTexture(new Vector3(0, -3, -1), new Vector2(1.5f, 1.5f)); vertices[i++] = new VertexPositionTexture(new Vector3(2.5f, 5, -1), new Vector2(0.5f, -1.5f)); vertices[i++] = new VertexPositionTexture(new Vector3(5.0f, -3, -1), new Vector2(-0.5f, 1.5f)); vertBuffer = new VertexBuffer(device, VertexPositionTexture.SizeInBytes * vertices.Length, BufferUsage.WriteOnly); vertBuffer.SetData(vertices, 0, vertices.Length);
} 

接下来使用InitIndices方法创建索引数组并将它们复制到索引缓冲中:

private void InitIndices()
{int[] indices = new int[6]; int i = 0; indices[i++] = 0; indices[i++] = 1; indices[i++] = 2; indices[i++] = 2; indices[i++] = 3; indices[i++] = 4; indexBuffer = new IndexBuffer(device, typeof(int), indices.Length, BufferUsage.WriteOnly); indexBuffer.SetData<int>(indices);
} 

创建IndexBuffer时,你需要指定索引的类型,类型可以是ints或shorts,还要指定索引的多少。

当心:一些低端显卡只支持16-bit的索引,如果你使用32-bit的整数型索引会出错。要解决这个问题你应将索引存储在一个short数组中,指定创建一个short类型的索引缓冲。

技巧:如果你的数组包含不超过32,768的索引,你应该使用shorts而不是ints。这样索引缓冲可以节省一半内存。

别忘了在项目开始调用这个方法。

当进行绘制时,你需要激活VertexBuffer和IndexBuffer,然后调用DrawIndexedPrimitives 方法绘制三角形:

device.RenderState.CullMode = CullMode.None;
basicEffect.World = Matrix.Identity;
basicEffect.View = fpsCam.ViewMatrix;
basicEffect.Projection = fpsCam.ProjectionMatrix;
basicEffect.Texture = myTexture;
basicEffect.TextureEnabled = true;
basicEffect.Begin();
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{pass.Begin(); device.VertexDeclaration = myVertexDeclaration; device.Vertices[0].SetSource(vertBuffer, 0, VertexPositionTexture.SizeInBytes); device.Indices = indexBuffer; device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 5, 0, 2); pass.End();
}
basicEffect.End(); 
代码

InitVertices,InitIndices和Draw方法的代码前面已经写过了。

转载于:https://www.cnblogs.com/AlexCheng/archive/2011/01/25/2120117.html

处理顶点——使用顶点缓冲和索引缓冲将顶点和索引保存在显存中相关推荐

  1. [Slimdx]顶点和索引缓冲,绘制了2个分离的三角形

    定义网格顶点和索引缓冲,绘制了2个分离的三角形. 1 using System; 2 using System.Drawing; 3 using RGeos.SlimScene.Core; 4 usi ...

  2. 【OpenGL学习笔记五】 索引缓冲对象EBO

    在绘制一些图形的时候比如正方体,正方体的顶点是有很多重合的,如果为每个顶点都分配内存那么就比较浪费内存了. OpenGL通过索引缓冲对象来解决这个问题,做到重复的顶点只需要分配一次内存,再绘图的时候后 ...

  3. D3D索引缓冲 - 画一个矩形

    索引可以定义如何绘制几何体.比如,通过创建三角形来画一个四边形,每个三角形需要3个顶点,总共就需要6个顶点来创建一个四边形.若使用索引缓冲,则只需要4个顶点就可创建一个四边形.索引列表中第一个三角形的 ...

  4. .dat文件写入byte类型数组_文件字节流、文件字符流、缓冲字节流、缓冲字符流字节数组流、数据流、转换流、对象流...

    一.实操名称: 描述如下流的基本作用:文件字节流.文件字符流.缓冲字节流.缓冲字符流字节数组流.数据流.转换流.对象流二.描述1.文件字节流:包括:FileInputStream,FileOutput ...

  5. 《系统集成项目管理工程师》必背100个知识点-39接驳缓冲和项目缓冲

    什么是接驳缓冲?什么是项目缓冲? 项目缓冲:放置在关键链末端的缓冲称为项目缓冲,用来保证项目不因关键链的延误而延误.接驳缓冲:则放置在非关键链与关键链接合点,用来保护关键链不受非关键链延误的影响.

  6. (转)标准I/O缓冲:全缓冲、行缓冲、无缓冲 .

    某日一朋友写了一个HELLO WORLD代码,出不来结果,代码如下: #include <stdio.h> int main(int argc, char **argv){     pri ...

  7. 全缓冲、行缓冲和无缓冲

    这里的缓冲是指的是用户空间的I/O缓冲区,不是内核缓冲. 无缓冲:用户层不提供缓冲,数据流直接到内核缓冲,再到磁盘等外设上.标准错误输出(2)通常是无缓存的,因为它必须尽快输出,且是输出到具有交互式的 ...

  8. C/C++ 的全缓冲、行缓冲和无缓冲

    1.简介 C/C++中,基于 I/O 流的操作最终会调用系统接口 read() 和 write() 完成 I/O 操作.为了使程序的运行效率最高,流对象通常会提供缓冲区,以减少调用系统I/O接口的调用 ...

  9. 网页高性能图形编程(四)-WebGL颜色-使用着色器绘制多顶点颜色的三角图形 操作部骤-顶点着色器和片段着色器 着色器编译羽图像绘制-vertexAttribPointer 方法

    第5章-WebGL颜色 01-操作步骤介绍 颜色添加步骤 在顶点着色器中定义一个接收外部传入颜色值的属性变量a_Color和用于传输获取到的颜色值变量v_Color 在片段着色器中定义一个同一类型和名 ...

  10. Linux缓冲区(无缓冲,行缓冲,全缓冲)的区别

    Linux缓冲区(无缓冲,行缓冲,全缓冲)的区别 1.缓冲区的概念 1.1 全缓冲区 1.2.行缓冲 1.3 无缓冲 1.4.控制缓冲区的方式 2.demo 3.结果分析 1.缓冲区的概念 缓冲区(B ...

最新文章

  1. 剑指Offer之栈的压入、弹出序列
  2. LOJ.2587.[APIO2018]铁人两项Duathlon(圆方树)
  3. Linux中使用异步 I/O 大大提高应用程序的性能
  4. PHP,如何防止同一用户同一时间多次登录
  5. object取值_this的原理、函数的不同调用方式this取值、以及不同环境下this的取值、函数四种调用方法...
  6. 华为发布会: 牛逼鸿蒙,吹水的大会
  7. 系统大小端的头文件定义
  8. 【Java从0到架构师】SpringCloud - Hystrix、Zuul
  9. html5 video标签兼容性与自定义控件
  10. 基金行业数据安全保障体系建设探析
  11. linux下 使用apache2 ab 测试进行压力测试
  12. Matlab实现均值滤波
  13. ym——android源码大放送(实战开发必备)
  14. < 知识拓展:CSS 中常用的计量单位有哪些? >
  15. c语言低通滤波参数调节,低通滤波器的参数设置
  16. pythonRuntimeError: Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing
  17. python自学1:更改excel内容案例及技术总结
  18. 小程序 banner 的使用
  19. 关于matlab提示“警告: 矩阵为奇异工作精度” 的问题
  20. 数据库查询张三的MYSQL成绩_MySQL数据库查询练习题

热门文章

  1. Android开发之——依赖冲突Program type already present
  2. mysql自带计划任务
  3. java基础--ObjectInputStream和ObjectInputStream类
  4. 【你的数据库危机四伏 】
  5. ElasticSearch(1)CentOS安装ElasticSearch测试CRUD
  6. hibernate+spring+struts集成,并自动生成实体类和DAO层的步奏
  7. 真题很重要,用科学的态度批判性地对待真题同等重要!
  8. C# FAQ: const和static readonly有什么区别?
  9. 给浪费时间找种方法?
  10. 小卷积核的特征图与卷积参数变化不大,计算量变化明显