-
Germano Cavalcante authored
This reverts commit 4e932c56. Was accidentally pushed before D14497.
Germano Cavalcante authoredThis reverts commit 4e932c56. Was accidentally pushed before D14497.
mesh_drawing.py 13.05 KiB
# SPDX-License-Identifier: GPL-2.0-or-later
import gpu
import bmesh
from mathutils import Matrix
def load_shader(shadername):
from os import path
with open(path.join(path.dirname(__file__), "shaders", shadername), "r") as f:
return f.read()
def get_mesh_vert_co_array(me):
tot_vco = len(me.vertices)
if tot_vco:
import numpy as np
verts_co = np.empty(len(me.vertices) * 3, "f4")
me.vertices.foreach_get("co", verts_co)
verts_co.shape = (-1, 3)
return verts_co
return ()
def get_bmesh_vert_co_array(bm):
tot_vco = len(bm.verts)
if tot_vco:
import numpy as np
return np.array([v.co for v in bm.verts], "f4")
return ()
def get_mesh_tri_verts_array(me):
me.calc_loop_triangles()
len_triangles = len(me.loop_triangles)
if len_triangles:
import numpy as np
tris = np.empty(len_triangles * 3, "i4")
me.loop_triangles.foreach_get("vertices", tris)
tris.shape = (-1, 3)
return tris
return ()
def get_bmesh_tri_verts_array(bm):
if bm.faces:
import numpy as np
l_tri_layer = bm.faces.layers.int.get("l_tri")
if l_tri_layer is None:
l_tri_layer = bm.faces.layers.int.new("l_tri")
ltris = bm.calc_loop_triangles()
tris = np.empty((len(ltris), 3), "i4")
i = 0
bm.faces.ensure_lookup_table()
last_face = bm.faces[-1]
for ltri in ltris:
face = ltri[0].face
if not face.hide:
tris[i] = ltri[0].vert.index, ltri[1].vert.index, ltri[2].vert.index
if last_face != face:
last_face = face
face[l_tri_layer] = i
i += 1
if i:
tris.resize((i, 3), refcheck=False)
return tris
return ()
def get_mesh_edge_verts_array(me):
tot_edges = len(me.edges)
if tot_edges:
import numpy as np
edge_verts = np.empty(tot_edges * 2, "i4")
me.edges.foreach_get("vertices", edge_verts)
edge_verts.shape = tot_edges, 2
return edge_verts
return ()
def get_bmesh_edge_verts_array(bm):
bm.edges.ensure_lookup_table()
edges = [[e.verts[0].index, e.verts[1].index] for e in bm.edges if not e.hide]
if edges:
import numpy as np
return np.array(edges, "i4")
return ()
def get_mesh_loosevert_array(me, edges):
import numpy as np
verts = np.arange(len(me.vertices))
mask = np.in1d(verts, edges, invert=True)
verts = verts[mask]
if len(verts):
return verts
return ()
def get_bmesh_loosevert_array(bm):
looseverts = [v.index for v in bm.verts if not (v.link_edges or v.hide)]
if looseverts:
import numpy as np
return np.array(looseverts, "i4")
return ()
class _Mesh_Arrays:
def __init__(self, obj, create_tris, create_edges, create_looseverts):
self.tri_verts = self.edge_verts = self.looseverts = ()
if obj.type == "MESH":
me = obj.data
if me.is_editmode:
bm = bmesh.from_edit_mesh(me)
bm.verts.ensure_lookup_table()
self.verts_co = get_bmesh_vert_co_array(bm)
if create_tris:
self.tri_verts = get_bmesh_tri_verts_array(bm)
if create_edges:
self.edge_verts = get_bmesh_edge_verts_array(bm)
if create_looseverts:
self.looseverts = get_bmesh_loosevert_array(bm)
del bm
else:
import bpy
self.verts_co = get_mesh_vert_co_array(me)
if create_tris:
self.tri_verts = get_mesh_tri_verts_array(me)
if create_edges:
self.edge_verts = get_mesh_edge_verts_array(me)
if create_looseverts:
edge_verts = self.edge_verts
if edge_verts is None:
edge_verts = get_mesh_edge_verts_array(me)
self.looseverts = get_mesh_loosevert_array(me, edge_verts)
del edge_verts
else: # TODO
import numpy as np
self.verts_co = np.zeros((1, 3), "f4")
self.looseverts = np.zeros(1, "i4")
def __del__(self):
del self.tri_verts, self.edge_verts, self.looseverts
del self.verts_co
class GPU_Indices_Mesh:
__slots__ = (
"ob_data",
"draw_tris",
"draw_edges",
"draw_verts",
"batch_tris",
"batch_edges",
"batch_lverts",
"verts_co",
"tri_verts",
"edge_verts",
"looseverts",
"first_index",
"users",
)
_Hash = {}
shader = None
@classmethod
def end_opengl(cls):
del cls.shader
del cls
@staticmethod
def init_opengl():
cls = GPU_Indices_Mesh
# OpenGL was already initialized, nothing to do here.
if cls.shader is not None:
return
import atexit
# Make sure we only registered the callback once.
atexit.unregister(cls.end_opengl)
atexit.register(cls.end_opengl)
cls.shader = gpu.types.GPUShader(
load_shader("ID_color_vert.glsl"),
load_shader("ID_color_frag.glsl"),
defines="#define USE_CLIP_PLANES\n",
)
cls.unif_offset = cls.shader.uniform_from_name("offset")
cls.use_clip_planes = False
def __init__(self, depsgraph, obj, draw_tris, draw_edges, draw_verts):
self.ob_data = obj.original.data
if self.ob_data in GPU_Indices_Mesh._Hash:
src = GPU_Indices_Mesh._Hash[self.ob_data]
dst = self
dst.draw_tris = src.draw_tris
dst.draw_edges = src.draw_edges
dst.draw_verts = src.draw_verts
dst.batch_tris = src.batch_tris
dst.batch_edges = src.batch_edges
dst.batch_lverts = src.batch_lverts
dst.verts_co = src.verts_co
dst.tri_verts = src.tri_verts
dst.edge_verts = src.edge_verts
dst.looseverts = src.looseverts
dst.users = src.users
dst.users.append(self)
update = False
else:
GPU_Indices_Mesh._Hash[self.ob_data] = self
self.users = [self]
update = True
if update:
self.draw_tris = draw_tris
self.draw_edges = draw_edges
self.draw_verts = draw_verts
GPU_Indices_Mesh.init_opengl()
## Init Array ##
mesh_arrays = _Mesh_Arrays(
depsgraph.id_eval_get(obj), draw_tris, draw_edges, draw_verts
)
if mesh_arrays.verts_co is None:
self.draw_tris = False
self.draw_edges = False
self.draw_verts = False
self.tri_verts = ()
self.edge_verts = ()
self.looseverts = ()
return
## Create VBO for vertices ##
self.verts_co = mesh_arrays.verts_co
self.tri_verts = mesh_arrays.tri_verts
self.edge_verts = mesh_arrays.edge_verts
self.looseverts = mesh_arrays.looseverts
del mesh_arrays
format = gpu.types.GPUVertFormat()
format.attr_add(id="pos", comp_type="F32", len=3, fetch_mode="FLOAT")
vbo = gpu.types.GPUVertBuf(format, len=len(self.verts_co))
vbo.attr_fill(0, data=self.verts_co)
## Create Batch for Tris ##
if len(self.tri_verts) > 0:
ebo = gpu.types.GPUIndexBuf(type="TRIS", seq=self.tri_verts)
self.batch_tris = gpu.types.GPUBatch(type="TRIS", buf=vbo, elem=ebo)
self.batch_tris.program_set(self.shader)
else:
self.draw_tris = False
self.batch_tris = None
## Create Batch for Edges ##
if len(self.edge_verts) > 0:
ebo = gpu.types.GPUIndexBuf(type="LINES", seq=self.edge_verts)
self.batch_edges = gpu.types.GPUBatch(type="LINES", buf=vbo, elem=ebo)
self.batch_edges.program_set(self.shader)
else:
self.draw_edges = False
self.batch_edges = None
## Create Batch for Loose Verts ##
if len(self.looseverts) > 0:
ebo = gpu.types.GPUIndexBuf(type="POINTS", seq=self.looseverts)
self.batch_lverts = gpu.types.GPUBatch(type="POINTS", buf=vbo, elem=ebo)
self.batch_lverts.program_set(self.shader)
else:
self.draw_verts = False
self.batch_lverts = None
def get_tot_elems(self):
tot = 0
if self.draw_tris:
tot += len(self.tri_verts)
if self.draw_edges:
tot += len(self.edge_verts)
if self.draw_verts:
tot += len(self.looseverts)
return tot
def set_draw_mode(self, draw_tris, draw_edges, draw_verts):
self.draw_tris = draw_tris and len(self.tri_verts) > 0
self.draw_edges = draw_edges and len(self.edge_verts) > 0
self.draw_verts = draw_verts and len(self.looseverts) > 0
def Draw(self, index_offset, ob_mat, depth_offset=0.00005):
self.first_index = index_offset
gpu.matrix.push()
gpu.matrix.push_projection()
gpu.matrix.multiply_matrix(ob_mat)
self.shader.bind()
if GPU_Indices_Mesh.use_clip_planes:
gpu.state.clip_distances_set(4)
self.shader.uniform_float("ModelMatrix", ob_mat)
if self.draw_tris:
self.shader.uniform_int("offset", (index_offset,))
self.batch_tris.draw(self.shader)
index_offset += len(self.tri_verts)
winmat = gpu.matrix.get_projection_matrix()
is_persp = winmat[3][3] == 0.0
if is_persp:
near = winmat[2][3] / (winmat[2][2] - 1.0)
far_ = winmat[2][3] / (winmat[2][2] + 1.0)
else:
near = (winmat[2][3] + 1.0) / winmat[2][2]
far_ = (winmat[2][3] - 1.0) / winmat[2][2]
far_ += depth_offset
near += depth_offset
range = far_ - near
if is_persp:
winmat[2][2] = -(far_ + near) / range
winmat[2][3] = (-2 * far_ * near) / range
else:
winmat[2][3] = -(far_ + near) / range
gpu.matrix.load_projection_matrix(winmat)
if self.draw_edges:
self.shader.uniform_int("offset", (index_offset,))
# bgl.glLineWidth(3.0)
self.batch_edges.draw(self.shader)
# bgl.glLineWidth(1.0)
index_offset += len(self.edge_verts)
if self.draw_verts:
self.shader.uniform_int("offset", (index_offset,))
self.batch_lverts.draw(self.shader)
if GPU_Indices_Mesh.use_clip_planes:
gpu.state.clip_distances_set(0)
gpu.matrix.pop()
gpu.matrix.pop_projection()
def get_tri_co(self, index):
return self.verts_co[self.tri_verts[index]]
def get_edge_co(self, index):
return self.verts_co[self.edge_verts[index]]
def get_loosevert_co(self, index):
return self.verts_co[self.looseverts[index]]
def get_loop_tri_co_by_bmface(self, bm, bmface):
l_tri_layer = bm.faces.layers.int["l_tri"]
tri = bmface[l_tri_layer]
return self.verts_co[self.tri_verts[tri : tri + len(bmface.verts) - 2]]
def get_tri_verts(self, index):
return self.tri_verts[index]
def get_edge_verts(self, index):
return self.edge_verts[index]
def get_loosevert_index(self, index):
return self.looseverts[index]
def free(self):
self.users.remove(self)
if len(self.users) == 0:
del self.batch_tris
del self.batch_edges
del self.batch_lverts
del self.verts_co
del self.tri_verts
del self.edge_verts
del self.looseverts
GPU_Indices_Mesh._Hash.pop(self.ob_data)
# print('mesh_del', self.obj.name)
def gpu_Indices_enable_state(winmat, viewmat):
GPU_Indices_Mesh.init_opengl()
gpu.matrix.push()
gpu.matrix.push_projection()
gpu.matrix.load_projection_matrix(winmat)
gpu.matrix.load_matrix(viewmat)
GPU_Indices_Mesh.shader.bind()
def gpu_Indices_restore_state():
gpu.matrix.pop()
gpu.matrix.pop_projection()
def gpu_Indices_use_clip_planes(rv3d, value):
GPU_Indices_Mesh.init_opengl()
shader = GPU_Indices_Mesh.shader
shader.bind()
if value and rv3d.use_clip_planes:
GPU_Indices_Mesh.use_clip_planes = True
planes = gpu.types.Buffer("FLOAT", (6, 4), rv3d.clip_planes)
shader.uniform_vector_float(
shader.uniform_from_name("WorldClipPlanes"), planes, 4, 4
)
else:
GPU_Indices_Mesh.use_clip_planes = False
shader.uniform_bool("use_clip_planes", (GPU_Indices_Mesh.use_clip_planes,))
def gpu_Indices_mesh_cache_clear():
GPU_Indices_Mesh._Hash.clear()