W ramach oderwania się od assemblera i przypomnienia sobie Cpp miałem opisać dosyć proste zagadnienie wczytywania obiektów .obj.
Niestety z powodu braku czasu postanowiłem zrobić coś innego - dla osób zainteresowanych umieszczam po prostu kod funkcji wczytującej którą pisałem rok temu. Mam nadzieję że przyda się osobom, szukającym pomysłów na optymalizację wczytywania obiektów obj - podstawy opisze innym razem.
Uwaga: poniższe, wybrane przeze mnie funkcje służą demonstracji możliwości optymalizacji loadera obiektów .obj. Zostały uproszczone o wiele linii kodu związanego z obsługą klasy i nie będą działały samodzielnie, bez reszty klasy i autorskich funkcji ogólnego użytku (między innymi operujących na stringach) więc nie warto próbować ich kompilować ;)
#define MAX_VERTEX 50000
#define MAX_TCORDS 38000
#define MAX_NORMALS 38000
#define MAX_WALLS 100000
#define MAX_MATERIALS 600
struct Wall_Vertex{
float tex[2];
float xyz[3];
};
struct Material{
string name;
float Ka[3];
float Kd[3];
float Ks[3];
float Ns;
float d; // the same as Tr
int illum; // nie używane
Texture map_Ka;
Texture map_Kd;
Texture map_Ks;
};
struct obj_Wall {
int x;
int y;
int z;
int w;
int tx;
int ty;
int tz;
int tw;
int normal_id;
bool quad_mode;
string material_name;
int material_id;
Wall_Vertex T2F_V3F[4];
Wall_Vertex T2F_V3F_TRI[3];
bool is_texture;
};
bool model::load_model_obj(string src){
main_color_on = false;
Vector4_clear(main_color);
vertex_num = 0;
walls_num = 0;
tex_cords_num = 0;
normals_num = 0;
materials_num = -1;
string curr_mat_name = "";
cout << "Ładowanie modelu typu obj ze źródła: " << src << endl;
FILE * obj_model_file;
char file_line [300];
// wyodrębnia ścieżkę do modelu
int temp_size;
string* path_array = string_explode(src,"/",temp_size);
path_to_model = "";
for(int i = 0; i < temp_size-1; i++){
path_to_model += path_array[i];
}
if(temp_size < 0)path_to_model = "";
//cout << path_to_model << endl;
obj_model_file = fopen (src.c_str() , „r”);
if(!obj_model_file){
Error(„In: load_model_obj, Nie udało się otworzyć pliku modelu”);
return 0;
}
else
while(fgets(file_line ,sizeof(file_line ),obj_model_file) != NULL){
string line_str = string(file_line);
int t_size;
string* line_exploded = string_explode(line_str," ",t_size);
if(t_size > 0){
if(file_line[0] == '#'){
// do nothing - komentarz
}
else if(file_line[0] == 'v' && file_line[1] == ' '){
// v - vertex - czyli parsujemy wierzchołek
if(t_size > 2){
if(vertex_num < MAX_VERTEX){
vertex_pos[vertex_num].x = atof(line_exploded[1].c_str());
vertex_pos[vertex_num].y = atof(line_exploded[2].c_str());
vertex_pos[vertex_num].z = atof(line_exploded[3].c_str());
vertex_num++;
} else Error(„Przekroczono MAX VERTEX”);
} else Error(„In load_model_obj, vertex: za mało argumentów do stworzenia wierzchołka.");
}
else if(file_line[0] == 'v' && file_line[1] == 'n'){
// vn - vertex normals - czyli parsujemy normalne
//cout << file_line;
if(t_size > 2){
if(normals_num < MAX_NORMALS){
normals[normals_num].x = atof(line_exploded[1].c_str());
normals[normals_num].y = atof(line_exploded[2].c_str());
normals[normals_num].z = atof(line_exploded[3].c_str());
normals_num++;
} else Error(„Przekroczono MAX_NORMALS”);
} else Error(„In load_model_obj, normals: za mało argumentów do stworzenia normalnej wierzchołka.");
}
else if(file_line[0] == 'v' && file_line[1] == 't'){
// vt - texture coords - czyli parsujemy koordynaty tekstur
if(t_size > 1){
if(tex_cords_num < MAX_TCORDS){
tex_cords[tex_cords_num].x = atof(line_exploded[1].c_str());
tex_cords[tex_cords_num].y = atof(line_exploded[2].c_str());
tex_cords_num++;
} else Error(„Przekroczono MAX_TCORDS”);
} else Error(„In load_model_obj, tex_cord: za mało argumentów do stworzenia text_cord.");
}
else if(file_line[0] == 'f' && file_line[1] == ' '){
// f - polygont zbudowane z trójkątów LUB QUADÓW. dla przypomninia 1/2/3:
// 1 - index of used vertex
// 2 - index of used texture coordinates
// 3 - index of used normals
if(t_size > 2){
if(walls_num < MAX_WALLS){
if(line_exploded[1] != "" && line_exploded[2] != "" && line_exploded[3] != ""){
//dla każdej ściany (bo każda ma minimum 3 wierzchołki)
string* temp_s = string_explode(line_exploded[1],"/");
walls_arra[walls_num].tx = atof(string_replace(temp_s[1],"/","").c_str());
string* temp_d = string_explode(line_exploded[2],"/");
walls_arra[walls_num].ty = atof(string_replace(temp_d[1],"/","").c_str());
string* temp_e = string_explode(line_exploded[3],"/");
walls_arra[walls_num].tz = atof(string_replace(temp_e[1],"/","").c_str());
if(walls_arra[walls_num].tx < 0){
walls_arra[walls_num].tx = tex_cords_num + walls_arra[walls_num].tx;
}
if(walls_arra[walls_num].ty < 0){
walls_arra[walls_num].ty = tex_cords_num + walls_arra[walls_num].ty;
}
if(walls_arra[walls_num].tz < 0){
walls_arra[walls_num].tz = tex_cords_num + walls_arra[walls_num].tz;
}
}
if(t_size > 4 && line_exploded[4] != ""){
// jeśli mam 4 wierzchołek to też go przetwarzam
string* temp_f = string_explode(line_exploded[4],"/");
walls_arra[walls_num].tw = atof(string_replace(temp_f[1],"/","").c_str());
if(walls_arra[walls_num].tw < 0){
walls_arra[walls_num].tw = tex_cords_num + walls_arra[walls_num].tw;
}
}
walls_arra[walls_num].x = atof(line_exploded[1].c_str());
walls_arra[walls_num].y = atof(line_exploded[2].c_str());
walls_arra[walls_num].z = atof(line_exploded[3].c_str());
if(t_size > 4){
walls_arra[walls_num].w = atof(line_exploded[4].c_str());
walls_arra[walls_num].quad_mode = true;
} else{
walls_arra[walls_num].quad_mode = false;
}
walls_arra[walls_num].material_name = curr_mat_name;
walls_arra[walls_num].material_id = -1;
walls_num++;
} else Error(„Przekroczono MAX_WALLS”);
} else Error(„In load_model_obj, polygon: za mało argumentów do stworzenia polygon.");
}else if(file_line[0] == 'u' && file_line[1] == 's'){
//usemtl
if(t_size > 1 && line_exploded[1] != "\n”){
curr_mat_name = string_replace(line_exploded[1].c_str(),"\n”, "");
curr_mat_name = string_replace(curr_mat_name.c_str(),"\r”, "");
} else Error(„In load_model_obj, mtlib: za mało argumentów do ustawienia mtl.");
}else if(file_line[0] == 'm' && file_line[1] == 't'){
//mtllib
if(t_size > 1){
string temp_src = string_replace(line_exploded[1].c_str(),"\n”, "");
temp_src = string_replace(temp_src.c_str(),"\r”, "");
load_mtlib(temp_src);
} else Error(„In load_model_obj, mtlib: za mało argumentów do stworzenia mtlib.");
}
}
}
calc_cords();
}
//UWAGA, ZMIENNE GLOBALNE
Material mat_array[MAX_MATERIALS];
string mat_src[MAX_MATERIALS];
int mat_loaded = -1;
bool model::load_mtlib(string src){
src = path_to_model + src;
//cout << "Ładowanie mtlib ze źródła: " << src << endl;
bool go = true;
for(int i = 0; i < mat_loaded+1; i++){
if(mat_src[i] == src){
materials_num++;
materials[materials_num] = mat_array[i];
go = false;
}
}
if(go){
FILE *mtlib_file;
char file_line [300];
mtlib_file = fopen (src.c_str() , „r”);
if(!mtlib_file){
Error(„In: load_mtlib, Nie udało się otworzyć pliku " + src);
return 0;
}
else{
while(fgets(file_line ,sizeof(file_line ),mtlib_file) != NULL){
string line_str = string(file_line);
line_str = string_replace(line_str.c_str(),"\r”,"");
int t_size;
string* line_exploded = string_explode(line_str," ",t_size);
arr_rm_spaces(line_exploded,t_size);
arr_rm_end_chars(line_exploded,t_size);
if(line_exploded[0] == „newmtl”){
if(t_size > 1){
if(materials_num+1 < MAX_MATERIALS){
if(materials_num >= 0) mat_array[mat_loaded] = materials[materials_num];
materials_num++;
mat_loaded++;
materials[materials_num].name = line_exploded[1];
mat_src[mat_loaded] = src;
materials[materials_num].Ka[0] = 1.0f;
materials[materials_num].Ka[1] = 1.0f;
materials[materials_num].Ka[2] = 1.0f;
materials[materials_num].Kd[0] = 1.0f;
materials[materials_num].Kd[1] = 1.0f;
materials[materials_num].Kd[2] = 1.0f;
materials[materials_num].Ks[0] = 1.0f;
materials[materials_num].Ks[1] = 1.0f;
materials[materials_num].Ks[2] = 1.0f;
materials[materials_num].d = 1.0f;
//cout << „Dodano materiał: " << materials[materials_num].name << endl;
} else Error(„Przekroczono MAX_MATERIALS”);
} else Error(„Za mało arg, in: load_mtlib, newmtl”);
} else if(line_exploded[0] == „Ns”){
if(t_size > 1){
materials[materials_num].Ns = atof(line_exploded[1].c_str());
} else Error(„Za mało arg, in: load_mtlib, Ns”);
} else if(line_exploded[0] == „Ka”){
if(t_size > 3){
materials[materials_num].Ka[0] = atof(line_exploded[1].c_str());
materials[materials_num].Ka[1] = atof(line_exploded[2].c_str());
materials[materials_num].Ka[2] = atof(line_exploded[3].c_str());
} else Error(„Za mało arg, in: load_mtlib, Ka”);
} else if(line_exploded[0] == „Kd”){
if(t_size > 1){
materials[materials_num].Kd[0] = atof(line_exploded[1].c_str());
materials[materials_num].Kd[1] = atof(line_exploded[2].c_str());
materials[materials_num].Kd[2] = atof(line_exploded[3].c_str());
} else Error(„Za mało arg, in: load_mtlib, Kd”);
} else if(line_exploded[0] == „Ks”){
if(t_size > 1){
materials[materials_num].Ks[0] = atof(line_exploded[1].c_str());
materials[materials_num].Ks[1] = atof(line_exploded[2].c_str());
materials[materials_num].Ks[2] = atof(line_exploded[3].c_str());
} else Error(„Za mało arg, in: load_mtlib, Ks”);
} else if(line_exploded[0] == „d” || line_exploded[0] == „Tr”){
if(t_size > 1){
materials[materials_num].d = atof(line_exploded[1].c_str());
} else Error(„Za mało arg, in: load_mtlib, d”);
} else if(line_exploded[0] == „illum”){
if(t_size > 1){
materials[materials_num].illum = atof(line_exploded[1].c_str());
} else Error(„Za mało arg, in: load_mtlib, illum”);
} else if(line_exploded[0] == „map_Kd”){
if(t_size > 1){
materials[materials_num].map_Kd.load_texture(path_to_model + line_exploded[1]);
//mat_array[mat_loaded].map_Kd = materials[materials_num].map_Kd;
//cout << materials[materials_num].map_Kd.imageData << endl;
} else Error(„Za mało arg, in: load_mtlib, illum”);
}
}
mat_array[mat_loaded] = materials[materials_num];
}
}
}
void model::compile_arrays(){
for(int i = 0; i < walls_num; i++){
bool is_texture = walls_arra[i].tz < tex_cords_num;
walls_arra[i].is_texture = is_texture;
if(walls_arra[i].quad_mode && is_texture){
walls_arra[i].T2F_V3F[0].tex[0] = tex_cords_calc[i][0].x;
walls_arra[i].T2F_V3F[0].tex[1] = tex_cords_calc[i][0].y;
walls_arra[i].T2F_V3F[0].xyz[0] = vertex_pos_calc[i][0].x;
walls_arra[i].T2F_V3F[0].xyz[1] = vertex_pos_calc[i][0].y;
walls_arra[i].T2F_V3F[0].xyz[2] = vertex_pos_calc[i][0].z;
walls_arra[i].T2F_V3F[1].tex[0] = tex_cords_calc[i][1].x;
walls_arra[i].T2F_V3F[1].tex[1] = tex_cords_calc[i][1].y;
walls_arra[i].T2F_V3F[1].xyz[0] = vertex_pos_calc[i][1].x;
walls_arra[i].T2F_V3F[1].xyz[1] = vertex_pos_calc[i][1].y;
walls_arra[i].T2F_V3F[1].xyz[2] = vertex_pos_calc[i][1].z;
walls_arra[i].T2F_V3F[2].tex[0] = tex_cords_calc[i][2].x;
walls_arra[i].T2F_V3F[2].tex[1] = tex_cords_calc[i][2].y;
walls_arra[i].T2F_V3F[2].xyz[0] = vertex_pos_calc[i][2].x;
walls_arra[i].T2F_V3F[2].xyz[1] = vertex_pos_calc[i][2].y;
walls_arra[i].T2F_V3F[2].xyz[2] = vertex_pos_calc[i][2].z;
walls_arra[i].T2F_V3F[3].tex[0] = tex_cords_calc[i][3].x;
walls_arra[i].T2F_V3F[3].tex[1] = tex_cords_calc[i][3].y;
walls_arra[i].T2F_V3F[3].xyz[0] = vertex_pos_calc[i][3].x;
walls_arra[i].T2F_V3F[3].xyz[1] = vertex_pos_calc[i][3].y;
walls_arra[i].T2F_V3F[3].xyz[2] = vertex_pos_calc[i][3].z;
}
else if(is_texture){
walls_arra[i].T2F_V3F_TRI[0].tex[0] = tex_cords_calc[i][1].x;
walls_arra[i].T2F_V3F_TRI[0].tex[1] = tex_cords_calc[i][1].y;
walls_arra[i].T2F_V3F_TRI[0].xyz[0] = vertex_pos_calc[i][1].x;
walls_arra[i].T2F_V3F_TRI[0].xyz[1] = vertex_pos_calc[i][1].y;
walls_arra[i].T2F_V3F_TRI[0].xyz[2] = vertex_pos_calc[i][1].z;
walls_arra[i].T2F_V3F_TRI[1].tex[0] = tex_cords_calc[i][2].x;
walls_arra[i].T2F_V3F_TRI[1].tex[1] = tex_cords_calc[i][2].y;
walls_arra[i].T2F_V3F_TRI[1].xyz[0] = vertex_pos_calc[i][2].x;
walls_arra[i].T2F_V3F_TRI[1].xyz[1] = vertex_pos_calc[i][2].y;
walls_arra[i].T2F_V3F_TRI[1].xyz[2] = vertex_pos_calc[i][2].z;
walls_arra[i].T2F_V3F_TRI[2].tex[0] = tex_cords_calc[i][3].x;
walls_arra[i].T2F_V3F_TRI[2].tex[1] = tex_cords_calc[i][3].y;
walls_arra[i].T2F_V3F_TRI[2].xyz[0] = vertex_pos_calc[i][3].x;
walls_arra[i].T2F_V3F_TRI[2].xyz[1] = vertex_pos_calc[i][3].y;
walls_arra[i].T2F_V3F_TRI[2].xyz[2] = vertex_pos_calc[i][3].z;
}
}
use_vertex_array = true;
bool main_mode_quad = walls_arra[0].quad_mode;
if(main_mode_quad){
vertex_array_quad = true;
} else {
vertex_array_quad = false;
}
string first_material = walls_arra[0].material_name;
for(int i = 0; i < walls_num; i++){
if(main_mode_quad && !walls_arra[i].quad_mode){
// złamano główny mode
i = walls_num;
use_vertex_array = false;
vertex_array_quad = false;
} else if(!main_mode_quad && walls_arra[i].quad_mode){
// złamano główny mode
i = walls_num;
use_vertex_array = false;
vertex_array_quad = false;
}
if(first_material != walls_arra[i].material_name){
//jeśli obiekt ma wiele materiałów to nie kompiluje tablicy ale
//ją dezaktywuję bo nie ma implementacji bindowania tekstur wewnątrz tablicy
i = walls_num;
use_vertex_array = false;
vertex_array_quad = false;
}
bool is_texture = walls_arra[i].tz < tex_cords_num;
if(vertex_array_quad && is_texture){
walls_array_packed_quad_T2F_V3F[i*4].tex[0] = tex_cords_calc[i][0].x;
walls_array_packed_quad_T2F_V3F[i*4].tex[1] = tex_cords_calc[i][0].y;
walls_array_packed_quad_T2F_V3F[i*4].xyz[0] = vertex_pos_calc[i][0].x;
walls_array_packed_quad_T2F_V3F[i*4].xyz[1] = vertex_pos_calc[i][0].y;
walls_array_packed_quad_T2F_V3F[i*4].xyz[2] = vertex_pos_calc[i][0].z;
walls_array_packed_quad_T2F_V3F[i*4+1].tex[0] = tex_cords_calc[i][1].x;
walls_array_packed_quad_T2F_V3F[i*4+1].tex[1] = tex_cords_calc[i][1].y;
walls_array_packed_quad_T2F_V3F[i*4+1].xyz[0] = vertex_pos_calc[i][1].x;
walls_array_packed_quad_T2F_V3F[i*4+1].xyz[1] = vertex_pos_calc[i][1].y;
walls_array_packed_quad_T2F_V3F[i*4+1].xyz[2] = vertex_pos_calc[i][1].z;
walls_array_packed_quad_T2F_V3F[i*4+2].tex[0] = tex_cords_calc[i][2].x;
walls_array_packed_quad_T2F_V3F[i*4+2].tex[1] = tex_cords_calc[i][2].y;
walls_array_packed_quad_T2F_V3F[i*4+2].xyz[0] = vertex_pos_calc[i][2].x;
walls_array_packed_quad_T2F_V3F[i*4+2].xyz[1] = vertex_pos_calc[i][2].y;
walls_array_packed_quad_T2F_V3F[i*4+2].xyz[2] = vertex_pos_calc[i][2].z;
walls_array_packed_quad_T2F_V3F[i*4+3].tex[0] = tex_cords_calc[i][3].x;
walls_array_packed_quad_T2F_V3F[i*4+3].tex[1] = tex_cords_calc[i][3].y;
walls_array_packed_quad_T2F_V3F[i*4+3].xyz[0] = vertex_pos_calc[i][3].x;
walls_array_packed_quad_T2F_V3F[i*4+3].xyz[1] = vertex_pos_calc[i][3].y;
walls_array_packed_quad_T2F_V3F[i*4+3].xyz[2] = vertex_pos_calc[i][3].z;
}
else if(is_texture){
walls_array_packed_trin_T2F_V3F_TRI[i*3].tex[0] = tex_cords_calc[i][1].x;
walls_array_packed_trin_T2F_V3F_TRI[i*3].tex[1] = tex_cords_calc[i][1].y;
walls_array_packed_trin_T2F_V3F_TRI[i*3].xyz[0] = vertex_pos_calc[i][1].x;
walls_array_packed_trin_T2F_V3F_TRI[i*3].xyz[1] = vertex_pos_calc[i][1].y;
walls_array_packed_trin_T2F_V3F_TRI[i*3].xyz[2] = vertex_pos_calc[i][1].z;
walls_array_packed_trin_T2F_V3F_TRI[i*3+1].tex[0] = tex_cords_calc[i][2].x;
walls_array_packed_trin_T2F_V3F_TRI[i*3+1].tex[1] = tex_cords_calc[i][2].y;
walls_array_packed_trin_T2F_V3F_TRI[i*3+1].xyz[0] = vertex_pos_calc[i][2].x;
walls_array_packed_trin_T2F_V3F_TRI[i*3+1].xyz[1] = vertex_pos_calc[i][2].y;
walls_array_packed_trin_T2F_V3F_TRI[i*3+1].xyz[2] = vertex_pos_calc[i][2].z;
walls_array_packed_trin_T2F_V3F_TRI[i*3+2].tex[0] = tex_cords_calc[i][3].x;
walls_array_packed_trin_T2F_V3F_TRI[i*3+2].tex[1] = tex_cords_calc[i][3].y;
walls_array_packed_trin_T2F_V3F_TRI[i*3+2].xyz[0] = vertex_pos_calc[i][3].x;
walls_array_packed_trin_T2F_V3F_TRI[i*3+2].xyz[1] = vertex_pos_calc[i][3].y;
walls_array_packed_trin_T2F_V3F_TRI[i*3+2].xyz[2] = vertex_pos_calc[i][3].z;
}
}
compile_list();
}
bool model::calc_cords(){
for(int i = 0; i < walls_num; i++){
if(i < MAX_TCORDS){
if(walls_arra[i].tw < tex_cords_num){
tex_cords_calc[i][0].x = tex_cords[walls_arra[i].tw-1].x;
tex_cords_calc[i][0].y = tex_cords[walls_arra[i].tw-1].y;
}
if(walls_arra[i].tx < tex_cords_num){
tex_cords_calc[i][1].x = tex_cords[walls_arra[i].tx-1].x;
tex_cords_calc[i][1].y = tex_cords[walls_arra[i].tx-1].y;
}
if(walls_arra[i].ty < tex_cords_num){
tex_cords_calc[i][2].x = tex_cords[walls_arra[i].ty-1].x;
tex_cords_calc[i][2].y = tex_cords[walls_arra[i].ty-1].y;
}
if(walls_arra[i].tz < tex_cords_num){
tex_cords_calc[i][3].x = tex_cords[walls_arra[i].tz-1].x;
tex_cords_calc[i][3].y = tex_cords[walls_arra[i].tz-1].y;
}
}
if(walls_arra[i].quad_mode){
vertex_pos_calc[i][0].x = vertex_pos[walls_arra[i].w-1].x;
vertex_pos_calc[i][0].y = vertex_pos[walls_arra[i].w-1].y;
vertex_pos_calc[i][0].z = vertex_pos[walls_arra[i].w-1].z;
}
vertex_pos_calc[i][1].x = vertex_pos[walls_arra[i].x-1].x;
vertex_pos_calc[i][1].y = vertex_pos[walls_arra[i].x-1].y;
vertex_pos_calc[i][1].z = vertex_pos[walls_arra[i].x-1].z;
vertex_pos_calc[i][2].x = vertex_pos[walls_arra[i].y-1].x;
vertex_pos_calc[i][2].y = vertex_pos[walls_arra[i].y-1].y;
vertex_pos_calc[i][2].z = vertex_pos[walls_arra[i].y-1].z;
vertex_pos_calc[i][3].x = vertex_pos[walls_arra[i].z-1].x;
vertex_pos_calc[i][3].y = vertex_pos[walls_arra[i].z-1].y;
vertex_pos_calc[i][3].z = vertex_pos[walls_arra[i].z-1].z;
if(walls_arra[i].material_name != ""){
for(int x = 0; x < materials_num + 1; x++){
if(walls_arra[i].material_name == materials[x].name){
walls_arra[i].material_id = x;
x = materials_num;
}
}
}
}
compile_arrays();
}
int locked_mat_id;
bool model::compile_list(){
if(!compiled_list){
compiled_list_id = glGenLists(1);
}
compiled_list = false;
glNewList(compiled_list_id, GL_COMPILE);
draw();
glEndList();
compiled_list = true;
}
Komentarze:
Brak komentarzy