我花了好几个小时试图在OpenGL中绘制我的.obj模型。我想我的Python脚本可能有问题(将obj模型转换为C ++文件)。或者.obj文件有问题。我不知道如何让它正常工作。 OpenGL绘制一个对象,但它与我在SketchUp中创建的对象完全不同。
简而言之:我的脚本正确转换.obj(除非我不知道其他规则)。首先,我在一个行列表中收集带顶点的行,与vn和vt相同。我还收集了关于面孔的数据。后来我将适当的v,vn和vt与面部相匹配。最后,它会生成包含数据的.h和.cpp文件。什么可能是错的?
这是.obj文件:https://pastebin.com/g0HwpRqB
# Alias OBJ Model File
# Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited
# File units = meters
mtllib sciany1.mtl
g Mesh1 Model
usemtl Brick_Tumbled
v 2.06118 0 0.0146645
vt -2.25413 -0.0320745
vn 0 -1 -0
v -3.02882 0 0.0146645
vt 3.31236 -0.0320745
v -3.02882 0 -9.68534
vt 3.31236 21.184
v 2.06118 0 -9.68534
vt -2.25413 21.184
f 1/1/1 2/2/1 3/3/1 4/4/1
usemtl FrontColor
vt -119.245 0
vn 0 0 1
vt 81.1487 0
v 2.06118 2.76 0.0146645
vt 81.1487 108.661
v -3.02882 2.76 0.0146645
vt -119.245 108.661
f 2/5/2 1/6/2 5/7/2 6/8/2
usemtl Brick_Tumbled
vt -0.0160372 0
vn 1 0 -0
vt 10.592 0
v 2.06118 2.76 -9.68534
vt 10.592 6.03675
vt -0.0160372 6.03675
f 1/9/3 4/10/3 7/11/3 5/12/3
usemtl FrontColor
vt -81.1487 0
vn 0 0 -1
vt 119.245 0
v -3.02882 2.76 -9.68534
vt 119.245 108.661
vt -81.1487 108.661
f 4/13/4 3/14/4 8/15/4 7/16/4
usemtl Brick_Tumbled
vt -10.592 0
vn -1 0 -0
vt 0.0160372 0
vt 0.0160372 6.03675
vt -10.592 6.03675
f 3/17/5 2/18/5 6/19/5 8/20/5
vt -3.31236 -0.0320745
vn 0 1 -0
vt 2.25413 -0.0320745
vt 2.25413 21.184
vt -3.31236 21.184
f 6/21/6 5/22/6 7/23/6 8/24/6
这是生成的.cpp文件:https://pastebin.com/YPXnuuzP
#include "sciany1.h"
namespace Models {
Sciany1 sciany1;
Sciany1::Sciany1() {
vertices=Sciany1Internal::vertices;
normals=Sciany1Internal::normals;
vertexNormals=Sciany1Internal::vertexNormals;
texCoords=Sciany1Internal::texCoords;
colors=Sciany1Internal::colors;
vertexCount=Sciany1Internal::vertexCount;
}
Sciany1::~Sciany1() {
}
void Sciany1::drawSolid() {
glEnable(GL_NORMALIZE);
glEnableClientState(GL_VERTEX_ARRAY);
//glEnableClientState(GL_COLOR_ARRAY);
//glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(4,GL_FLOAT,0,vertices);
//glColorPointer(4,GL_FLOAT,0,colors);
glNormalPointer(GL_FLOAT,sizeof(float)*4,vertexNormals);
glTexCoordPointer(2,GL_FLOAT,0,texCoords);
glDrawArrays(GL_TRIANGLES,0,vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
//glDisableClientState(GL_COLOR_ARRAY);
//glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
namespace Sciany1Internal {
unsigned int vertexCount=18;
float vertices[]={
2.06,0,0.01,
-3.02,0,0.01,
-3.02,0,-9.68,
-3.02,0,0.01,
2.06,0,0.01,
2.06,2.76,0.01,
2.06,0,0.01,
2.06,0,-9.68,
2.06,2.76,-9.68,
2.06,0,-9.68,
-3.02,0,-9.68,
-3.02,2.76,-9.68,
-3.02,0,-9.68,
-3.02,0,0.01,
-3.02,2.76,0.01,
-3.02,2.76,0.01,
2.06,2.76,0.01,
2.06,2.76,-9.68,
};
float colors[]={
};
float normals[]={
0,-1,-0,
0,-1,-0,
0,-1,-0,
0,0,1,
0,0,1,
0,0,1,
1,0,-0,
1,0,-0,
1,0,-0,
0,0,-1,
0,0,-1,
0,0,-1,
-1,0,-0,
-1,0,-0,
-1,0,-0,
0,1,-0,
0,1,-0,
0,1,-0,
};
float vertexNormals[]={
};
float texCoords[]={
-2.25,-0.03,
3.31,-0.03,
3.31,21.18,
-119.24,0,
81.14,0,
81.14,108.66,
-0.01,0,
10.59,0,
10.59,6.03,
-81.14,0,
119.24,0,
119.24,108.66,
-10.59,0,
0.01,0,
0.01,6.03,
-3.31,-0.03,
2.25,-0.03,
2.25,21.18,
};
}
}
这是生成的.h文件:https://pastebin.com/jaf73yf2
#ifndef SCIANY1_H
#define SCIANY1_H
//Sciany1 model made out of triangles
//Contains arrays:
//vertices - vertex positions in homogenous coordinates
//normals - vertex normals in homogenous coordinates
//texCoords - texturing coordinates
//colors - vertex colors (rgba)
//Culling GL_CW
//TBN friendly
#include "model.h"
namespace Models {
namespace Sciany1Internal {
extern float vertices[];
extern float normals[];
extern float vertexNormals[];
extern float texCoords[];
extern float colors[];
extern unsigned int vertexCount;
}
class Sciany1: public Model {
public:
Sciany1();
virtual ~Sciany1();
virtual void drawSolid();
};
extern Sciany1 sciany1;
}
#endif
这是我的Python脚本:https://pastebin.com/LivefwgY
def round_number(string_number):
if "\n" in string_number:
string_number = string_number.replace("\n", "")
if "." in string_number:
parts = string_number.split(".")
if len(parts[1]) > 2:
return parts[0] + "." + parts[1][:2]
return string_number
def line_to_good_line(line):
processed_numbers=[]
numbers=line.split(" ")
for number in numbers:
if number and number != "\n":
processed_numbers.append(round_number(number))
output = str.join(",", processed_numbers) + ",\n"
return output
def add_numbers_in_the_end(lines, additional_number):
new_lines=[]
for line in lines:
new_lines.append(line[:-1]+","+additional_number+",\n")
return new_lines
def prepare_output_from_faces(data, faces):
ready_list = []
for face in faces:
for number in face:
ready_list.append(data[int(number)-1])
return str.join("", ready_list)
def convert_to_cpp(filename):
model_name = filename[0].upper() + filename[1:-4]
upper_model_name = model_name.upper()
lower_model_name = model_name.lower()
vertices_lines = []
normals_lines = []
tex_coords_lines = []
vertices_faces = []
normals_faces = []
tex_coords_faces = []
vertices="" # final string output
normals="" # final string output
tex_coords="" # final string output
with open(filename, "r") as file:
lines = file.readlines()
for line in lines:
if line[0:2] == "v ":
line = line_to_good_line(line[2:])
vertices_lines.append(line)
elif line[0:3] == "vn ":
line = line_to_good_line(line[3:])
normals_lines.append(line);
elif line[0:3] == "vt ":
line = line_to_good_line(line[3:])
tex_coords_lines.append(line)
elif line[0:2] == "f ":
face = line[2:].replace("\n", "").split(" ")
face[0] = face[0].split("/")
face[1] = face[1].split("/")
face[2] = face[2].split("/")
vertex_face = [face[0][0], face[1][0], face[2][0]]
tex_coord_face = [face[0][1], face[1][1], face[2][1]]
normals_face = [face[0][2], face[1][2], face[2][2]]
vertices_faces.append(vertex_face)
tex_coords_faces.append(tex_coord_face)
normals_faces.append(normals_face)
vertices = prepare_output_from_faces(vertices_lines, vertices_faces)
normals = prepare_output_from_faces(normals_lines, normals_faces)
tex_coords = prepare_output_from_faces(tex_coords_lines, tex_coords_faces)
vertices_number = vertices.count("\n")
with open(lower_model_name + ".h", "w") as header_file:
data = """
/*
Niniejszy program jest wolnym oprogramowaniem; możesz go
rozprowadzać dalej i / lub modyfikować na warunkach Powszechnej
Licencji Publicznej GNU, wydanej przez Fundację Wolnego
Oprogramowania - według wersji 2 tej Licencji lub(według twojego
wyboru) którejś z późniejszych wersji.
Niniejszy program rozpowszechniany jest z nadzieją, iż będzie on
użyteczny - jednak BEZ JAKIEJKOLWIEK GWARANCJI, nawet domyślnej
gwarancji PRZYDATNOŚCI HANDLOWEJ albo PRZYDATNOŚCI DO OKREŚLONYCH
ZASTOSOWAŃ.W celu uzyskania bliższych informacji sięgnij do
Powszechnej Licencji Publicznej GNU.
Z pewnością wraz z niniejszym programem otrzymałeś też egzemplarz
Powszechnej Licencji Publicznej GNU(GNU General Public License);
jeśli nie - napisz do Free Software Foundation, Inc., 59 Temple
Place, Fifth face, Boston, MA 02110 - 1301 USA
*/
#ifndef {}_H
#define {}_H
//{} model made out of triangles
//Contains arrays:
//vertices - vertex positions in homogenous coordinates
//normals - vertex normals in homogenous coordinates
//texCoords - texturing coordinates
//colors - vertex colors (rgba)
//Culling GL_CW
//TBN friendly
#include "model.h"
namespace Models {{
namespace {}Internal {{
extern float vertices[];
extern float normals[];
extern float vertexNormals[];
extern float texCoords[];
extern float colors[];
extern unsigned int vertexCount;
}}
class {}: public Model {{
public:
{}();
virtual ~{}();
virtual void drawSolid();
}};
extern {} {};
}}
#endif
""".format(upper_model_name, upper_model_name,
model_name, model_name, model_name, model_name,
model_name, model_name, lower_model_name)
header_file.write(data)
with open(model_name + ".cpp", "w") as cpp_file:
data = """
/*
Niniejszy program jest wolnym oprogramowaniem; możesz go
rozprowadzać dalej i / lub modyfikować na warunkach Powszechnej
Licencji Publicznej GNU, wydanej przez Fundację Wolnego
Oprogramowania - według wersji 2 tej Licencji lub(według twojego
wyboru) którejś z późniejszych wersji.
Niniejszy program rozpowszechniany jest z nadzieją, iż będzie on
użyteczny - jednak BEZ JAKIEJKOLWIEK GWARANCJI, nawet domyślnej
gwarancji PRZYDATNOŚCI HANDLOWEJ albo PRZYDATNOŚCI DO OKREŚLONYCH
ZASTOSOWAŃ.W celu uzyskania bliższych informacji sięgnij do
Powszechnej Licencji Publicznej GNU.
Z pewnością wraz z niniejszym programem otrzymałeś też egzemplarz
Powszechnej Licencji Publicznej GNU(GNU General Public License);
jeśli nie - napisz do Free Software Foundation, Inc., 59 Temple
Place, Fifth face, Boston, MA 02110 - 1301 USA
*/
#include "{}.h"
namespace Models {{
{} {};
{}::{}() {{
vertices={}Internal::vertices;
normals={}Internal::normals;
vertexNormals={}Internal::vertexNormals;
texCoords={}Internal::texCoords;
colors={}Internal::colors;
vertexCount={}Internal::vertexCount;
}}
{}::~{}() {{
}}
void {}::drawSolid() {{
glEnable(GL_NORMALIZE);
glEnableClientState(GL_VERTEX_ARRAY);
//glEnableClientState(GL_COLOR_ARRAY);
//glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(4,GL_FLOAT,0,vertices);
//glColorPointer(4,GL_FLOAT,0,colors);
glNormalPointer(GL_FLOAT,sizeof(float)*4,vertexNormals);
glTexCoordPointer(2,GL_FLOAT,0,texCoords);
glDrawArrays(GL_TRIANGLES,0,vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
//glDisableClientState(GL_COLOR_ARRAY);
//glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}}
namespace {}Internal {{
unsigned int vertexCount={};
float vertices[]={{
{}
}};
float colors[]={{
}};
float normals[]={{
{}
}};
float vertexNormals[]={{
}};
float texCoords[]={{
{}
}};
}}
}}
""".format(lower_model_name, model_name, lower_model_name, model_name,
model_name, model_name, model_name, model_name, model_name, model_name,
model_name, model_name, model_name, model_name, model_name, vertices_number,
vertices, normals, tex_coords)
cpp_file.write(data)
filename = input("Input the name of the obj file: ")
convert_to_cpp(filename)
答案 0 :(得分:2)
obj 文件包含具有3个分量(x,y,z)的顶点坐标,具有3个分量(x,y,z)的法向量和具有2个分量的纹理坐标(u,v) )。
glVertexPointer
的第一个参数指定每个顶点的坐标(分量)数
并且glTexCoordPointer
的第一个参数指定每个纹理属性的坐标(分量)数。
你很好地完成了纹理坐标的规范,但是在顶点坐标的定义中你指定了4个组件而不是3个。
更改顶点坐标数组的定义:
glVertexPointer(3, GL_FLOAT, 0, vertices);
注意,由于顶点数组是用4个组件而不是3组件定义的,因此对顶点坐标的访问不对齐,最后超出界限。 这导致渲染网格的顶点坐标似乎是任意的。
glNormalPointer
的第二个参数指定连续法线之间的字节偏移。如果stride为0,则法线被理解为紧密排列在数组中。
法线向量由3个组成部分组成(正如glNormalPointer
所预期的那样)并且它们紧密排列。
stride 参数必须为0:
glNormalPointer(GL_FLOAT, 0, vertexNormals);
或必须是3*sizeof(float)
:
glNormalPointer(GL_FLOAT, sizeof(float)*3, vertexNormals);
在函数轮数中,属性坐标四舍五入到小数点后两位,但在 obj 文件中,顶点坐标的提交精度最多为5位小数。
将数字的舍入值从2位数改为5位小数:
def round_number(string_number):
if "\n" in string_number:
string_number = string_number.replace("\n", "")
if "." in string_number:
parts = string_number.split(".")
if len(parts[1]) > 5: # <---------------- 5 instead of 2
return parts[0] + "." + parts[1][:2]
return string_number