Engine Code
This commit is contained in:
128
engine/mesh.py
Normal file
128
engine/mesh.py
Normal file
@@ -0,0 +1,128 @@
|
||||
from OpenGL.GL import *
|
||||
import numpy as np
|
||||
import open3d as o3d
|
||||
import ctypes
|
||||
|
||||
|
||||
class Mesh:
|
||||
def __init__(self, o3d_mesh=None, vertices=None, indices=None, textures=None):
|
||||
self.textures = textures if textures else []
|
||||
self.VAO = glGenVertexArrays(1)
|
||||
self.VBO = glGenBuffers(1)
|
||||
self.EBO = glGenBuffers(1)
|
||||
|
||||
#if we use a mesh from open3d we should use vertices and indices
|
||||
|
||||
if o3d_mesh is not None:
|
||||
self._init_from_open3d(o3d_mesh)
|
||||
#if not just use the vertices and indices
|
||||
elif vertices is not None and indices is not None:
|
||||
self._init_from_arrays(vertices, indices)
|
||||
else:
|
||||
raise ValueError("Either an Open3D mesh or vertices and indices must be provided")
|
||||
|
||||
def _init_from_open3d(self, o3d_mesh):
|
||||
if not o3d_mesh.has_vertex_normals():
|
||||
o3d_mesh.compute_vertex_normals()
|
||||
vertices = np.asarray(o3d_mesh.vertices)
|
||||
normals = np.asarray(o3d_mesh.vertex_normals)
|
||||
|
||||
if o3d_mesh.has_triangle_uvs():
|
||||
uvs = np.asarray(o3d_mesh.triangle_uvs)
|
||||
#this is only some workaround though, still need to implement this right
|
||||
if len(uvs) > 0:
|
||||
tex_coords = np.zeros((len(vertices), 2), dtype=np.float32)
|
||||
for i, triangle in enumerate(o3d_mesh.triangles):
|
||||
for j in range(3):
|
||||
tex_coords[triangle[j]] = uvs[i * 3 + j]
|
||||
else:
|
||||
tex_coords = np.zeros((len(vertices), 2), dtype=np.float32)
|
||||
else:
|
||||
tex_coords = np.zeros((len(vertices), 2), dtype=np.float32)
|
||||
vertex_data = np.zeros((len(vertices), 8), dtype=np.float32)
|
||||
vertex_data[:, 0:3] = vertices
|
||||
vertex_data[:, 3:6] = normals
|
||||
vertex_data[:, 6:8] = tex_coords
|
||||
|
||||
indices = np.asarray(o3d_mesh.triangles).flatten()
|
||||
|
||||
self._init_from_arrays(vertex_data, indices)
|
||||
|
||||
self.o3d_mesh = o3d_mesh
|
||||
|
||||
def _init_from_arrays(self, vertices, indices):
|
||||
self.vertices = vertices
|
||||
self.indices = indices
|
||||
glBindVertexArray(self.VAO)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.VBO)
|
||||
glBufferData(GL_ARRAY_BUFFER, self.vertices.nbytes, self.vertices, GL_STATIC_DRAW)
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.EBO)
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.indices.nbytes, self.indices, GL_STATIC_DRAW)
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * 4, ctypes.c_void_p(0))
|
||||
glEnableVertexAttribArray(0)
|
||||
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * 4, ctypes.c_void_p(3 * 4))
|
||||
glEnableVertexAttribArray(1)
|
||||
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * 4, ctypes.c_void_p(6 * 4))
|
||||
glEnableVertexAttribArray(2)
|
||||
|
||||
glBindVertexArray(0)
|
||||
|
||||
@staticmethod
|
||||
def create_box(width=1.0, height=1.0, depth=1.0):
|
||||
box = o3d.geometry.TriangleMesh.create_box(width=width, height=height, depth=depth)
|
||||
box.compute_vertex_normals()
|
||||
return Mesh(o3d_mesh=box)
|
||||
|
||||
@staticmethod
|
||||
def create_sphere(radius=1.0, resolution=20):
|
||||
sphere = o3d.geometry.TriangleMesh.create_sphere(radius=radius, resolution=resolution)
|
||||
sphere.compute_vertex_normals()
|
||||
return Mesh(o3d_mesh=sphere)
|
||||
|
||||
@staticmethod
|
||||
def create_cylinder(radius=1.0, height=2.0, resolution=20, split=4):
|
||||
cylinder = o3d.geometry.TriangleMesh.create_cylinder(radius=radius, height=height, resolution=resolution,
|
||||
split=split)
|
||||
cylinder.compute_vertex_normals()
|
||||
return Mesh(o3d_mesh=cylinder)
|
||||
|
||||
@staticmethod
|
||||
def create_cone(radius=1.0, height=2.0, resolution=20, split=1):
|
||||
cone = o3d.geometry.TriangleMesh.create_cone(radius=radius, height=height, resolution=resolution, split=split)
|
||||
cone.compute_vertex_normals()
|
||||
return Mesh(o3d_mesh=cone)
|
||||
|
||||
@staticmethod
|
||||
def create_torus(torus_radius=1.0, tube_radius=0.2, radial_resolution=30, tubular_resolution=20):
|
||||
torus = o3d.geometry.TriangleMesh.create_torus(torus_radius=torus_radius, tube_radius=tube_radius,
|
||||
radial_resolution=radial_resolution,
|
||||
tubular_resolution=tubular_resolution)
|
||||
torus.compute_vertex_normals()
|
||||
return Mesh(o3d_mesh=torus)
|
||||
|
||||
def draw(self, shader):
|
||||
diffuse_nr = 1
|
||||
specular_nr = 1
|
||||
|
||||
for i, texture in enumerate(self.textures):
|
||||
glActiveTexture(GL_TEXTURE0 + i)
|
||||
number = ""
|
||||
name = texture.type
|
||||
if name == "texture_diffuse":
|
||||
number = str(diffuse_nr)
|
||||
diffuse_nr += 1
|
||||
elif name == "texture_specular":
|
||||
number = str(specular_nr)
|
||||
specular_nr += 1
|
||||
|
||||
shader.set_int(f"material.{name}{number}", i)
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture.id)
|
||||
|
||||
glBindVertexArray(self.VAO)
|
||||
glDrawElements(GL_TRIANGLES, len(self.indices), GL_UNSIGNED_INT, None)
|
||||
glBindVertexArray(0)
|
||||
glActiveTexture(GL_TEXTURE0)
|
||||
Reference in New Issue
Block a user