Skip to main content
Commonmark migration
Source Link

#Current OBJLoader:

Current OBJLoader:

#Current OBJLoader:

Current OBJLoader:

Became Hot Network Question
Tweeted twitter.com/StackCodeReview/status/1240745029485891584
Rollback to Revision 5
Source Link
Mast
  • 13.5k
  • 12
  • 54
  • 119
import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram, compileShader
import os
import glm
from PIL import Image


class ObjLoader:
    def __init__(self):
        self.vert_coords: [float] = []
        self.text_coords: [float] = []
        self.norm_coords: [float] = []
        self.object_parts = {}
        self.setup_index()
        self.obj_shaders()

    def setup_index(self):

        self.material_index: [int] = []
        self.vertex_index: [int] = []
        self.texture_index: [int] = []
        self.normal_index: [int] = []
        self.model = []
        self.material_index = []
        self.vertex_index = []
        self.texture_index = []
        self.normal_index = []

    def load_model(self, file, *args):

        for line in open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'v':
                self.vert_coords.append(values[1:4])
            if values[0] == 'vt':
                self.text_coords.append(values[1:3])
            if values[0] == 'vn':
                self.norm_coords.append(values[1:4])
            if values[0] == 'mtllib':
                self.mtl = values[1]
                materials=matarials = self.mat_in_file(file)


        m_counter = 0
        for line in open(file, 'r'):  # open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'usemtl':
                if values[1] != materials[m_counter][0]matarials[m_counter][0]:
                    self.define_i_t_u(file, materials[m_counter]matarials[m_counter], args)
                    m_counter += 1
                    self.setup_index()
            if values[0] == 'f':
                partsface_i = [[]
                text_i = []
  [
              norm_i = []
        int(w) - 1 for w in v.split('/')
  for v in values[1:4]:
                   for w in= v.split('/')
                    ]
                    for vface_i.append(int(w[0]) in- values[1:4]1)
                ]

                self.vertex_indextext_i.append([part[0] for partint(w[1]) in- parts]1)
                self.texture_index.append([part[1] for part in parts])
                self.normal_indexnorm_i.append([part[2] for partint(w[2]) in- parts]1)

                self.define_i_t_uvertex_index.append(file,face_i)
 materials[m_counter], args              self.texture_index.append(text_i)
                self.normal_index.append(norm_i)

    def get_vertices(values):
        for v in values[1:4]:
            yield int(vself.splitdefine_i_t_u('/')[0])file, -matarials[m_counter], 1args)

    def define_i_t_u(self, file, mat, args):
        self.vertex_index = [y for x in self.vertex_index for y in x]
        self.texture_index = [y for x in self.texture_index for y in x]
        self.normal_index = [y for x in self.normal_index for y in x]

        for i in self.vertex_index:
            self.model.extend(self.vert_coords[i])
        for i in self.texture_index:
            self.model.extend(self.text_coords[i])
        for i in self.normal_index:
            self.model.extend(self.norm_coords[i])
        self.model = np.array(self.model, dtype='float32')

        glUseProgram(mat[1])
        texid = self.texture_materialMTL(file)
        l_vao = self.vao_creator(self.vertex_index, self.model, mat[1], mat[2], texid, args)
        self.object_parts["{0}".format(mat[0])] = l_vao

    def texture_materialMTL(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        filepath = os.path.dirname(filename)
        base = os.path.basename(filename)
        file_only_name = os.path.splitext(base)[0]
        contents = {}
        mtl = None
        image = None
        texid = None
        surf = None
        values = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                mtl = contents[values[1]] = {}
            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'map_Kd':
                self.object_shader = self.shader_obj_text
                # load the texture referred to by this declaration
                mtl[values[0]] = values[1]

                texid = mtl['texture_Kd'] = glGenTextures(1)

                glBindTexture(GL_TEXTURE_2D, texid)

                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                                GL_LINEAR)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                                GL_LINEAR)

                image = Image.open(os.path.join(filepath, mtl['map_Kd']))
                flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
                img_data = flipped_image.convert("RGBA").tobytes()
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                             img_data)

        return texid


    def vao_creator(self, vertex_index, model, shader, defuse_col, texid, args):
        texture_offset = len(vertex_index) * 12
        VAO = glGenVertexArrays(1)
        glBindVertexArray(VAO)
        VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, VBO)
        glBufferData(GL_ARRAY_BUFFER, model.itemsize * len(model), model, GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # texture
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, model.itemsize * 2, ctypes.c_void_p(texture_offset))
        glEnableVertexAttribArray(1)
        # Normals
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(12))
        glEnableVertexAttribArray(2)

        # Instancing
        if len(args) == 0:
            amount = 1
            vert_instance = np.array([
                [0[[0.0, 0.0, 0.0]
         , [1.0, 1.0, ]1.0]])
        else:
            amount = len(args)
            vert_instance = np.array(args)

        model_matricesmodelMatrices = []
        # Storring the objects in a list
        for i in range(0, amount):
            mod_list = []
            model_o = glm.mat4(1.0)
            model_o = glm.translate(model_o, glm.vec3(vert_instance[i][0], vert_instance[i][1], vert_instance[i][2]))
            # model_o = glm.scale(model_o, glm.vec3(0.00005, 0.00005, 0.00005))
            for i in range(4):
                for j in range(4):
                    mod_list.append(model_o[i][j])
            model_matricesmodelMatrices.append(mod_list)
        model_matricesmodelMatrices = np.array(model_matricesmodelMatrices, dtype="f")

        instanceVBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, instanceVBO)

        glBufferData(GL_ARRAY_BUFFER, amount * glm.sizeof(glm.mat4), model_matricesmodelMatrices, GL_STATIC_DRAW)
        # Bind each vertex attrib array of matrices (4 vectors in Matrix)
        glEnableVertexAttribArray(3)
        glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(0))
        glEnableVertexAttribArray(4)
        glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(glm.sizeof(glm.vec4)))
        glEnableVertexAttribArray(5)
        glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((2 * glm.sizeof(glm.vec4))))
        glEnableVertexAttribArray(6)
        glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((3 * glm.sizeof(glm.vec4))))
        # Set instancing
        forglVertexAttribDivisor(3, i1)
 in range      glVertexAttribDivisor(34, 71):
        glVertexAttribDivisor(5, 1)
        glVertexAttribDivisor(i6, 1)

        glBindVertexArray(0)

        return ([VAO, len(vertex_index), shader, defuse_col, texid, len(vert_instance)])

    def mat_in_file(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        mtl = None
        contents = {}
        mat_list = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                object_shader = self.shader_obj
                mtl = contents[values[1]] = {}
                matname = values[1]

            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'Kd':
                defuse_col = [float(values[1]), float(values[2]), float(values[3])]
            elif values[0] == 'd':
                defuse_col = defuse_col + [float(values[1])]
                mat_list.append([matname, object_shader, defuse_col])
            elif values[0] == 'map_Kd':
                object_shader = self.shader_obj_text
                mat_list.pop()
                mat_list.append([matname, object_shader, defuse_col])


        return mat_list

    def load_obj(self):
        obj_list = [self.object_parts[ind] for ind in self.object_parts]
        return obj_list

    def draw_call(self, vao_list, view, projection, model, *transf):

        if len(transf) == 0:
            transform = glm.mat4(1.0)
        else:
            transform = transf[0]

        for key in vao_list:
            VAO = key[0]
            vertex_len = key[1]
            shader = key[2]
            d_colour = key[3]
            texid = key[4]
            len_instanced = key[5]

            glUseProgram(shader)
            glBindTexture(GL_TEXTURE_2D, texid)
            view_loc = glGetUniformLocation(shader, "view")
            proj_loc = glGetUniformLocation(shader, "projection")
            model_loc = glGetUniformLocation(shader, "model")
            col_loc = glGetUniformLocation(shader, "mycolor")

            glUniformMatrix4fv(view_loc, 1, GL_FALSE, view)
            glUniformMatrix4fv(proj_loc, 1, GL_FALSE, projection)
            glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)

            glUniform4fv(col_loc, 1, glm.value_ptr(glm.vec4(d_colour)))

            transformLoc = glGetUniformLocation(shader, "transform")
            glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm.value_ptr(transform))

            glBindVertexArray(VAO)
            glDrawArraysInstanced(GL_TRIANGLES, 0, vertex_len, len_instanced)
            glBindVertexArray(0)

    def obj_shaders(self):
        vertex_obj = """
                                   # version 330
                                    in layout(location = 0) vec3 position;
                                    in layout(location = 1) vec2 textureCoords;
                                    in layout(location = 2) vec3 normalCoords;
                                    in layout (location = 3) mat4 instanceMatrix;

                                    uniform mat4 transform;

                                    uniform mat4 view;
                                    uniform mat4 model;
                                    uniform mat4 projection;

                                    out vec2 newTexture;
                                    out vec3 newNorm;


                                    void main()
                                    {
                                        gl_Position = projection * view *instanceMatrix *model * transform *vec4(position, 1.0f);
                                        newTexture = textureCoords;
                                        newNorm = normalCoords;

                                    }

                                   """
        fragment_obj = """
                                  #version 330
                                    in vec2 newTexture;
                                    in vec3 newNorm;

                                    uniform vec4 mycolor;

                                    out vec4 outColor;
                                    uniform sampler2D samplerTexture;
                                    void main()
                                    {
                                        outColor = mycolor;
                                        }
                                    """
        fragment_obj_text = """
                                          #version 330
                                            in vec2 newTexture;
                                            in vec3 newNorm;
                                            in vec3 out_colours;

                                            uniform vec4 mycolor;

                                            out vec4 outColor;
                                            uniform sampler2D samplerTexture;
                                            void main()
                                            {
                                                outColor = texture(samplerTexture, newTexture);

                                            }
                                            """

        self.shader_obj = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                         compileShader(fragment_obj, GL_FRAGMENT_SHADER))

        self.shader_obj_text = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                              compileShader(fragment_obj_text, GL_FRAGMENT_SHADER))
