PyOpenGL seems not to work with trimesh .obj through glDrawElementsInstanced
I've been stuck on this problem for at least 4 days and I have almost tried everything. I have .obj files, I load them through trimesh.load and then make up the vertex data and indices, but PyOpenGL seems not to draw correctly the mesh through glDrawElementsInstanced (the "Instanced" part works just fine).
Mesh Loader from file:
def _load_mesh_from_file(self, path):
mesh = trimesh.load(path, force="mesh")
trimesh.repair.fill_holes(mesh)
trimesh.repair.fix_winding(mesh)
# vertices_pos = data[:, 0:3]
# vertices_uv = data[:, 3:5] # texcoord
# vertices_normal = data[:, 5:8] # normal
# vertices_tangent = data[:, 8:11] # tangent
# vertices_bitangent = data[:, 11:14] # bitangent
faces = mesh.faces
vertex_pos = mesh.vertices
vertex_uv = mesh.visual.uv
vertex_normal = mesh.vertex_normals
vertex_tangent, vertex_bitangent = self._load_tangent_bitangent(vertex_pos, vertex_uv, faces)
vertex_data = []
for i in range(len(vertex_pos)):
vertex_data.extend([
*vertex_pos[i],
*vertex_uv[i],
*vertex_normal[i],
*vertex_tangent[i],
*vertex_bitangent[i],
])
return np.ascontiguousarray(vertex_data, dtype=np.float32), np.ascontiguousarray(faces, dtype=np.uint32) // this is what makes up mesh_data
Mesh Instance:
def __init__(self,
mesh_data: list | tuple,
name: str="",
position: list | np.ndarray=[0, 0, 0],
eulers: list | np.ndarray=[0, 0, 0],
scale: list | np.ndarray=[1, 1, 1],
):
self.objects: list = []
self.position = np.array(position, dtype=np.float32)
self.eulers = np.array(eulers, dtype=np.float32)
self.scale = np.array(scale, dtype=np.float32)
self.name = name
self.max_instances = 1000
self.mesh_data = mesh_data
vertex_data = mesh_data[0]
indices = mesh_data[1]
self.vertex_data = np.ascontiguousarray(vertex_data, dtype=np.float32)
self.indices_data = np.ascontiguousarray(indices, dtype=np.uint32)
self.vertex_count = vertex_data.shape[0]
self.index_count = len(indices)
stride = 14 * 4
self.vao = glGenVertexArrays(1)
glBindVertexArray(self.vao)
vertex_buffer = np.array(self.vertex_data, dtype=np.float32).reshape(-1, 14)
self.vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, vertex_buffer.nbytes, vertex_buffer, GL_STATIC_DRAW)
index_buffer = np.array(self.indices_data, dtype=np.uint32)
self.ebo = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.ebo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_buffer.nbytes, index_buffer, GL_STATIC_DRAW)
# Posizione
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, ctypes.c_void_p(0))
# UV
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, ctypes.c_void_p(12))
# Normale
glEnableVertexAttribArray(2)
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, ctypes.c_void_p(20))
# Tangente
glEnableVertexAttribArray(3)
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, stride, ctypes.c_void_p(32))
# Bitangente
glEnableVertexAttribArray(4)
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, stride, ctypes.c_void_p(44))
self._gpu_indices = self.indices_data
self._gpu_vertices = self.vertex_data
self.max_instances = getattr(self, "max_instances", 1000)
self.instance_vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.instance_vbo)
glBufferData(GL_ARRAY_BUFFER, self.max_instances * 16 * 4, None, GL_DYNAMIC_DRAW)
for i in range(4):
glEnableVertexAttribArray(5 + i)
glVertexAttribPointer(
5 + i,
4,
GL_FLOAT,
GL_FALSE,
64,
ctypes.c_void_p(i * 16)
)
glVertexAttribDivisor(5 + i, 1)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
Draw call:
def draw(self, instance_count):
if instance_count == 0:
return
self._bind_vao()
self.shader.use()
if engine_config.SHOW_WIRE_FRAME:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
glDrawElementsInstanced(
GL_TRIANGLES,
self.index_count,
GL_UNSIGNED_INT,
None,
instance_count
)
# glDrawArraysInstanced(
# GL_TRIANGLES,
# 0,
# self.vertex_count,
# instance_count
# )
if engine_config.SHOW_WIRE_FRAME:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
glBindVertexArray(0)
# glDrawArraysInstanced( GL_LINE_STRIP, 0, self.vertex_count, instance_count )