Removed shaders, textures are now supported
This commit is contained in:
parent
85c14c8b09
commit
1443ea35ba
|
@ -4,6 +4,8 @@ from math import sqrt
|
||||||
|
|
||||||
from ..geometry import Vector
|
from ..geometry import Vector
|
||||||
|
|
||||||
|
from .mesh import Material, MeshPart
|
||||||
|
|
||||||
Vertex = Vector
|
Vertex = Vector
|
||||||
Normal = Vertex
|
Normal = Vertex
|
||||||
TexCoord = Vertex
|
TexCoord = Vertex
|
||||||
|
@ -43,22 +45,14 @@ class Face:
|
||||||
self.c = FaceVertex().from_array(arr[2])
|
self.c = FaceVertex().from_array(arr[2])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class Material:
|
|
||||||
def __init__(self, name):
|
|
||||||
self.name = name
|
|
||||||
self.Ka = None
|
|
||||||
self.Kd = None
|
|
||||||
self.Ks = None
|
|
||||||
self.map_Kd = None
|
|
||||||
|
|
||||||
|
|
||||||
class ModelParser:
|
class ModelParser:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.vertices = []
|
self.vertices = []
|
||||||
self.normals = []
|
self.normals = []
|
||||||
self.tex_coords = []
|
self.tex_coords = []
|
||||||
self.faces = []
|
self.parts = []
|
||||||
|
self.current_part = None
|
||||||
self.bounding_box = BoundingBox()
|
self.bounding_box = BoundingBox()
|
||||||
self.center_and_scale = True
|
self.center_and_scale = True
|
||||||
self.vertex_vbo = None
|
self.vertex_vbo = None
|
||||||
|
@ -66,6 +60,10 @@ class ModelParser:
|
||||||
self.normal_vbo = None
|
self.normal_vbo = None
|
||||||
self.path = None
|
self.path = None
|
||||||
|
|
||||||
|
def init_textures(self):
|
||||||
|
for part in self.parts:
|
||||||
|
part.init_texture()
|
||||||
|
|
||||||
def add_vertex(self, vertex):
|
def add_vertex(self, vertex):
|
||||||
self.vertices.append(vertex)
|
self.vertices.append(vertex)
|
||||||
self.bounding_box.add(vertex)
|
self.bounding_box.add(vertex)
|
||||||
|
@ -77,7 +75,12 @@ class ModelParser:
|
||||||
self.normals.append(normal)
|
self.normals.append(normal)
|
||||||
|
|
||||||
def add_face(self, face):
|
def add_face(self, face):
|
||||||
self.faces.append(face)
|
if self.current_part is None or face.material != self.current_part.material:
|
||||||
|
self.current_part = MeshPart(self)
|
||||||
|
self.current_part.material = face.material
|
||||||
|
self.parts.append(self.current_part)
|
||||||
|
|
||||||
|
self.current_part.add_face(face)
|
||||||
|
|
||||||
def parse_line(self, string):
|
def parse_line(self, string):
|
||||||
pass
|
pass
|
||||||
|
@ -90,11 +93,8 @@ class ModelParser:
|
||||||
self.parse_line(line)
|
self.parse_line(line)
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
|
|
||||||
import OpenGL.GL as gl
|
import OpenGL.GL as gl
|
||||||
|
|
||||||
gl.glColor3f(1.0,0.0,0.0)
|
|
||||||
|
|
||||||
if self.center_and_scale:
|
if self.center_and_scale:
|
||||||
center = self.bounding_box.get_center()
|
center = self.bounding_box.get_center()
|
||||||
scale = self.bounding_box.get_scale() / 2
|
scale = self.bounding_box.get_scale() / 2
|
||||||
|
@ -102,104 +102,43 @@ class ModelParser:
|
||||||
gl.glScalef(1/scale, 1/scale, 1/scale)
|
gl.glScalef(1/scale, 1/scale, 1/scale)
|
||||||
gl.glTranslatef(-center.x, -center.y, -center.z)
|
gl.glTranslatef(-center.x, -center.y, -center.z)
|
||||||
|
|
||||||
if self.vertex_vbo is not None:
|
for part in self.parts:
|
||||||
|
part.draw()
|
||||||
self.vertex_vbo.bind()
|
|
||||||
gl.glEnableClientState(gl.GL_VERTEX_ARRAY);
|
|
||||||
gl.glVertexPointerf(self.vertex_vbo)
|
|
||||||
self.vertex_vbo.unbind()
|
|
||||||
|
|
||||||
self.normal_vbo.bind()
|
|
||||||
gl.glEnableClientState(gl.GL_NORMAL_ARRAY);
|
|
||||||
gl.glNormalPointerf(self.normal_vbo)
|
|
||||||
self.normal_vbo.unbind()
|
|
||||||
|
|
||||||
gl.glDrawArrays(gl.GL_TRIANGLES, 0, len(self.vertex_vbo.data) * 9)
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
gl.glBegin(gl.GL_TRIANGLES)
|
|
||||||
for face in self.faces:
|
|
||||||
v1 = self.vertices[face.a.vertex]
|
|
||||||
v2 = self.vertices[face.b.vertex]
|
|
||||||
v3 = self.vertices[face.c.vertex]
|
|
||||||
|
|
||||||
if face.a.normal is not None:
|
|
||||||
n1 = self.normals[face.a.normal]
|
|
||||||
n2 = self.normals[face.b.normal]
|
|
||||||
n3 = self.normals[face.c.normal]
|
|
||||||
|
|
||||||
if face.a.normal is not None:
|
|
||||||
gl.glNormal3f(n1.x, n1.y, n1.z)
|
|
||||||
gl.glVertex3f(v1.x, v1.y, v1.z)
|
|
||||||
|
|
||||||
if face.b.normal is not None:
|
|
||||||
gl.glNormal3f(n2.x, n2.y, n2.z)
|
|
||||||
gl.glVertex3f(v2.x, v2.y, v2.z)
|
|
||||||
|
|
||||||
if face.c.normal is not None:
|
|
||||||
gl.glNormal3f(n3.x, n3.y, n3.z)
|
|
||||||
gl.glVertex3f(v3.x, v3.y, v3.z)
|
|
||||||
|
|
||||||
gl.glEnd()
|
|
||||||
|
|
||||||
if self.center_and_scale:
|
if self.center_and_scale:
|
||||||
gl.glPopMatrix()
|
gl.glPopMatrix()
|
||||||
|
|
||||||
def generate_vbos(self):
|
def generate_vbos(self):
|
||||||
from OpenGL.arrays import vbo
|
for part in self.parts:
|
||||||
from numpy import array
|
part.generate_vbos()
|
||||||
# Build VBO
|
|
||||||
v = []
|
|
||||||
n = []
|
|
||||||
t = []
|
|
||||||
|
|
||||||
for face in self.faces:
|
|
||||||
v1 = self.vertices[face.a.vertex]
|
|
||||||
v2 = self.vertices[face.b.vertex]
|
|
||||||
v3 = self.vertices[face.c.vertex]
|
|
||||||
v += [[v1.x, v1.y, v1.z], [v2.x, v2.y, v2.z], [v3.x, v3.y, v3.z]]
|
|
||||||
|
|
||||||
if face.a.normal is not None:
|
|
||||||
n1 = self.normals[face.a.normal]
|
|
||||||
n2 = self.normals[face.b.normal]
|
|
||||||
n3 = self.normals[face.c.normal]
|
|
||||||
n += [[n1.x, n1.y, n1.z], [n2.x, n2.y, n2.z], [n3.x, n3.y, n3.z]]
|
|
||||||
|
|
||||||
if face.a.tex_coord is not None:
|
|
||||||
t1 = self.tex_coords[face.a.tex_coord]
|
|
||||||
t2 = self.tex_coords[face.b.tex_coord]
|
|
||||||
t3 = self.tex_coords[face.c.tex_coord]
|
|
||||||
t += [[t1.x, t1.y], [t2.x, t2.y], [t3.x, t3.y]]
|
|
||||||
|
|
||||||
self.vertex_vbo = vbo.VBO(array(v, 'f'))
|
|
||||||
self.normal_vbo = vbo.VBO(array(n, 'f'))
|
|
||||||
self.texture_vbo = vbo.VBO(array(t, 'f'))
|
|
||||||
|
|
||||||
def generate_vertex_normals(self):
|
def generate_vertex_normals(self):
|
||||||
|
|
||||||
self.normals = [Normal() for i in self.vertices]
|
self.normals = [Normal() for i in self.vertices]
|
||||||
|
|
||||||
for face in self.faces:
|
for part in self.parts:
|
||||||
v1 = Vertex.from_points(self.vertices[face.a.vertex], self.vertices[face.b.vertex])
|
for face in part.faces:
|
||||||
v2 = Vertex.from_points(self.vertices[face.a.vertex], self.vertices[face.c.vertex])
|
v1 = Vertex.from_points(self.vertices[face.a.vertex], self.vertices[face.b.vertex])
|
||||||
cross = Vertex.cross_product(v1, v2)
|
v2 = Vertex.from_points(self.vertices[face.a.vertex], self.vertices[face.c.vertex])
|
||||||
self.normals[face.a.vertex] += cross
|
cross = Vertex.cross_product(v1, v2)
|
||||||
self.normals[face.b.vertex] += cross
|
self.normals[face.a.vertex] += cross
|
||||||
self.normals[face.c.vertex] += cross
|
self.normals[face.b.vertex] += cross
|
||||||
|
self.normals[face.c.vertex] += cross
|
||||||
|
|
||||||
for normal in self.normals:
|
for normal in self.normals:
|
||||||
normal.normalize()
|
normal.normalize()
|
||||||
|
|
||||||
for face in self.faces:
|
for part in self.parts:
|
||||||
face.a.normal = face.a.vertex
|
for face in part.faces:
|
||||||
face.b.normal = face.b.vertex
|
face.a.normal = face.a.vertex
|
||||||
face.c.normal = face.c.vertex
|
face.b.normal = face.b.vertex
|
||||||
|
face.c.normal = face.c.vertex
|
||||||
|
|
||||||
def generate_face_normals(self):
|
def generate_face_normals(self):
|
||||||
|
|
||||||
self.normals = [Normal() for i in self.faces]
|
self.normals = [Normal() for i in sum(list(map(lambda x: len(x), self.faces)))]
|
||||||
|
|
||||||
for (index, face) in enumerate(self.faces):
|
for (index, face) in enumerate(sum(self.faces, [])):
|
||||||
|
|
||||||
v1 = Vertex.from_points(self.vertices[face.a.vertex], self.vertices[face.b.vertex])
|
v1 = Vertex.from_points(self.vertices[face.a.vertex], self.vertices[face.b.vertex])
|
||||||
v2 = Vertex.from_points(self.vertices[face.a.vertex], self.vertices[face.c.vertex])
|
v2 = Vertex.from_points(self.vertices[face.a.vertex], self.vertices[face.c.vertex])
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
class Material:
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
self.Ka = None
|
||||||
|
self.Kd = None
|
||||||
|
self.Ks = None
|
||||||
|
self.map_Kd = None
|
||||||
|
self.id = None
|
||||||
|
|
||||||
|
def init_texture(self):
|
||||||
|
|
||||||
|
import OpenGL.GL as gl
|
||||||
|
|
||||||
|
# Already initialized
|
||||||
|
if self.id is not None:
|
||||||
|
return
|
||||||
|
|
||||||
|
# If no map_Kd, nothing to do
|
||||||
|
if self.map_Kd is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
ix, iy, image = self.map_Kd.size[0], self.map_Kd.size[1], self.map_Kd.tobytes("raw", "RGBA", 0, -1)
|
||||||
|
except SystemError:
|
||||||
|
ix, iy, image = self.map_Kd.size[0], self.map_Kd.size[1], self.map_Kd.tobytes("raw", "RGBX", 0, -1)
|
||||||
|
|
||||||
|
self.id = gl.glGenTextures(1)
|
||||||
|
|
||||||
|
gl.glBindTexture(gl.GL_TEXTURE_2D, self.id)
|
||||||
|
gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT,1)
|
||||||
|
|
||||||
|
gl.glTexImage2D(
|
||||||
|
gl.GL_TEXTURE_2D, 0, 3, ix, iy, 0,
|
||||||
|
gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, image
|
||||||
|
)
|
||||||
|
|
||||||
|
def bind(self):
|
||||||
|
from OpenGL import GL as gl
|
||||||
|
|
||||||
|
gl.glEnable(gl.GL_TEXTURE_2D)
|
||||||
|
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST)
|
||||||
|
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST)
|
||||||
|
gl.glTexEnvf(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_DECAL)
|
||||||
|
gl.glBindTexture(gl.GL_TEXTURE_2D, self.id)
|
||||||
|
|
||||||
|
def unbind(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MeshPart:
|
||||||
|
def __init__(self, parent):
|
||||||
|
self.parent = parent
|
||||||
|
self.material = None
|
||||||
|
self.vertex_vbo = None
|
||||||
|
self.tex_coord_vbo = None
|
||||||
|
self.normal_vbo = None
|
||||||
|
self.faces = []
|
||||||
|
|
||||||
|
def init_texture(self):
|
||||||
|
if self.material is not None:
|
||||||
|
self.material.init_texture()
|
||||||
|
|
||||||
|
def add_face(self, face):
|
||||||
|
self.faces.append(face)
|
||||||
|
|
||||||
|
def generate_vbos(self):
|
||||||
|
|
||||||
|
from OpenGL.arrays import vbo
|
||||||
|
from numpy import array
|
||||||
|
|
||||||
|
# Build VBO
|
||||||
|
v = []
|
||||||
|
n = []
|
||||||
|
t = []
|
||||||
|
|
||||||
|
for face in self.faces:
|
||||||
|
v1 = self.parent.vertices[face.a.vertex]
|
||||||
|
v2 = self.parent.vertices[face.b.vertex]
|
||||||
|
v3 = self.parent.vertices[face.c.vertex]
|
||||||
|
v += [[v1.x, v1.y, v1.z], [v2.x, v2.y, v2.z], [v3.x, v3.y, v3.z]]
|
||||||
|
|
||||||
|
if face.a.normal is not None:
|
||||||
|
n1 = self.parent.normals[face.a.normal]
|
||||||
|
n2 = self.parent.normals[face.b.normal]
|
||||||
|
n3 = self.parent.normals[face.c.normal]
|
||||||
|
n += [[n1.x, n1.y, n1.z], [n2.x, n2.y, n2.z], [n3.x, n3.y, n3.z]]
|
||||||
|
|
||||||
|
if face.a.tex_coord is not None:
|
||||||
|
t1 = self.parent.tex_coords[face.a.tex_coord]
|
||||||
|
t2 = self.parent.tex_coords[face.b.tex_coord]
|
||||||
|
t3 = self.parent.tex_coords[face.c.tex_coord]
|
||||||
|
t += [[t1.x, t1.y], [t2.x, t2.y], [t3.x, t3.y]]
|
||||||
|
|
||||||
|
self.vertex_vbo = vbo.VBO(array(v, 'f'))
|
||||||
|
|
||||||
|
if len(n) > 0:
|
||||||
|
self.normal_vbo = vbo.VBO(array(n, 'f'))
|
||||||
|
|
||||||
|
if len(t) > 0:
|
||||||
|
self.tex_coord_vbo = vbo.VBO(array(t, 'f'))
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
|
||||||
|
if self.material is not None:
|
||||||
|
self.material.bind()
|
||||||
|
|
||||||
|
if self.vertex_vbo is not None:
|
||||||
|
self.draw_from_vbos()
|
||||||
|
else:
|
||||||
|
self.draw_from_arrays()
|
||||||
|
|
||||||
|
if self.material is not None:
|
||||||
|
self.material.unbind()
|
||||||
|
|
||||||
|
def draw_from_vbos(self):
|
||||||
|
|
||||||
|
import OpenGL.GL as gl
|
||||||
|
|
||||||
|
self.vertex_vbo.bind()
|
||||||
|
gl.glEnableClientState(gl.GL_VERTEX_ARRAY);
|
||||||
|
gl.glVertexPointerf(self.vertex_vbo)
|
||||||
|
self.vertex_vbo.unbind()
|
||||||
|
|
||||||
|
if self.normal_vbo is not None:
|
||||||
|
self.normal_vbo.bind()
|
||||||
|
gl.glEnableClientState(gl.GL_NORMAL_ARRAY)
|
||||||
|
gl.glNormalPointerf(self.normal_vbo)
|
||||||
|
self.normal_vbo.unbind()
|
||||||
|
|
||||||
|
if self.tex_coord_vbo is not None:
|
||||||
|
|
||||||
|
if self.material is not None:
|
||||||
|
self.material.bind()
|
||||||
|
|
||||||
|
self.tex_coord_vbo.bind()
|
||||||
|
gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY)
|
||||||
|
gl.glTexCoordPointerf(self.tex_coord_vbo)
|
||||||
|
self.tex_coord_vbo.unbind()
|
||||||
|
|
||||||
|
gl.glDrawArrays(gl.GL_TRIANGLES, 0, len(self.vertex_vbo.data) * 9)
|
||||||
|
|
||||||
|
def draw_from_arrays(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Mesh:
|
||||||
|
def __init__(self):
|
||||||
|
self.vertices = []
|
||||||
|
self.tex_coords = []
|
||||||
|
self.normals = []
|
||||||
|
self.parts = []
|
||||||
|
self.current_material = None
|
||||||
|
self.current_part = None
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
for part in self.parts:
|
||||||
|
part.draw()
|
||||||
|
|
||||||
|
def add_face(self, face):
|
||||||
|
if self.current_part is None or face.material != self.current_part.material:
|
||||||
|
self.current_part = MeshPart(self)
|
||||||
|
self.current_part.material = face.material
|
||||||
|
self.parts.append(self.current_part)
|
||||||
|
|
||||||
|
self.current_part.add_face(face)
|
||||||
|
|
||||||
|
def generate_vbos(self):
|
||||||
|
for part in self.parts:
|
||||||
|
part.generate_vbos()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from .basemodel import ModelParser, Exporter, Vertex, TexCoord, Normal, FaceVertex, Face, Material
|
from .basemodel import ModelParser, Exporter, Vertex, TexCoord, Normal, FaceVertex, Face
|
||||||
|
from .mesh import Material, MeshPart
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
import os.path
|
import os.path
|
||||||
import PIL.Image
|
import PIL.Image
|
||||||
|
@ -24,7 +25,7 @@ class OBJParser(ModelParser):
|
||||||
split = split[1:]
|
split = split[1:]
|
||||||
|
|
||||||
if first == 'usemtl':
|
if first == 'usemtl':
|
||||||
self.current_material = split[0]
|
self.current_material = self.mtl[split[0]]
|
||||||
elif first == 'mtllib':
|
elif first == 'mtllib':
|
||||||
path = os.path.join(os.path.dirname(self.path), split[0])
|
path = os.path.join(os.path.dirname(self.path), split[0])
|
||||||
self.mtl = MTLParser(self)
|
self.mtl = MTLParser(self)
|
||||||
|
@ -73,7 +74,7 @@ class MTLParser:
|
||||||
elif first == 'Ks':
|
elif first == 'Ks':
|
||||||
self.current_mtl.Ks = Vertex().from_array(split)
|
self.current_mtl.Ks = Vertex().from_array(split)
|
||||||
elif first == 'map_Kd':
|
elif first == 'map_Kd':
|
||||||
self.map_Kd = PIL.Image.open(os.path.join(os.path.dirname(self.parent.path), split[0]))
|
self.current_mtl.map_Kd = PIL.Image.open(os.path.join(os.path.dirname(self.parent.path), split[0]))
|
||||||
|
|
||||||
|
|
||||||
def parse_file(self, path):
|
def parse_file(self, path):
|
||||||
|
@ -82,6 +83,11 @@ class MTLParser:
|
||||||
line = line.rstrip()
|
line = line.rstrip()
|
||||||
self.parse_line(line)
|
self.parse_line(line)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
for material in self.materials:
|
||||||
|
if material.name == key:
|
||||||
|
return material
|
||||||
|
|
||||||
|
|
||||||
class OBJExporter(Exporter):
|
class OBJExporter(Exporter):
|
||||||
def __init__(self, model):
|
def __init__(self, model):
|
||||||
|
|
|
@ -82,6 +82,9 @@ class PLYExporter(Exporter):
|
||||||
super().__init__(model)
|
super().__init__(model)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
||||||
|
faces = sum([part.faces for part in self.model.parts], [])
|
||||||
|
|
||||||
# Header
|
# Header
|
||||||
string = "ply\nformat ascii 1.0\ncomment Automatically gnerated by model-converter\n"
|
string = "ply\nformat ascii 1.0\ncomment Automatically gnerated by model-converter\n"
|
||||||
|
|
||||||
|
@ -90,7 +93,7 @@ class PLYExporter(Exporter):
|
||||||
string += "property float32 x\nproperty float32 y\nproperty float32 z\n"
|
string += "property float32 x\nproperty float32 y\nproperty float32 z\n"
|
||||||
|
|
||||||
# Types : faces
|
# Types : faces
|
||||||
string += "element face " + str(len(self.model.faces)) + "\n"
|
string += "element face " + str(len(faces)) + "\n"
|
||||||
string += "property list uint8 int32 vertex_indices\n"
|
string += "property list uint8 int32 vertex_indices\n"
|
||||||
|
|
||||||
# End header
|
# End header
|
||||||
|
@ -100,7 +103,7 @@ class PLYExporter(Exporter):
|
||||||
for vertex in self.model.vertices:
|
for vertex in self.model.vertices:
|
||||||
string += str(vertex.x) + " " + str(vertex.y) + " " + str(vertex.z) + "\n"
|
string += str(vertex.x) + " " + str(vertex.y) + " " + str(vertex.z) + "\n"
|
||||||
|
|
||||||
for face in self.model.faces:
|
for face in faces:
|
||||||
string += "3 " + str(face.a.vertex) + " " + str(face.b.vertex) + " " + str(face.c.vertex) + "\n"
|
string += "3 " + str(face.a.vertex) + " " + str(face.b.vertex) + " " + str(face.c.vertex) + "\n"
|
||||||
|
|
||||||
return string
|
return string
|
||||||
|
|
|
@ -43,9 +43,10 @@ def main(args):
|
||||||
running = True
|
running = True
|
||||||
|
|
||||||
model = load_model(args.input)
|
model = load_model(args.input)
|
||||||
|
model.init_textures()
|
||||||
model.generate_vbos()
|
model.generate_vbos()
|
||||||
|
|
||||||
shader = DefaultShader()
|
# shader = DefaultShader()
|
||||||
|
|
||||||
while running:
|
while running:
|
||||||
for event in pg.event.get():
|
for event in pg.event.get():
|
||||||
|
@ -72,9 +73,9 @@ def main(args):
|
||||||
|
|
||||||
gl.glPushMatrix()
|
gl.glPushMatrix()
|
||||||
controls.apply()
|
controls.apply()
|
||||||
shader.bind()
|
# shader.bind()
|
||||||
model.draw()
|
model.draw()
|
||||||
shader.unbind()
|
# shader.unbind()
|
||||||
gl.glPopMatrix()
|
gl.glPopMatrix()
|
||||||
|
|
||||||
gl.glFlush()
|
gl.glFlush()
|
||||||
|
|
Loading…
Reference in New Issue