import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram, compileShader
import os
import glm
from PIL import Image


class ObjLoader:
    def __init__(self):
        self.vert_coords: [float] = []
        self.text_coords: [float] = []
        self.norm_coords: [float] = []
        self.object_parts = {}
        self.setup_index()
        self.obj_shaders()

    def setup_index(self):

        self.material_index: [int] = []
        self.vertex_index: [int] = []
        self.texture_index: [int] = []
        self.normal_index: [int] = []
        self.model = []

    def load_model(self, file, *args):

        for line in open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'v':
                self.vert_coords.append(values[1:4])
            if values[0] == 'vt':
                self.text_coords.append(values[1:3])
            if values[0] == 'vn':
                self.norm_coords.append(values[1:4])
            if values[0] == 'mtllib':
                self.mtl = values[1]
                materials= self.mat_in_file(file)


        m_counter = 0
        for line in open(file, 'r'):  # open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'usemtl':
                if values[1] != materials[m_counter][0]:
                    self.define_i_t_u(file, materials[m_counter], args)
                    m_counter += 1
                    self.setup_index()
            if values[0] == 'f':
                parts = [
                    [
                        int(w) - 1 for w in v.split('/')
                        for w in v.split('/')
                    ]
                    for v in values[1:4]
                ]

                self.vertex_index.append([part[0] for part in parts])
                self.texture_index.append([part[1] for part in parts])
                self.normal_index.append([part[2] for part in parts])

        self.define_i_t_u(file, materials[m_counter], args)

    def get_vertices(values):
        for v in values[1:4]:
            yield int(v.split('/')[0]) - 1

    def define_i_t_u(self, file, mat, args):
        self.vertex_index = [y for x in self.vertex_index for y in x]
        self.texture_index = [y for x in self.texture_index for y in x]
        self.normal_index = [y for x in self.normal_index for y in x]

        for i in self.vertex_index:
            self.model.extend(self.vert_coords[i])
        for i in self.texture_index:
            self.model.extend(self.text_coords[i])
        for i in self.normal_index:
            self.model.extend(self.norm_coords[i])
        self.model = np.array(self.model, dtype='float32')

        glUseProgram(mat[1])
        texid = self.texture_material(file)
        l_vao = self.vao_creator(self.vertex_index, self.model, mat[1], mat[2], texid, args)
        self.object_parts["{0}".format(mat[0])] = l_vao

    def texture_material(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        filepath = os.path.dirname(filename)
        base = os.path.basename(filename)
        file_only_name = os.path.splitext(base)[0]
        contents = {}
        mtl = None
        image = None
        texid = None
        surf = None
        values = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                mtl = contents[values[1]] = {}
            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'map_Kd':
                self.object_shader = self.shader_obj_text
                # load the texture referred to by this declaration
                mtl[values[0]] = values[1]

                texid = mtl['texture_Kd'] = glGenTextures(1)

                glBindTexture(GL_TEXTURE_2D, texid)

                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                                GL_LINEAR)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                                GL_LINEAR)

                image = Image.open(os.path.join(filepath, mtl['map_Kd']))
                flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
                img_data = flipped_image.convert("RGBA").tobytes()
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                             img_data)

        return texid


    def vao_creator(self, vertex_index, model, shader, defuse_col, texid, args):
        texture_offset = len(vertex_index) * 12
        VAO = glGenVertexArrays(1)
        glBindVertexArray(VAO)
        VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, VBO)
        glBufferData(GL_ARRAY_BUFFER, model.itemsize * len(model), model, GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # texture
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, model.itemsize * 2, ctypes.c_void_p(texture_offset))
        glEnableVertexAttribArray(1)
        # Normals
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(12))
        glEnableVertexAttribArray(2)

        # Instancing
        if len(args) == 0:
            amount = 1
            vert_instance = np.array([
                [0.0, 0.0, 0.0]
            ])
        else:
            amount = len(args)
            vert_instance = np.array(args)

        model_matrices = []
        # Storring the objects in a list
        for i in range(0, amount):
            mod_list = []
            model_o = glm.mat4(1.0)
            model_o = glm.translate(model_o, glm.vec3(vert_instance[i][0], vert_instance[i][1], vert_instance[i][2]))
            # model_o = glm.scale(model_o, glm.vec3(0.00005, 0.00005, 0.00005))
            for i in range(4):
                for j in range(4):
                    mod_list.append(model_o[i][j])
            model_matrices.append(mod_list)
        model_matrices = np.array(model_matrices, dtype="f")

        instanceVBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, instanceVBO)

        glBufferData(GL_ARRAY_BUFFER, amount * glm.sizeof(glm.mat4), model_matrices, GL_STATIC_DRAW)
        # Bind each vertex attrib array of matrices (4 vectors in Matrix)
        glEnableVertexAttribArray(3)
        glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(0))
        glEnableVertexAttribArray(4)
        glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(glm.sizeof(glm.vec4)))
        glEnableVertexAttribArray(5)
        glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((2 * glm.sizeof(glm.vec4))))
        glEnableVertexAttribArray(6)
        glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((3 * glm.sizeof(glm.vec4))))
        # Set instancing
        for i in range(3, 7):
            glVertexAttribDivisor(i, 1)

        glBindVertexArray(0)

        return ([VAO, len(vertex_index), shader, defuse_col, texid, len(vert_instance)])

    def mat_in_file(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        mtl = None
        contents = {}
        mat_list = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                object_shader = self.shader_obj
                mtl = contents[values[1]] = {}
                matname = values[1]

            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'Kd':
                defuse_col = [float(values[1]), float(values[2]), float(values[3])]
            elif values[0] == 'd':
                defuse_col = defuse_col + [float(values[1])]
                mat_list.append([matname, object_shader, defuse_col])
            elif values[0] == 'map_Kd':
                object_shader = self.shader_obj_text
                mat_list.pop()
                mat_list.append([matname, object_shader, defuse_col])


        return mat_list

    def load_obj(self):
        obj_list = [self.object_parts[ind] for ind in self.object_parts]
        return obj_list

    def draw_call(self, vao_list, view, projection, model, *transf):

        if len(transf) == 0:
            transform = glm.mat4(1.0)
        else:
            transform = transf[0]

        for key in vao_list:
            VAO = key[0]
            vertex_len = key[1]
            shader = key[2]
            d_colour = key[3]
            texid = key[4]
            len_instanced = key[5]

            glUseProgram(shader)
            glBindTexture(GL_TEXTURE_2D, texid)
            view_loc = glGetUniformLocation(shader, "view")
            proj_loc = glGetUniformLocation(shader, "projection")
            model_loc = glGetUniformLocation(shader, "model")
            col_loc = glGetUniformLocation(shader, "mycolor")

            glUniformMatrix4fv(view_loc, 1, GL_FALSE, view)
            glUniformMatrix4fv(proj_loc, 1, GL_FALSE, projection)
            glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)

            glUniform4fv(col_loc, 1, glm.value_ptr(glm.vec4(d_colour)))

            transformLoc = glGetUniformLocation(shader, "transform")
            glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm.value_ptr(transform))

            glBindVertexArray(VAO)
            glDrawArraysInstanced(GL_TRIANGLES, 0, vertex_len, len_instanced)
            glBindVertexArray(0)

    def obj_shaders(self):
        vertex_obj = """
               # version 330
                in layout(location = 0) vec3 position;
                in layout(location = 1) vec2 textureCoords;
                in layout(location = 2) vec3 normalCoords;
                in layout (location = 3) mat4 instanceMatrix;

                uniform mat4 transform;

                uniform mat4 view;
                uniform mat4 model;
                uniform mat4 projection;

                out vec2 newTexture;
                out vec3 newNorm;


                void main()
                {
                    gl_Position = projection * view *instanceMatrix *model * transform *vec4(position, 1.0f);
                    newTexture = textureCoords;
                    newNorm = normalCoords;

                }

               """
        fragment_obj = """
                  #version 330
                    in vec2 newTexture;
                    in vec3 newNorm;

                    uniform vec4 mycolor;

                    out vec4 outColor;
                    uniform sampler2D samplerTexture;
                    void main()
                    {
                        outColor = mycolor;
                        }
                    """
        fragment_obj_text = """
                  #version 330
                    in vec2 newTexture;
                    in vec3 newNorm;
                    in vec3 out_colours;

                    uniform vec4 mycolor;

                    out vec4 outColor;
                    uniform sampler2D samplerTexture;
                    void main()
                    {
                        outColor = texture(samplerTexture, newTexture);

                    }
                    """

        self.shader_obj = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                         compileShader(fragment_obj, GL_FRAGMENT_SHADER))

        self.shader_obj_text = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                              compileShader(fragment_obj_text, GL_FRAGMENT_SHADER))
