-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodel.cpp
283 lines (243 loc) · 10 KB
/
model.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#include "model.h"
#include <QFile>
QOpenGLTexture *temp;
Model::Model(){
core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
}
bool Model::init(const QString &path){
/********** 更换模型时 删除上一个模型的数据 节约内存 ***********/
for(int i = 0; i < objects.size(); ++i){
core->glDeleteBuffers(1, &objects[i].positionVBO);
core->glDeleteBuffers(1, &objects[i].uvVBO);
core->glDeleteBuffers(1, &objects[i].normalVBO);
}
objects.clear();
map_materials.clear();
/*********** 初始化模型数据 ***************/
bool res = loadOBJ(path);
if(res){
this->bindBufferData();
}
return res;
}
void Model::draw(GLboolean isOpenLighting){
for(int i = 0; i < objects.size(); ++i){
//
ResourceManager::getShader("model").use().setVector3f("material.Ka", map_materials[objects[i].matName].Ka);
ResourceManager::getShader("model").use().setBool("isOpenLighting", isOpenLighting);
if(!map_materials.empty()){
core->glActiveTexture(GL_TEXTURE0);
ResourceManager::getTexture(map_materials[objects[i].matName].name_map_Ka).bind();
if(isOpenLighting){
//开启光照效果
core->glActiveTexture(GL_TEXTURE1);
ResourceManager::getTexture(map_materials[objects[i].matName].name_map_Kd).bind();
ResourceManager::getShader("model").use().setVector3f("material.Kd", map_materials[objects[i].matName].Kd);
ResourceManager::getShader("model").use().setVector3f("material.Ks", map_materials[objects[i].matName].Ks);
ResourceManager::getShader("model").use().setFloat("material.shininess", map_materials[objects[i].matName].shininess);
}
}
core->glEnableVertexAttribArray(0);
core->glBindBuffer(GL_ARRAY_BUFFER, objects[i].positionVBO);
core->glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
core->glEnableVertexAttribArray(1);
core->glBindBuffer(GL_ARRAY_BUFFER, objects[i].uvVBO);
core->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
core->glEnableVertexAttribArray(2);
core->glBindBuffer(GL_ARRAY_BUFFER, objects[i].normalVBO);
core->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
//绘图
core->glDrawArrays(GL_TRIANGLES, 0, objects[i].positions.size());
}
}
bool Model::loadOBJ(const QString &path){
QFile file(path);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug()<<"OBJLOADER ERROR::FILE CAN NOT OPEN!";
file.close();
return false;
}
QTextStream in(&file);
QString line;//文件流
QVector<int> positionIndices, uvIndices, normalIndices;
QVector<QVector3D> temp_positions;
QVector<QVector2D> temp_uvs;
QVector<QVector3D> temp_normals;
QString temp_matName;//材质的名称
while(!in.atEnd()){
line = in.readLine();//读取一行,还有读取所有readAll();
QStringList list = line.split(" ", QString::SkipEmptyParts);
if(list.empty())
continue;
//qDebug() << list;
if(list[0] == "mtllib"){//处理材质文件,即处理图片纹理
/******* 1.1 处理材质文件路径 *********/
//":/models/res/models/huapen/penzi.obj"
QString mtl_path = path;
int tempIndex = path.lastIndexOf("/")+1;
mtl_path.remove(tempIndex, path.size()-tempIndex);//":/models/res/models/huapen/" 得到根目录路径,用来和材质文件名结合,生成正确路径
//mtl_path += list[1];//得到材料路径":/models/res/models/huapen/penzi.mtl"
// qDebug() << mtl_path;
/******* 1.2 读取材质文件,导入Material类中 *********/
QFile mtl_file(mtl_path+list[1]);//正确的材质文件路径
if(!mtl_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug()<<"OBJLOADER ERROR::MTL_FILE CAN NOT OPEN!";
mtl_file.close();
file.close();
return false;
}
QTextStream mtl_in(&mtl_file);
QString mtl_line;//读取材质文件流的一行
Material material;
QString matName;//材质的名称
while(!mtl_in.atEnd()){
mtl_line = mtl_in.readLine();//读取一行,还有读取所有readAll();
QStringList mtl_list = mtl_line.split(QRegExp("\\s+"), QString::SkipEmptyParts); //以“空格”与“\t”为识别符号,分开字符串
if(mtl_list.empty())
continue;
if(mtl_list[0] == "newmtl"){
matName = mtl_list[1];
map_materials[matName] = material;
}else if(mtl_list[0] == "Ns"){
double shininess = mtl_list[1].toDouble();
map_materials[matName].shininess = shininess;
}else if(mtl_list[0] == "Ka"){
double x = mtl_list[1].toDouble();
double y = mtl_list[2].toDouble();
double z = mtl_list[3].toDouble();
QVector3D Ka(x, y, z);
map_materials[matName].Ka = Ka;
}else if(mtl_list[0] == "Kd"){
double x = mtl_list[1].toDouble();
double y = mtl_list[2].toDouble();
double z = mtl_list[3].toDouble();
QVector3D Kd(x, y, z);
map_materials[matName].Kd = Kd;
}else if(mtl_list[0] == "Ks"){
double x = mtl_list[1].toDouble();
double y = mtl_list[2].toDouble();
double z = mtl_list[3].toDouble();
QVector3D Ks(x, y, z);
map_materials[matName].Ks = Ks;
}else if(mtl_list[0] == "map_Ka"){
ResourceManager::loadTexture(mtl_list[1], mtl_path+mtl_list[1]);
map_materials[matName].name_map_Ka = mtl_list[1];
}else if(mtl_list[0] == "map_Kd"){
ResourceManager::loadTexture(mtl_list[1], mtl_path+mtl_list[1]);
map_materials[matName].name_map_Kd = mtl_list[1];
}
}
/******* 1.2 读取材质文件,导入Material类中 *********/
}else if(list.size() > 1 && list[1] == "object"){//扫描寻找object
if(!objects.empty()){
for(int i=0; i < positionIndices.size(); i++ ){
//得到索引
int posIndex = positionIndices[i];
int uvIndex = uvIndices[i];
int norIndex = normalIndices[i];
//根据索引取值
QVector3D pos = temp_positions[posIndex-1];
objects.last().positions.push_back(pos);
QVector3D nor = temp_normals[norIndex-1];
objects.last().normals.push_back(nor);
if(uvIndex != 0){
QVector2D uv = temp_uvs[uvIndex-1];
objects.last().uvs.push_back(uv);
}
}
objects.last().matName = temp_matName;
positionIndices.clear();
uvIndices.clear();
normalIndices.clear();
}
Object object;
objects.push_back(object);//obj模型文件中的第一个object对象,因为一个obj模型可能还有多个object对象
}else if (list[0] == "v"){
double x = list[1].toDouble();
double y = list[2].toDouble();
double z = list[3].toDouble();
QVector3D pos;
pos.setX(x);
pos.setY(y);
pos.setZ(z);
temp_positions.push_back(pos);
}else if (list[0] == "vt"){
double x = list[1].toDouble();
double y = list[2].toDouble();
QVector2D uv;
uv.setX(x);
uv.setY(y);
temp_uvs.push_back(uv);
}else if (list[0] == "vn"){
double x = list[1].toDouble();
double y = list[2].toDouble();
double z = list[3].toDouble();
QVector3D nor;
nor.setX(x);
nor.setY(y);
nor.setZ(z);
temp_normals.push_back(nor);
}else if (list[0] == "usemtl"){
temp_matName = list[1];
//qDebug() << list[1];
}else if (list[0] == "f"){
if(list.size() > 4){
qDebug() << "OBJLOADER ERROR::THE LOADER ONLY SUPPORT THE TRIANGLES MESH!" << endl;
file.close();
return false;
}
for(int i = 1; i < 4; ++i){//读取处理 f字符后边的 三长串字符,如“f 2396/2442/2376 101/107/111 100/106/110”
QStringList slist = list[i].split("/");
int posIndex = slist[0].toInt();
int uvIndex = slist[1].toInt();
int norIndex = slist[2].toInt();
positionIndices.push_back(posIndex);
uvIndices.push_back(uvIndex);
normalIndices.push_back(norIndex);
//qDebug() <<posIndex << " " << uvIndex << " " << norIndex;
}
}
}
//处理最后一个object
for(int i=0; i < positionIndices.size(); i++ ){
//得到索引
int posIndex = positionIndices[i];
int uvIndex = uvIndices[i];
int norIndex = normalIndices[i];
//根据索引取值
QVector3D pos = temp_positions[posIndex-1];
objects.last().positions.push_back(pos);
QVector3D nor = temp_normals[norIndex-1];
objects.last().normals.push_back(nor);
if(uvIndex != 0){
QVector2D uv = temp_uvs[uvIndex-1];
objects.last().uvs.push_back(uv);
}
//qDebug() <<posIndex << " " << uvIndex << " " << norIndex;
}
objects.last().matName = temp_matName;
file.close();
return true;
}
void Model::bindBufferData(){
for(int i = 0; i < objects.size(); ++i){
core->glGenBuffers(1, &objects[i].positionVBO);
core->glBindBuffer(GL_ARRAY_BUFFER, objects[i].positionVBO);
// qDebug() << objects[i].positions.size();
core->glBufferData(GL_ARRAY_BUFFER, objects[i].positions.size() * sizeof(QVector3D), &objects[i].positions[0], GL_STATIC_DRAW);
core->glGenBuffers(1, &objects[i].uvVBO);
core->glBindBuffer(GL_ARRAY_BUFFER, objects[i].uvVBO);
core->glBufferData(GL_ARRAY_BUFFER, objects[i].uvs.size() * sizeof(QVector2D), &objects[i].uvs[0], GL_STATIC_DRAW);
core->glGenBuffers(1, &objects[i].normalVBO);
core->glBindBuffer(GL_ARRAY_BUFFER, objects[i].normalVBO);
core->glBufferData(GL_ARRAY_BUFFER, objects[i].normals.size() * sizeof(QVector3D), &objects[i].normals[0], GL_STATIC_DRAW);
// qDebug() << i << " : " << objects[i].positionVBO << " " << objects[i].uvVBO << " " << objects[i].normalVBO;
}
}