Opengl绘制数组数据与文件数据的方法与Nvidia opengl sdk辅助实现

在opengl中绘制基本的集合原语可以使用诸如
gl_begin(type)
。。。
gl_end
的方式,逐个顶点进行绘制,但是如果想绘制一个大的模型或是一个完整的场景,里面的顶点数目几十上百万,这时就不能这样逐个顶点绘制了,为此,在opengl中有从数组绘制的方式。

数组绘制的基本思想:
就是把所所有顶点的位置、法向等信息装入数组,并且按照一定的序列(预先排好的)绘制他们就行了,这只需要几步操作。这里面一共涉及到两种数组,顶点数组(vertex array)与序列数组(indice array)。顶点数组就是将各顶点的位置、法向等装入(可单独也可联合),序列数组就好比一个目录,上面记录了先绘制哪个顶点,在绘制哪一个。图例


 
有了这个数组就可以进行绘制了
在opengl的数组绘制中,一共分三步:
第一步:用glEnableClientState(type)激活一个类型的数组type=GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_INDEX_ARRAY, GL_NORMAL_ARRAY, GL_TEXTURE_COORD_ARRAY, and GL_EDGE_FLAG_ARRAY,表示要进行那种数据的绘制
第二步: 用glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)/glNormalPointer…指定定点数组,size为分量数(位置为2或3,法向为3等),type是GL_SHORT, GL_INT, GL_FLOAT, or GL_DOUBLE的一种,为数组中数据的类型,stride是指在定点数组中两个连续顶点的数据间的间隔(byte为单位),这只在联合的形式中有用,在上图的顶点的联合数组中,GL_VERTEX_ARRAY的stride为3*四儿总分(GLfloat),因为要跨国3个向量的数据,POINTE为指向第一个数据的指针,上图中联合类型中GL_VERTEX_ARRAY的为pointer,而GL_NORMAL_ARRAY的为pointer+3。
第三步:用glDrawElements(GLenum mode, GLsizei count, GLenum type, void *indices)进行绘制,其中mode为绘制的集合原语类型(三角形等),count为绘制的顶点个数,type为索引数组中数据的类型,indeces为索引数组。另外有函数glArrayElement()一次绘制一个点。

使用以上三步可以从数组中绘制图形了,但是通常我们不直接在程序中直接定义这些长数组,而是将一个图形的数据保存在文件中,常用的如OBJ文件,这是就需要先解析文件,然后从中得到这些数组
解析OBJ文件的过程的主要思想为:
Obj文件包含了所有顶点的信息,和所有面片所包含的顶点的信息。

V 0.1 0.2 0.3
V 1.1 1 2.1
……
F 1 2 3
F2 3 5
首先将其中的所有的顶点信息读入到我们的顶点数组中;
然后解读面片信息,将所有的面片按照顺序读入到索引数组中,如上面的例子在
顶点的位置数组中将是{0.1 0.2 0.3 1.1 1 2.1。。。。。。}
索引数组将是{1,2,3,2,3,5。。。。。。}
当然实际的OBJ可能还有很多其他的顶点信息,如法向、贴图、颜色等,过称相同
这样构建好数组后,就可以用opengl的三步绘制了
注意,索引数组中的个数和总定点数是不等的,因为一个顶点可能会被几个面共有,这时,他在索引数组中会出现多次,索引数组就是绘制顶点的顺序。