import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram, compileShader
import os
import glm
from PIL import Image


class ObjLoader:
    def __init__(self):
        self.vert_coords = []
        self.text_coords = []
        self.norm_coords = []
        self.object_parts = {}
        self.setup_index()
        self.obj_shaders()

    def setup_index(self):

        self.material_index = []
        self.vertex_index = []
        self.texture_index = []
        self.normal_index = []
        self.model = []
        self.material_index = []
        self.vertex_index = []
        self.texture_index = []
        self.normal_index = []

    def load_model(self, file, *args):

        for line in open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'v':
                self.vert_coords.append(values[1:4])
            if values[0] == 'vt':
                self.text_coords.append(values[1:3])
            if values[0] == 'vn':
                self.norm_coords.append(values[1:4])
            if values[0] == 'mtllib':
                self.mtl = values[1]
                matarials = self.mat_in_file(file)


        m_counter = 0
        for line in open(file, 'r'):  # open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'usemtl':
                if values[1] != matarials[m_counter][0]:
                    self.define_i_t_u(file, matarials[m_counter], args)
                    m_counter += 1
                    self.setup_index()
            if values[0] == 'f':
                face_i = []
                text_i = []
                norm_i = []
                for v in values[1:4]:
                    w = v.split('/')
                    face_i.append(int(w[0]) - 1)
                    text_i.append(int(w[1]) - 1)
                    norm_i.append(int(w[2]) - 1)

                self.vertex_index.append(face_i)
                self.texture_index.append(text_i)
                self.normal_index.append(norm_i)

        self.define_i_t_u(file, matarials[m_counter], args)

    def define_i_t_u(self, file, mat, args):
        self.vertex_index = [y for x in self.vertex_index for y in x]
        self.texture_index = [y for x in self.texture_index for y in x]
        self.normal_index = [y for x in self.normal_index for y in x]

        for i in self.vertex_index:
            self.model.extend(self.vert_coords[i])
        for i in self.texture_index:
            self.model.extend(self.text_coords[i])
        for i in self.normal_index:
            self.model.extend(self.norm_coords[i])
        self.model = np.array(self.model, dtype='float32')

        glUseProgram(mat[1])
        texid = self.MTL(file)
        l_vao = self.vao_creator(self.vertex_index, self.model, mat[1], mat[2], texid, args)
        self.object_parts["{0}".format(mat[0])] = l_vao

    def MTL(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        filepath = os.path.dirname(filename)
        base = os.path.basename(filename)
        file_only_name = os.path.splitext(base)[0]
        contents = {}
        mtl = None
        image = None
        texid = None
        surf = None
        values = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                mtl = contents[values[1]] = {}
            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'map_Kd':
                self.object_shader = self.shader_obj_text
                # load the texture referred to by this declaration
                mtl[values[0]] = values[1]

                texid = mtl['texture_Kd'] = glGenTextures(1)

                glBindTexture(GL_TEXTURE_2D, texid)

                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                                GL_LINEAR)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                                GL_LINEAR)

                image = Image.open(os.path.join(filepath, mtl['map_Kd']))
                flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
                img_data = flipped_image.convert("RGBA").tobytes()
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                             img_data)

        return texid


    def vao_creator(self, vertex_index, model, shader, defuse_col, texid, args):
        texture_offset = len(vertex_index) * 12
        VAO = glGenVertexArrays(1)
        glBindVertexArray(VAO)
        VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, VBO)
        glBufferData(GL_ARRAY_BUFFER, model.itemsize * len(model), model, GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # texture
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, model.itemsize * 2, ctypes.c_void_p(texture_offset))
        glEnableVertexAttribArray(1)
        # Normals
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(12))
        glEnableVertexAttribArray(2)

        # Instancing
        if len(args) == 0:
            amount = 1
            vert_instance = np.array([[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]])
        else:
            amount = len(args)
            vert_instance = np.array(args)

        modelMatrices = []
        # Storring the objects in a list
        for i in range(0, amount):
            mod_list = []
            model_o = glm.mat4(1.0)
            model_o = glm.translate(model_o, glm.vec3(vert_instance[i][0], vert_instance[i][1], vert_instance[i][2]))
            # model_o = glm.scale(model_o, glm.vec3(0.00005, 0.00005, 0.00005))
            for i in range(4):
                for j in range(4):
                    mod_list.append(model_o[i][j])
            modelMatrices.append(mod_list)
        modelMatrices = np.array(modelMatrices, dtype="f")

        instanceVBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, instanceVBO)

        glBufferData(GL_ARRAY_BUFFER, amount * glm.sizeof(glm.mat4), modelMatrices, GL_STATIC_DRAW)
        # Bind each vertex attrib array of matrices (4 vectors in Matrix)
        glEnableVertexAttribArray(3)
        glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(0))
        glEnableVertexAttribArray(4)
        glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(glm.sizeof(glm.vec4)))
        glEnableVertexAttribArray(5)
        glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((2 * glm.sizeof(glm.vec4))))
        glEnableVertexAttribArray(6)
        glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((3 * glm.sizeof(glm.vec4))))
        # Set instancing
        glVertexAttribDivisor(3, 1)
        glVertexAttribDivisor(4, 1)
        glVertexAttribDivisor(5, 1)
        glVertexAttribDivisor(6, 1)

        glBindVertexArray(0)

        return ([VAO, len(vertex_index), shader, defuse_col, texid, len(vert_instance)])

    def mat_in_file(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        mtl = None
        contents = {}
        mat_list = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                object_shader = self.shader_obj
                mtl = contents[values[1]] = {}
                matname = values[1]

            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'Kd':
                defuse_col = [float(values[1]), float(values[2]), float(values[3])]
            elif values[0] == 'd':
                defuse_col = defuse_col + [float(values[1])]
                mat_list.append([matname, object_shader, defuse_col])
            elif values[0] == 'map_Kd':
                object_shader = self.shader_obj_text
                mat_list.pop()
                mat_list.append([matname, object_shader, defuse_col])


        return mat_list

    def load_obj(self):
        obj_list = [self.object_parts[ind] for ind in self.object_parts]
        return obj_list

    def draw_call(self, vao_list, view, projection, model, *transf):

        if len(transf) == 0:
            transform = glm.mat4(1.0)
        else:
            transform = transf[0]

        for key in vao_list:
            VAO = key[0]
            vertex_len = key[1]
            shader = key[2]
            d_colour = key[3]
            texid = key[4]
            len_instanced = key[5]

            glUseProgram(shader)
            glBindTexture(GL_TEXTURE_2D, texid)
            view_loc = glGetUniformLocation(shader, "view")
            proj_loc = glGetUniformLocation(shader, "projection")
            model_loc = glGetUniformLocation(shader, "model")
            col_loc = glGetUniformLocation(shader, "mycolor")

            glUniformMatrix4fv(view_loc, 1, GL_FALSE, view)
            glUniformMatrix4fv(proj_loc, 1, GL_FALSE, projection)
            glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)

            glUniform4fv(col_loc, 1, glm.value_ptr(glm.vec4(d_colour)))

            transformLoc = glGetUniformLocation(shader, "transform")
            glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm.value_ptr(transform))

            glBindVertexArray(VAO)
            glDrawArraysInstanced(GL_TRIANGLES, 0, vertex_len, len_instanced)
            glBindVertexArray(0)

    def obj_shaders(self):
        vertex_obj = """
                                   # version 330
                                    in layout(location = 0) vec3 position;
                                    in layout(location = 1) vec2 textureCoords;
                                    in layout(location = 2) vec3 normalCoords;
                                    in layout (location = 3) mat4 instanceMatrix;

                                    uniform mat4 transform;

                                    uniform mat4 view;
                                    uniform mat4 model;
                                    uniform mat4 projection;

                                    out vec2 newTexture;
                                    out vec3 newNorm;


                                    void main()
                                    {
                                        gl_Position = projection * view *instanceMatrix *model * transform *vec4(position, 1.0f);
                                        newTexture = textureCoords;
                                        newNorm = normalCoords;

                                    }

                                   """
        fragment_obj = """
                                  #version 330
                                    in vec2 newTexture;
                                    in vec3 newNorm;

                                    uniform vec4 mycolor;

                                    out vec4 outColor;
                                    uniform sampler2D samplerTexture;
                                    void main()
                                    {
                                        outColor = mycolor;
                                        }
                                    """
        fragment_obj_text = """
                                          #version 330
                                            in vec2 newTexture;
                                            in vec3 newNorm;
                                            in vec3 out_colours;

                                            uniform vec4 mycolor;

                                            out vec4 outColor;
                                            uniform sampler2D samplerTexture;
                                            void main()
                                            {
                                                outColor = texture(samplerTexture, newTexture);

                                            }
                                            """

        self.shader_obj = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                         compileShader(fragment_obj, GL_FRAGMENT_SHADER))

        self.shader_obj_text = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                              compileShader(fragment_obj_text, GL_FRAGMENT_SHADER))
