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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介:

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

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

opengl绘制数组数据时的数组组织图
 
有了这个数组就可以进行绘制了
在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;

目录
相关文章
|
7月前
|
分布式计算 DataWorks Java
DataWorks操作报错合集之在使用MaxCompute的Java SDK创建函数时,出现找不到文件资源的情况,是BUG吗
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
93 0
|
4月前
|
Java Apache 开发工具
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
|
4月前
|
监控 Java 开发工具
【事件中心 Azure Event Hub】Event Hub Java SDK的消费端出现不消费某一个分区中数据的情况,出现IdleTimerExpired错误消息记录
【事件中心 Azure Event Hub】Event Hub Java SDK的消费端出现不消费某一个分区中数据的情况,出现IdleTimerExpired错误消息记录
|
4月前
|
网络安全 开发工具 Python
【Azure事件中心】使用Python SDK(Confluent)相关方法获取offset或lag时提示SSL相关错误
【Azure事件中心】使用Python SDK(Confluent)相关方法获取offset或lag时提示SSL相关错误
|
4月前
|
API 网络安全 开发工具
【Azure Developer - 密钥保管库 】使用 Python Azure SDK 实现从 Azure Key Vault Certificate 中下载证书(PEM文件)
【Azure Developer - 密钥保管库 】使用 Python Azure SDK 实现从 Azure Key Vault Certificate 中下载证书(PEM文件)
|
4月前
|
固态存储 Java 网络安全
【Azure Developer】使用Java SDK代码创建Azure VM (包含设置NSG,及添加数据磁盘SSD)
【Azure Developer】使用Java SDK代码创建Azure VM (包含设置NSG,及添加数据磁盘SSD)
|
4月前
|
Java 开发工具 Windows
【Azure Developer】调用SDK的runPowerShellScript方法,在Azure VM中执行PowerShell脚本示例
【Azure Developer】调用SDK的runPowerShellScript方法,在Azure VM中执行PowerShell脚本示例
|
4月前
|
存储 Java 开发工具
【Azure Developer】VS Code运行Java 版Azure Storage SDK操作Blob (新建Container, 上传Blob文件,下载及清理)
【Azure Developer】VS Code运行Java 版Azure Storage SDK操作Blob (新建Container, 上传Blob文件,下载及清理)
|
5月前
|
消息中间件 分布式计算 DataWorks
DataWorks产品使用合集之如何使用Python和阿里云SDK读取OSS中的文件
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
4月前
|
缓存 JavaScript 前端开发
微信 JS-SDK Demo “分享信息设置” API 及数字签名生成方法(NodeJS版本)
微信 JS-SDK Demo “分享信息设置” API 及数字签名生成方法(NodeJS版本)更新时间(2020-10-29)