Nvidia opengl sdk辅助
应用中有很多外部的库实现了对obj文件的解析,其中NVIDIA opengl sdk是很好的一个opengl辅助库,他其中实现了很多类,都是较有用的工具。其中的nv::Model类就是一个可以解析obj文件的类。
Nv::Mode类
该类描述了一个模型的信息。使用该类的过程通常是这样的
首先用loadModel从obj文件读入一个模型信息,此时里面包含的信息是最原始的obj中的数据,如果obj文件中未定义法向等,可以调用computeNormals()进行计算。
读入后就可以用opengl的三个步骤绘制了,如这段代码
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3,GL_FLOAT,0,model->getPositions());
glNormalPointer(GL_FLOAT,0,model->getNormals());
glDrawElements(GL_TRIANGLES, model->getIndexCount(), GL_UNSIGNED_INT, model->getPositionIndices());
glDrawElements(GL_TRIANGLES, model->getIndexCount(), GL_UNSIGNED_INT, model-> getNormals());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
这只是一种绘制方法,这种方法中,顶点的位置、发相等分别在不同的数组中,各自的索引也可能是不同的,该类有另一种方法可以将所有的数据都归结到一个数组中(也就是联合形式),然后索引也是唯一的。
这种方式更加推荐
首先调用compileModel()将数组编辑归结到一起,然后就可以用下面代码绘制
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
int stride=model->getCompiledVertexSize()*sizeof(GLfloat);
glVertexPointer(3,GL_FLOAT,stride,model->getCompiledVertices());
glNormalPointer(GL_FLOAT,stride,model->getCompiledVertices()+model->getCompiledNormalOffset());
glDrawElements(GL_TRIANGLES, model->getCompiledIndexCount(), GL_UNSIGNED_INT, model->getCompiledIndices());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
这里面stride是大数组中两个同类型数据间的跨度,所有类型的都是相等的
然后在glVertexPointer/ glNormalPointer时,就要加上一个位移就可以了。
(我在用这个类时发现最后进行delete时会出问题,而且nvidia的demo中也只new,不delete,不知其中是否有其他机制在里面)

归结一下nv::Model类的函数
初始化:
读文件
loadModelFromFile

查询是否有法向(。。。)特性和计算:
NVSDKENTRY bool hasNormals() const;
NVSDKENTRY bool hasTexCoords() const;
NVSDKENTRY bool hasTangents() const;
NVSDKENTRY bool hasColors() const;
NVSDKENTRY void computeTangents();
NVSDKENTRY void computeNormals();
用原始OBJ绘制:
得到顶点数组
  NVSDKENTRY const float* getPositions() const;
  NVSDKENTRY const float* getNormals() const;
  NVSDKENTRY const float* getTexCoords() const;
  NVSDKENTRY const float* getTangents() const;
  NVSDKENTRY const float* getColors() const;
  得到序列数组
  NVSDKENTRY const GLuint* getPositionIndices() const;
  NVSDKENTRY const GLuint* getNormalIndices() const;
  NVSDKENTRY const GLuint* getTexCoordIndices() const;
  NVSDKENTRY const GLuint* getTangentIndices() const;
  NVSDKENTRY const GLuint* getColorIndices() const;
得到数组的数目
  NVSDKENTRY int getPositionCount() const;
  NVSDKENTRY int getNormalCount() const;
  NVSDKENTRY int getTexCoordCount() const;
  NVSDKENTRY int getTangentCount() const;
  NVSDKENTRY int getColorCount() const;
  NVSDKENTRY int getIndexCount() const;
用联合的大数组进行绘制:
首先重编数组
  compileModel()
  得到联合的顶点数组:
  NVSDKENTRY const float* getCompiledVertices() const;
  得到联合的索引数组
  NVSDKENTRY const GLuint* getCompiledIndices( PrimType prim = eptTriangles) const;
  得到在联合数组中各特性数据的起始位移
  NVSDKENTRY int getCompiledPositionOffset() const;
  NVSDKENTRY int getCompiledNormalOffset() const;
  NVSDKENTRY int getCompiledTexCoordOffset() const;
  NVSDKENTRY int getCompiledTangentOffset() const;
  NVSDKENTRY int getCompiledColorOffset() const;
  得到联合数组中一个顶点所包含的分量数
  // returns the size of the merged vertex in # of floats
  NVSDKENTRY int getCompiledVertexSize() const;
  得到顶点数和索引数
  NVSDKENTRY int getCompiledVertexCount() const;
  NVSDKENTRY intgetCompiledIndexCount( PrimType prim = eptTriangles) const;

时间: 2024-07-28 16:04:41

Opengl绘制数组数据与文件数据的方法与Nvidia opengl sdk辅助实现的相关文章

修复DBF数据表文件的简单方法

数据   修复DBF数据表文件的简单方法 如果你的软件提示"不是DATABASE 数据库"等意思说明你的数据库已经受损,需要进行修理.本人在实践中,摸索出几种可行的办法,以供大家参考,如有不正确之处或者其他更好的方法,希望不吝赐教:       方法1.如果你有DELPHI的Database DeskTop,修复DBF文件是一件非常容易的事,只要打开损坏的数据库(用Database DeskTop是可以打开损坏的DBF数据表的),修正损坏的记录,一般是最后几条记录,不能修正的损坏记录也