deleted 791 characters in body
Source Link
Kempie
  • 201
  • 2
  • 5
import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram, compileShader
import os
import glm
from PIL import Image


class ObjLoader:
    def __init__(self):
        self.vert_coords: [float] = []
        self.text_coords: [float] = []
        self.norm_coords: [float] = []
        self.object_parts = {}
        self.setup_index()
        self.obj_shaders()

    def setup_index(self):

        self.material_index: [int] = []
        self.vertex_index: [int] = []
        self.texture_index: [int] = []
        self.normal_index: [int] = []
        self.model = []
        self.material_index = []
        self.vertex_index = []
        self.texture_index = []
        self.normal_index = []

    def load_model(self, file, *args):

        for line in open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'v':
                self.vert_coords.append(values[1:4])
            if values[0] == 'vt':
                self.text_coords.append(values[1:3])
            if values[0] == 'vn':
                self.norm_coords.append(values[1:4])
            if values[0] == 'mtllib':
                self.mtl = values[1]
                matarials =materials= self.mat_in_file(file)


        m_counter = 0
        for line in open(file, 'r'):  # open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'usemtl':
                if values[1] != matarials[m_counter][0]materials[m_counter][0]:
                    self.define_i_t_u(file, matarials[m_counter]materials[m_counter], args)
                    m_counter += 1
                    self.setup_index()
            if values[0] == 'f':
                face_iparts = [][
                text_i = []
  [
              norm_i = []
        int(w) - 1 for w in v.split('/')
  for v in values[1:4]:
                   for w =in v.split('/')
                    face_i.append(int(w[0]) - 1)]
                    text_i.append(int(w[1]) - 1)
   for v in values[1:4]
              norm_i.append(int(w[2]) - 1)]

                self.vertex_index.append(face_i[part[0] for part in parts])
                self.texture_index.append(text_i[part[1] for part in parts])
                self.normal_index.append(norm_i[part[2] for part in parts])

        self.define_i_t_u(file, matarials[m_counter]materials[m_counter], args)

    def get_vertices(values):
        for v in values[1:4]:
            yield int(v.split('/')[0]) - 1

    def define_i_t_u(self, file, mat, args):
        self.vertex_index = [y for x in self.vertex_index for y in x]
        self.texture_index = [y for x in self.texture_index for y in x]
        self.normal_index = [y for x in self.normal_index for y in x]

        for i in self.vertex_index:
            self.model.extend(self.vert_coords[i])
        for i in self.texture_index:
            self.model.extend(self.text_coords[i])
        for i in self.normal_index:
            self.model.extend(self.norm_coords[i])
        self.model = np.array(self.model, dtype='float32')

        glUseProgram(mat[1])
        texid = self.MTLtexture_material(file)
        l_vao = self.vao_creator(self.vertex_index, self.model, mat[1], mat[2], texid, args)
        self.object_parts["{0}".format(mat[0])] = l_vao

    def MTLtexture_material(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        filepath = os.path.dirname(filename)
        base = os.path.basename(filename)
        file_only_name = os.path.splitext(base)[0]
        contents = {}
        mtl = None
        image = None
        texid = None
        surf = None
        values = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                mtl = contents[values[1]] = {}
            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'map_Kd':
                self.object_shader = self.shader_obj_text
                # load the texture referred to by this declaration
                mtl[values[0]] = values[1]

                texid = mtl['texture_Kd'] = glGenTextures(1)

                glBindTexture(GL_TEXTURE_2D, texid)

                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                                GL_LINEAR)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                                GL_LINEAR)

                image = Image.open(os.path.join(filepath, mtl['map_Kd']))
                flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
                img_data = flipped_image.convert("RGBA").tobytes()
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                             img_data)

        return texid


    def vao_creator(self, vertex_index, model, shader, defuse_col, texid, args):
        texture_offset = len(vertex_index) * 12
        VAO = glGenVertexArrays(1)
        glBindVertexArray(VAO)
        VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, VBO)
        glBufferData(GL_ARRAY_BUFFER, model.itemsize * len(model), model, GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # texture
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, model.itemsize * 2, ctypes.c_void_p(texture_offset))
        glEnableVertexAttribArray(1)
        # Normals
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(12))
        glEnableVertexAttribArray(2)

        # Instancing
        if len(args) == 0:
            amount = 1
            vert_instance = np.array([[0[
                [0.0, 0.0, 0.0], 
 [1.0, 1.0, 1.0]]         ])
        else:
            amount = len(args)
            vert_instance = np.array(args)

        modelMatricesmodel_matrices = []
        # Storring the objects in a list
        for i in range(0, amount):
            mod_list = []
            model_o = glm.mat4(1.0)
            model_o = glm.translate(model_o, glm.vec3(vert_instance[i][0], vert_instance[i][1], vert_instance[i][2]))
            # model_o = glm.scale(model_o, glm.vec3(0.00005, 0.00005, 0.00005))
            for i in range(4):
                for j in range(4):
                    mod_list.append(model_o[i][j])
            modelMatricesmodel_matrices.append(mod_list)
        modelMatricesmodel_matrices = np.array(modelMatricesmodel_matrices, dtype="f")

        instanceVBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, instanceVBO)

        glBufferData(GL_ARRAY_BUFFER, amount * glm.sizeof(glm.mat4), modelMatricesmodel_matrices, GL_STATIC_DRAW)
        # Bind each vertex attrib array of matrices (4 vectors in Matrix)
        glEnableVertexAttribArray(3)
        glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(0))
        glEnableVertexAttribArray(4)
        glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(glm.sizeof(glm.vec4)))
        glEnableVertexAttribArray(5)
        glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((2 * glm.sizeof(glm.vec4))))
        glEnableVertexAttribArray(6)
        glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((3 * glm.sizeof(glm.vec4))))
        # Set instancing
        glVertexAttribDivisor(3, 1)
     for i in glVertexAttribDivisorrange(43, 17):
        glVertexAttribDivisor(5, 1)
        glVertexAttribDivisor(6i, 1)

        glBindVertexArray(0)

        return ([VAO, len(vertex_index), shader, defuse_col, texid, len(vert_instance)])

    def mat_in_file(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        mtl = None
        contents = {}
        mat_list = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                object_shader = self.shader_obj
                mtl = contents[values[1]] = {}
                matname = values[1]

            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'Kd':
                defuse_col = [float(values[1]), float(values[2]), float(values[3])]
            elif values[0] == 'd':
                defuse_col = defuse_col + [float(values[1])]
                mat_list.append([matname, object_shader, defuse_col])
            elif values[0] == 'map_Kd':
                object_shader = self.shader_obj_text
                mat_list.pop()
                mat_list.append([matname, object_shader, defuse_col])


        return mat_list

    def load_obj(self):
        obj_list = [self.object_parts[ind] for ind in self.object_parts]
        return obj_list

    def draw_call(self, vao_list, view, projection, model, *transf):

        if len(transf) == 0:
            transform = glm.mat4(1.0)
        else:
            transform = transf[0]

        for key in vao_list:
            VAO = key[0]
            vertex_len = key[1]
            shader = key[2]
            d_colour = key[3]
            texid = key[4]
            len_instanced = key[5]

            glUseProgram(shader)
            glBindTexture(GL_TEXTURE_2D, texid)
            view_loc = glGetUniformLocation(shader, "view")
            proj_loc = glGetUniformLocation(shader, "projection")
            model_loc = glGetUniformLocation(shader, "model")
            col_loc = glGetUniformLocation(shader, "mycolor")

            glUniformMatrix4fv(view_loc, 1, GL_FALSE, view)
            glUniformMatrix4fv(proj_loc, 1, GL_FALSE, projection)
            glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)

            glUniform4fv(col_loc, 1, glm.value_ptr(glm.vec4(d_colour)))

            transformLoc = glGetUniformLocation(shader, "transform")
            glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm.value_ptr(transform))

            glBindVertexArray(VAO)
            glDrawArraysInstanced(GL_TRIANGLES, 0, vertex_len, len_instanced)
            glBindVertexArray(0)

    def obj_shaders(self):
        vertex_obj = """
                                   # version 330
                                    in layout(location = 0) vec3 position;
                                    in layout(location = 1) vec2 textureCoords;
                                    in layout(location = 2) vec3 normalCoords;
                                    in layout (location = 3) mat4 instanceMatrix;

                                    uniform mat4 transform;

                                    uniform mat4 view;
                                    uniform mat4 model;
                                    uniform mat4 projection;

                                    out vec2 newTexture;
                                    out vec3 newNorm;


                                    void main()
                                    {
                                        gl_Position = projection * view *instanceMatrix *model * transform *vec4(position, 1.0f);
                                        newTexture = textureCoords;
                                        newNorm = normalCoords;

                                    }

                                   """
        fragment_obj = """
                                  #version 330
                                    in vec2 newTexture;
                                    in vec3 newNorm;

                                    uniform vec4 mycolor;

                                    out vec4 outColor;
                                    uniform sampler2D samplerTexture;
                                    void main()
                                    {
                                        outColor = mycolor;
                                        }
                                    """
        fragment_obj_text = """
                                          #version 330
                                            in vec2 newTexture;
                                            in vec3 newNorm;
                                            in vec3 out_colours;

                                            uniform vec4 mycolor;

                                            out vec4 outColor;
                                            uniform sampler2D samplerTexture;
                                            void main()
                                            {
                                                outColor = texture(samplerTexture, newTexture);

                                            }
                                            """

        self.shader_obj = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                         compileShader(fragment_obj, GL_FRAGMENT_SHADER))

        self.shader_obj_text = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                              compileShader(fragment_obj_text, GL_FRAGMENT_SHADER))
