链接: https://pan.baidu.com/s/1cBTTbbzRCVBCX_H4jf6qMA 提取码: kj8w
一、实验要求和内容
1.1 实验内容
(1)实验描述
实现一个三维图形交互程序,能够读入三维obj文件、绘制并打上光照,并且实现基本的三维交互—包含平移、旋转和缩放。要求能够成功读取发给大家的obj文件模型(bunny.obj),也可以自行增加另外的三维模型文件。此作业要求每人单独完成。
(2)实验环境
在Clion平台下结合OpenGL开发
操作系统:macOS Monterey 12.0 Beta版(21A5248p)
处理器:Apple M1
内存:16.00GB
系统类型:64位操作系统
1.2 实验要求
(1)读入三维Obj文件
设计一定的数据结构,从而实现从实验资料bunny.obj文件中,将三维模型的必要信息进行读取收集。
(2)绘制三维模型并打光
在上述操作后,结合OpenGL的数据接口,绘制三维模型,给场景添加光照,使得最终效果良好。
(3)实现三维交互
实现基本的三维交互,包括平移,旋转,缩放。
二、实验步骤
2.1 数据结构设计
(1)OpenGL绘制要求
三维模型事实上是由许多的三角面拼接而成的,而OpenGL的接口可以绘制小三角面,通过绘制许多三角面,最终拼接成兔子模型。
要绘制三维模型,OpenGL需要知道三维模型每个三角面的顶点的坐标(每个坐标有x、y、z这3个坐标值),以及每个点或者每个面的法向量;读出obj文件中的顶点坐标v,顶点向量值vn,然后根据每个三角形面的点坐标和法向的索引值,把点和法向按照顺序存储在triangleVerts和normals中,再三个点为一组面进行渲染,得到bunny模型。
(2)设计数据结构
设计存储模型的类Imported
class Imported
{
private:
int numVertices{
};//存放点的个数
std::vector<glm::vec3> vertices;//存放顶点集
std::vector<glm::vec3> normalVecs;//存放法向集
std::vector<float> vertVals;//存放读入的点的值
std::vector<float> triangleVerts;//存放按面的索引排序后的顶点集
std::vector<float> fnormals;//存放按面的索引排序后的法向集
std::vector<float> normVals;//存放法向的值
public:
Imported();//无参构造
Imported(const char *filePath);//文件名构造,传输本地模型
int getNumVertices() const;//返回顶点个数的函数
std::vector<glm::vec3> getVertices();//返回顶点集vertices的函数
std::vector<glm::vec3> getNormals();//返回法向集normalVecs的函数
};
内置返回顶点个数、顶点集、法向集的函数,Imported利用parseOBJ函数实现获取有顺序意义的点集和法向集,以此来返回正确的顶点个数、顶点集、法向集。
2.2 OBJ文件读取
(1)Bunny.obj文件内容格式
将bunny.obj文件用记事本打开如下(截取部分):


对于该文件内容有如下说明:
v:代表顶点。格式为v、x、y、z,v后面的x、y、z表示三个顶点坐标。
vn:法向量。三角形的三个顶点都要指定法向量。格式为vn,nx、ny、nz。
f: 面。后面的整型值分别是属于这个面的顶点、法向量的索引。
(2)文件读取
在该文件中,顶点数据所在行由“v”字符开头,法向量数据所在行由“vn”字符开头,而面数据所在行由“f”字符开头。由此,根据每行开头字符,可以通过C++文件流将obj文件中不同类型的数据装入特定的数据结构中。
其中对使用的特殊的文件流对象stringstream,通过stringstream对象,我们可以简单的将一行以空格(或其他字符)为分界的字符串进行值分离。在本实验中,以点为例
1.v 0.1102022 0.74011 1.132398
用该对象可以轻松的将三个值读取出来。
然而在读取面时,则先将“//”替换成空格,最后通过子串函数获取相应值。
2.f 6830//6830 10332//10332 15543//15543
2.3 程序模块介绍
(1)读取文件模块
通过Imported读取文件模块,可以将Obj文件的点、法向量、面的数据转移到内存中,通过一定数据结构进行存储。上述内容已经给出了文件模块的具体代码,其主要思想是:先读取模型中的点和点的法向,存储起来,然后将模型的面部分逐行读取,通过面的索引把顶点数据和法向数据按照面的顺序重新储存一遍。
#include <fstream>
#include <sstream>
#include "glm/glm.hpp"
#include "Model.h"
using namespace std;
Imported::Imported() = default;
Imported::Imported(const char *filePath) {
float x, y, z;
ifstream fileStream(filePath, ios::in);
string line;
while (!fileStream.eof()) {
getline(fileStream, line);
if (line.compare(0, 2, "v ") == 0) {
stringstream ss(line.erase(0, 1));
ss >> x; ss >> y; ss >> z;
vertVals.push_back(x);
vertVals.push_back(y);
vertVals.push_back(z);
}
if (line.compare(0, 2, "vn") == 0) {
stringstream ss(line.erase(0, 2));
ss >> x; ss >> y; ss >> z;
normVals.push_back(x);
normVals.push_back(y);
normVals.push_back(z);
}
if (line.compare(0, 2, "f ") == 0) {
string oneCorner, v, t, n;
stringstream ss(line.erase(0, 2));
for (int i = 0; i < 3; i++) {
getline(ss, oneCorner, ' ');
stringstream oneCornerSS(oneCorner);
getline(oneCornerSS, v,

本文档详细介绍了使用OpenGL在Clion环境下开发三维图形交互程序的过程,包括读取Obj文件、绘制模型、添加光照、实现平移、旋转和缩放等交互功能。通过解析bunny.obj文件,设计适当的数据结构存储模型信息,并使用OpenGL接口绘制三维模型。实验结果展示了模型在不同交互操作下的变化,如视角变换、平移、缩放和线框图与面图的切换。

3436

被折叠的 条评论
为什么被折叠?



