Не могу правильно конвертировать OBJ или OpenGL плохо рисует объект - PullRequest
0 голосов
/ 29 мая 2018

Я часами пытался нарисовать свои модели .obj в OpenGL.Я подумал, что, возможно, что-то не так с моим скриптом 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 голосов
/ 29 мая 2018

Файл obj состоит из координат вершин с 3 компонентами (x, y, z), векторов нормалей с 3 компонентами (x, y, z) и текстурных координат с 2 компонентами (u, v).

Первый параметр glVertexPointer указывает количество координат (компонентов) на вершину, а первый параметр glTexCoordPointer указывает количество координат (компонентов) для каждого атрибута текстуры.

Вы правильно задали координаты текстуры, но в определении координат вершины вы указали 4 компонента вместо 3.

Измените определениемассив координат вершин:

glVertexPointer(3, GL_FLOAT, 0, vertices);

Обратите внимание: поскольку массив вершин был определен с 4 компонентами вместо 3, доступ к координатам вершин не выровнен и находится за пределами границ в конце.Это приводит к тому, что координаты вершины визуализированной сетки кажутся произвольными.


2-й параметр glNormalPointer указывает смещение байта между последовательными нормалями.Если значение шага равно 0, то нормалы считаются плотно упакованными в массив.

Векторы нормалей состоят из 3 компонентов (как ожидается glNormalPointer), и они плотно упакованы.

Либо параметр stride должен быть 0:

glNormalPointer(GL_FLOAT, 0, vertexNormals);

, либо он должен быть 3*sizeof(float):

glNormalPointer(GL_FLOAT, sizeof(float)*3, vertexNormals);

В номере функции раундакоординаты атрибута округляются до 2 десятичных знаков, но в файле 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 
...