import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram, compileShader
import os
import glm
from PIL import Image


class ObjLoader:
    def __init__(self):
        self.vert_coords = []
        self.text_coords = []
        self.norm_coords = []
        self.object_parts = {}
        self.setup_index()
        self.obj_shaders()

    def setup_index(self):

        self.material_index = []
        self.vertex_index = []
        self.texture_index = []
        self.normal_index = []
        self.model = []
        self.material_index = []
        self.vertex_index = []
        self.texture_index = []
        self.normal_index = []

    def load_model(self, file, *args):

        for line in open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'v':
                self.vert_coords.append(values[1:4])
            if values[0] == 'vt':
                self.text_coords.append(values[1:3])
            if values[0] == 'vn':
                self.norm_coords.append(values[1:4])
            if values[0] == 'mtllib':
                self.mtl = values[1]
                matarials = self.mat_in_file(file)


        m_counter = 0
        for line in open(file, 'r'):  # open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'usemtl':
                if values[1] != matarials[m_counter][0]:
                    self.define_i_t_u(file, matarials[m_counter], args)
                    m_counter += 1
                    self.setup_index()
            if values[0] == 'f':
                face_i = []
                text_i = []
                norm_i = []
                for v in values[1:4]:
                    w = v.split('/')
                    face_i.append(int(w[0]) - 1)
                    text_i.append(int(w[1]) - 1)
                    norm_i.append(int(w[2]) - 1)

                self.vertex_index.append(face_i)
                self.texture_index.append(text_i)
                self.normal_index.append(norm_i)

        self.define_i_t_u(file, matarials[m_counter], args)

    def define_i_t_u(self, file, mat, args):
        self.vertex_index = [y for x in self.vertex_index for y in x]
        self.texture_index = [y for x in self.texture_index for y in x]
        self.normal_index = [y for x in self.normal_index for y in x]

        for i in self.vertex_index:
            self.model.extend(self.vert_coords[i])
        for i in self.texture_index:
            self.model.extend(self.text_coords[i])
        for i in self.normal_index:
            self.model.extend(self.norm_coords[i])
        self.model = np.array(self.model, dtype='float32')

        glUseProgram(mat[1])
        texid = self.MTL(file)
        l_vao = self.vao_creator(self.vertex_index, self.model, mat[1], mat[2], texid, args)
        self.object_parts["{0}".format(mat[0])] = l_vao

    def MTL(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        filepath = os.path.dirname(filename)
        base = os.path.basename(filename)
        file_only_name = os.path.splitext(base)[0]
        contents = {}
        mtl = None
        image = None
        texid = None
        surf = None
        values = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                mtl = contents[values[1]] = {}
            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'map_Kd':
                self.object_shader = self.shader_obj_text
                # load the texture referred to by this declaration
                mtl[values[0]] = values[1]

                texid = mtl['texture_Kd'] = glGenTextures(1)

                glBindTexture(GL_TEXTURE_2D, texid)

                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                                GL_LINEAR)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                                GL_LINEAR)

                image = Image.open(os.path.join(filepath, mtl['map_Kd']))
                flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
                img_data = flipped_image.convert("RGBA").tobytes()
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                             img_data)

        return texid


    def vao_creator(self, vertex_index, model, shader, defuse_col, texid, args):
        texture_offset = len(vertex_index) * 12
        VAO = glGenVertexArrays(1)
        glBindVertexArray(VAO)
        VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, VBO)
        glBufferData(GL_ARRAY_BUFFER, model.itemsize * len(model), model, GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # texture
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, model.itemsize * 2, ctypes.c_void_p(texture_offset))
        glEnableVertexAttribArray(1)
        # Normals
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(12))
        glEnableVertexAttribArray(2)

        # Instancing
        if len(args) == 0:
            amount = 1
            vert_instance = np.array([[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]])
        else:
            amount = len(args)
            vert_instance = np.array(args)

        modelMatrices = []
        # Storring the objects in a list
        for i in range(0, amount):
            mod_list = []
            model_o = glm.mat4(1.0)
            model_o = glm.translate(model_o, glm.vec3(vert_instance[i][0], vert_instance[i][1], vert_instance[i][2]))
            # model_o = glm.scale(model_o, glm.vec3(0.00005, 0.00005, 0.00005))
            for i in range(4):
                for j in range(4):
                    mod_list.append(model_o[i][j])
            modelMatrices.append(mod_list)
        modelMatrices = np.array(modelMatrices, dtype="f")

        instanceVBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, instanceVBO)

        glBufferData(GL_ARRAY_BUFFER, amount * glm.sizeof(glm.mat4), modelMatrices, GL_STATIC_DRAW)
        # Bind each vertex attrib array of matrices (4 vectors in Matrix)
        glEnableVertexAttribArray(3)
        glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(0))
        glEnableVertexAttribArray(4)
        glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(glm.sizeof(glm.vec4)))
        glEnableVertexAttribArray(5)
        glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((2 * glm.sizeof(glm.vec4))))
        glEnableVertexAttribArray(6)
        glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((3 * glm.sizeof(glm.vec4))))
        # Set instancing
        glVertexAttribDivisor(3, 1)
        glVertexAttribDivisor(4, 1)
        glVertexAttribDivisor(5, 1)
        glVertexAttribDivisor(6, 1)

        glBindVertexArray(0)

        return ([VAO, len(vertex_index), shader, defuse_col, texid, len(vert_instance)])

    def mat_in_file(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        mtl = None
        contents = {}
        mat_list = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                object_shader = self.shader_obj
                mtl = contents[values[1]] = {}
                matname = values[1]

            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'Kd':
                defuse_col = [float(values[1]), float(values[2]), float(values[3])]
            elif values[0] == 'd':
                defuse_col = defuse_col + [float(values[1])]
                mat_list.append([matname, object_shader, defuse_col])
            elif values[0] == 'map_Kd':
                object_shader = self.shader_obj_text
                mat_list.pop()
                mat_list.append([matname, object_shader, defuse_col])


        return mat_list

    def load_obj(self):
        obj_list = [self.object_parts[ind] for ind in self.object_parts]
        return obj_list

    def draw_call(self, vao_list, view, projection, model, *transf):

        if len(transf) == 0:
            transform = glm.mat4(1.0)
        else:
            transform = transf[0]

        for key in vao_list:
            VAO = key[0]
            vertex_len = key[1]
            shader = key[2]
            d_colour = key[3]
            texid = key[4]
            len_instanced = key[5]

            glUseProgram(shader)
            glBindTexture(GL_TEXTURE_2D, texid)
            view_loc = glGetUniformLocation(shader, "view")
            proj_loc = glGetUniformLocation(shader, "projection")
            model_loc = glGetUniformLocation(shader, "model")
            col_loc = glGetUniformLocation(shader, "mycolor")

            glUniformMatrix4fv(view_loc, 1, GL_FALSE, view)
            glUniformMatrix4fv(proj_loc, 1, GL_FALSE, projection)
            glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)

            glUniform4fv(col_loc, 1, glm.value_ptr(glm.vec4(d_colour)))

            transformLoc = glGetUniformLocation(shader, "transform")
            glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm.value_ptr(transform))

            glBindVertexArray(VAO)
            glDrawArraysInstanced(GL_TRIANGLES, 0, vertex_len, len_instanced)
            glBindVertexArray(0)

    def obj_shaders(self):
        vertex_obj = """
                                   # version 330
                                    in layout(location = 0) vec3 position;
                                    in layout(location = 1) vec2 textureCoords;
                                    in layout(location = 2) vec3 normalCoords;
                                    in layout (location = 3) mat4 instanceMatrix;

                                    uniform mat4 transform;

                                    uniform mat4 view;
                                    uniform mat4 model;
                                    uniform mat4 projection;

                                    out vec2 newTexture;
                                    out vec3 newNorm;


                                    void main()
                                    {
                                        gl_Position = projection * view *instanceMatrix *model * transform *vec4(position, 1.0f);
                                        newTexture = textureCoords;
                                        newNorm = normalCoords;

                                    }

                                   """
        fragment_obj = """
                                  #version 330
                                    in vec2 newTexture;
                                    in vec3 newNorm;

                                    uniform vec4 mycolor;

                                    out vec4 outColor;
                                    uniform sampler2D samplerTexture;
                                    void main()
                                    {
                                        outColor = mycolor;
                                        }
                                    """
        fragment_obj_text = """
                                          #version 330
                                            in vec2 newTexture;
                                            in vec3 newNorm;
                                            in vec3 out_colours;

                                            uniform vec4 mycolor;

                                            out vec4 outColor;
                                            uniform sampler2D samplerTexture;
                                            void main()
                                            {
                                                outColor = texture(samplerTexture, newTexture);

                                            }
                                            """

        self.shader_obj = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                         compileShader(fragment_obj, GL_FRAGMENT_SHADER))

        self.shader_obj_text = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                              compileShader(fragment_obj_text, GL_FRAGMENT_SHADER))