MSSQL 监控数据/日志文件增长实现方法

前几天,在所有数据库服务器部署了监控磁盘空间的存储过程和作业后(MS SQL 监控磁盘空间告警),今天突然收到了两封告警邮件,好吧,存储规划是一方面,但是,是不是要分析一下是什么原因造成磁盘空间不足的呢?会不会是因为突然暴增的日志文件,抑或是系统业务猛增导致数据量暴增,还是历史数据累计原因....分析总得有数据来支撑吧,但是现在只有那些数据文件的当前大小信息,没有数据文件的历史增长变化信息,所以,今天就想实现这么一个功能,每天(频率可以调整)去收集一下数据文件的信息,放到一个表里面,这样方便我们

MSSQL 监控数据/日志文件增长实现方法_MsSql

前几天,在所有数据库服务器部署了监控磁盘空间的存储过程和作业后(MS SQL 监控磁盘空间告警),今天突然收到了两封告警邮件,好吧,存储规划是一方面,但是,是不是要分析一下是什么原因造成磁盘空间不足的呢?会不会是因为突然暴增的日志文件,抑或是系统业务猛增导致数据量暴增,还是历史数据累计原因....分析总得有数据来支撑吧,但是现在只有那些数据文件的当前大小信息,没有数据文件的历史增长变化信息,所以,今天就想实现这么一个功能,每天(频率可以调整)去收集一下数据文件的信息,放到一个表里面,这样方便我们

一组文件数据库函数

函数|数据|数据库 <?/** * 文件数据库函数 * 约定: * 数据库名为同名目录 * 数据表名后缀为 tab * 索引文件后缀为 ind * 管理文件名为 数据库同名目录/manage.ini * 备注型字段以独立文件存在,表中保留文件名 * 字段以定长方式或csv方式保存,由管理文件指定 * 每行一条记录 * 索引文件以二进制方式包存键值(定长)和偏移量(长整型) * ** 函数列表(前面有:+ 为已实现,- 为部分实现,其余为尚未实现)      套用 MySQL 函数集 取名 FIL

显示-vb.net如何读取文件,把文件数据保存成数组?

问题描述 vb.net如何读取文件,把文件数据保存成数组? Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Me.ListBox1.Items.Clear() Dim StrRed As StreamReader = New StreamReader("C:JD.JD", System.Text.Encoding.Default) While Not StrRed.End

把数组内的数据写入文件流 和读取文件流啊

问题描述 publicclassData{//创建一个顾客对象的动态数组publicArrayListcustoms=newArrayList();//会员//创建一个商品对象的动态数组publicArrayListgoods=newArrayList();//商品数据}数组内定义有Customs和goos商品的数据怎么把把数组内的数据写入文件流和读取文件流啊 解决方案 解决方案二:序列号成二进制文件吧可以参考这个解决方案三:上面写错了,是序列化,不是序列号解决方案四:可以定义一个文件,publ

用 WebClient.UploadData 方法 上载文件数据

client|web|数据 假如某网站有个表单,例如(url: http://localhost/login.aspx):   帐号   密码      我们需要在程序中提交数据到这个表单,对于这种表单,我们可以使用 WebClient.UploadData 方法来实现,将所要上传的数据拼成字符即可,程序很简单:      string uriString = "http://localhost/login.aspx";   // 创建一个新的 WebClient 实例.   WebC

for循环存取数据到文件中

问题描述 for循环存取数据到文件中 经过一个for循环,每次都能得到一组数据,将每组数据按行存入一个txt文件中,大约十几万行,该怎样写,求助大神们!给个大概模板也可以,相似的例子之类的! 解决方案 我觉得这个问题就是写入数据的问题,怎么大家给的答案都是从txt中读取数据呢...脚蹬轱辘转 同学给的思路是正确的,遍历数组,然后用输出流写入数据即可.给你个参考例子吧: int[] intStrs = new int[] { 1 2 3 4 }; String outPath = ""D

Android通过HTTP协议实现上传文件数据_Android

本文实例为大家分享了Android通过HTTP协议实现上传文件数据的具体代码,供大家参考,具体内容如下 SocketHttpRequester.java package cn.itcast.utils; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.InputStream; import java.io.Inp