无法正确转换OBJ或OpenGL不能很好地绘制对象

时间:2018-05-29 18:05:11

标签: python c++ opengl drawing wavefront

我花了好几个小时试图在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)

1 个答案:

答案 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