import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram, compileShader
import os
import glm
from PIL import Image


class ObjLoader:
    def __init__(self):
        self.vert_coords: [float] = []
        self.text_coords: [float] = []
        self.norm_coords: [float] = []
        self.object_parts = {}
        self.setup_index()
        self.obj_shaders()

    def setup_index(self):

        self.material_index: [int] = []
        self.vertex_index: [int] = []
        self.texture_index: [int] = []
        self.normal_index: [int] = []
        self.model = []

    def load_model(self, file, *args):

        for line in open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'v':
                self.vert_coords.append(values[1:4])
            if values[0] == 'vt':
                self.text_coords.append(values[1:3])
            if values[0] == 'vn':
                self.norm_coords.append(values[1:4])
            if values[0] == 'mtllib':
                self.mtl = values[1]
                materials= self.mat_in_file(file)


        m_counter = 0
        for line in open(file, 'r'):  # open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'usemtl':
                if values[1] != materials[m_counter][0]:
                    self.define_i_t_u(file, materials[m_counter], args)
                    m_counter += 1
                    self.setup_index()
            if values[0] == 'f':
                parts = [
                    [
                        int(w) - 1 for w in v.split('/')
                        for w in v.split('/')
                    ]
                    for v in values[1:4]
                ]

                self.vertex_index.append([part[0] for part in parts])
                self.texture_index.append([part[1] for part in parts])
                self.normal_index.append([part[2] for part in parts])

        self.define_i_t_u(file, materials[m_counter], args)

    def get_vertices(values):
        for v in values[1:4]:
            yield int(v.split('/')[0]) - 1

    def define_i_t_u(self, file, mat, args):
        self.vertex_index = [y for x in self.vertex_index for y in x]
        self.texture_index = [y for x in self.texture_index for y in x]
        self.normal_index = [y for x in self.normal_index for y in x]

        for i in self.vertex_index:
            self.model.extend(self.vert_coords[i])
        for i in self.texture_index:
            self.model.extend(self.text_coords[i])
        for i in self.normal_index:
            self.model.extend(self.norm_coords[i])
        self.model = np.array(self.model, dtype='float32')

        glUseProgram(mat[1])
        texid = self.texture_material(file)
        l_vao = self.vao_creator(self.vertex_index, self.model, mat[1], mat[2], texid, args)
        self.object_parts["{0}".format(mat[0])] = l_vao

    def texture_material(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        filepath = os.path.dirname(filename)
        base = os.path.basename(filename)
        file_only_name = os.path.splitext(base)[0]
        contents = {}
        mtl = None
        image = None
        texid = None
        surf = None
        values = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                mtl = contents[values[1]] = {}
            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'map_Kd':
                self.object_shader = self.shader_obj_text
                # load the texture referred to by this declaration
                mtl[values[0]] = values[1]

                texid = mtl['texture_Kd'] = glGenTextures(1)

                glBindTexture(GL_TEXTURE_2D, texid)

                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                                GL_LINEAR)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                                GL_LINEAR)

                image = Image.open(os.path.join(filepath, mtl['map_Kd']))
                flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
                img_data = flipped_image.convert("RGBA").tobytes()
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                             img_data)

        return texid


    def vao_creator(self, vertex_index, model, shader, defuse_col, texid, args):
        texture_offset = len(vertex_index) * 12
        VAO = glGenVertexArrays(1)
        glBindVertexArray(VAO)
        VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, VBO)
        glBufferData(GL_ARRAY_BUFFER, model.itemsize * len(model), model, GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # texture
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, model.itemsize * 2, ctypes.c_void_p(texture_offset))
        glEnableVertexAttribArray(1)
        # Normals
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, model.itemsize * 3, ctypes.c_void_p(12))
        glEnableVertexAttribArray(2)

        # Instancing
        if len(args) == 0:
            amount = 1
            vert_instance = np.array([
                [0.0, 0.0, 0.0] 
            ])
        else:
            amount = len(args)
            vert_instance = np.array(args)

        model_matrices = []
        # Storring the objects in a list
        for i in range(0, amount):
            mod_list = []
            model_o = glm.mat4(1.0)
            model_o = glm.translate(model_o, glm.vec3(vert_instance[i][0], vert_instance[i][1], vert_instance[i][2]))
            # model_o = glm.scale(model_o, glm.vec3(0.00005, 0.00005, 0.00005))
            for i in range(4):
                for j in range(4):
                    mod_list.append(model_o[i][j])
            model_matrices.append(mod_list)
        model_matrices = np.array(model_matrices, dtype="f")

        instanceVBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, instanceVBO)

        glBufferData(GL_ARRAY_BUFFER, amount * glm.sizeof(glm.mat4), model_matrices, GL_STATIC_DRAW)
        # Bind each vertex attrib array of matrices (4 vectors in Matrix)
        glEnableVertexAttribArray(3)
        glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(0))
        glEnableVertexAttribArray(4)
        glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4), ctypes.c_void_p(glm.sizeof(glm.vec4)))
        glEnableVertexAttribArray(5)
        glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((2 * glm.sizeof(glm.vec4))))
        glEnableVertexAttribArray(6)
        glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, glm.sizeof(glm.mat4),
                              ctypes.c_void_p((3 * glm.sizeof(glm.vec4))))
        # Set instancing
        for i in range(3, 7):
            glVertexAttribDivisor(i, 1)

        glBindVertexArray(0)

        return ([VAO, len(vertex_index), shader, defuse_col, texid, len(vert_instance)])

    def mat_in_file(self, filename):
        filename = os.path.splitext(filename)[0] + '.mtl'
        mtl = None
        contents = {}
        mat_list = []
        for line in open(filename, "r"):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                object_shader = self.shader_obj
                mtl = contents[values[1]] = {}
                matname = values[1]

            elif mtl is None:
                raise ValueError("mtl file doesn't start with newmtl stmt")
            elif values[0] == 'Kd':
                defuse_col = [float(values[1]), float(values[2]), float(values[3])]
            elif values[0] == 'd':
                defuse_col = defuse_col + [float(values[1])]
                mat_list.append([matname, object_shader, defuse_col])
            elif values[0] == 'map_Kd':
                object_shader = self.shader_obj_text
                mat_list.pop()
                mat_list.append([matname, object_shader, defuse_col])


        return mat_list

    def load_obj(self):
        obj_list = [self.object_parts[ind] for ind in self.object_parts]
        return obj_list

    def draw_call(self, vao_list, view, projection, model, *transf):

        if len(transf) == 0:
            transform = glm.mat4(1.0)
        else:
            transform = transf[0]

        for key in vao_list:
            VAO = key[0]
            vertex_len = key[1]
            shader = key[2]
            d_colour = key[3]
            texid = key[4]
            len_instanced = key[5]

            glUseProgram(shader)
            glBindTexture(GL_TEXTURE_2D, texid)
            view_loc = glGetUniformLocation(shader, "view")
            proj_loc = glGetUniformLocation(shader, "projection")
            model_loc = glGetUniformLocation(shader, "model")
            col_loc = glGetUniformLocation(shader, "mycolor")

            glUniformMatrix4fv(view_loc, 1, GL_FALSE, view)
            glUniformMatrix4fv(proj_loc, 1, GL_FALSE, projection)
            glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)

            glUniform4fv(col_loc, 1, glm.value_ptr(glm.vec4(d_colour)))

            transformLoc = glGetUniformLocation(shader, "transform")
            glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm.value_ptr(transform))

            glBindVertexArray(VAO)
            glDrawArraysInstanced(GL_TRIANGLES, 0, vertex_len, len_instanced)
            glBindVertexArray(0)

    def obj_shaders(self):
        vertex_obj = """
               # version 330
                in layout(location = 0) vec3 position;
                in layout(location = 1) vec2 textureCoords;
                in layout(location = 2) vec3 normalCoords;
                in layout (location = 3) mat4 instanceMatrix;

                uniform mat4 transform;

                uniform mat4 view;
                uniform mat4 model;
                uniform mat4 projection;

                out vec2 newTexture;
                out vec3 newNorm;


                void main()
                {
                    gl_Position = projection * view *instanceMatrix *model * transform *vec4(position, 1.0f);
                    newTexture = textureCoords;
                    newNorm = normalCoords;

                }

               """
        fragment_obj = """
                  #version 330
                    in vec2 newTexture;
                    in vec3 newNorm;

                    uniform vec4 mycolor;

                    out vec4 outColor;
                    uniform sampler2D samplerTexture;
                    void main()
                    {
                        outColor = mycolor;
                        }
                    """
        fragment_obj_text = """
                  #version 330
                    in vec2 newTexture;
                    in vec3 newNorm;
                    in vec3 out_colours;

                    uniform vec4 mycolor;

                    out vec4 outColor;
                    uniform sampler2D samplerTexture;
                    void main()
                    {
                        outColor = texture(samplerTexture, newTexture);

                    }
                    """

        self.shader_obj = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                         compileShader(fragment_obj, GL_FRAGMENT_SHADER))

        self.shader_obj_text = compileProgram(compileShader(vertex_obj, GL_VERTEX_SHADER),
                                              compileShader(fragment_obj_text, GL_FRAGMENT_SHADER))
Partial rollback, and improvement, of grammatically incorrect edit.
Source Link
Peilonrayz
  • 43.5k
  • 7
  • 76
  • 155
Loading
deleted 2 characters in body
Source Link
Kempie
  • 201
  • 2
  • 5
Loading
Spelling correction
Source Link
Kempie
  • 201
  • 2
  • 5
Loading
Source Link
Kempie
  • 201
  • 2
  • 5
Loading