diff --git a/korman/exporter/physics.py b/korman/exporter/physics.py index b02a249..d13f221 100644 --- a/korman/exporter/physics.py +++ b/korman/exporter/physics.py @@ -13,13 +13,15 @@ # You should have received a copy of the GNU General Public License # along with Korman. If not, see . +import bmesh import bpy +import itertools import mathutils from PyHSPlasma import * import weakref from .explosions import ExportError, ExportAssertionError -from ..helpers import TemporaryObject +from ..helpers import bmesh_from_object, TemporaryObject from . import utils def _set_phys_prop(prop, sim, phys, value=True): @@ -58,18 +60,11 @@ class PhysicsConverter: indices += (v[0], v[2], v[3],) return indices - def _convert_mesh_data(self, bo, physical, local_space, indices=True, mesh_func=None): - try: - mesh = bo.to_mesh(bpy.context.scene, True, "RENDER", calc_tessface=False) - except: - raise ExportError("Unable to convert object [{}] '{}' to a mesh. Make sure you didn't try to use this object as a region!", - bo.type, bo.name) + def _convert_mesh_data(self, bo, physical, local_space, indices=True): mat = bo.matrix_world + mesh = bo.to_mesh(bpy.context.scene, True, "RENDER", calc_tessface=False) with TemporaryObject(mesh, bpy.data.meshes.remove): - if mesh_func is not None: - mesh_func(mesh) - if local_space: mesh.update(calc_tessface=indices) physical.pos = hsVector3(*mat.to_translation()) @@ -264,21 +259,19 @@ class PhysicsConverter: # Only certain builds of libHSPlasma are able to take artist generated triangle soups and # bake them to convex hulls. Specifically, Windows 32-bit w/PhysX 2.6. Everything else just # needs to have us provide some friendlier data... - def _bake_hull(mesh): - # The bmesh API for doing this is trash, so we will link this temporary mesh to an - # even more temporary object so we can use the traditional operator. - # Unless you want to write some code to do this by hand...??? (not me) - bo = bpy.data.objects.new("BMeshSucks", mesh) - bpy.context.scene.objects.link(bo) - with TemporaryObject(bo, bpy.data.objects.remove): - bpy.context.scene.objects.active = bo - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_all(action="SELECT") - bpy.ops.mesh.convex_hull(use_existing_faces=False) - bpy.ops.object.mode_set(mode="OBJECT") - - physical.verts = self._convert_mesh_data(bo, physical, local_space, indices=False, - mesh_func=_bake_hull) + with bmesh_from_object(bo) as mesh: + mat = bo.matrix_world + if local_space: + physical.pos = hsVector3(*mat.to_translation()) + physical.rot = utils.quaternion(mat.to_quaternion()) + bmesh.ops.scale(mesh, vec=mat.to_scale(), verts=mesh.verts) + else: + mesh.transform(mat) + + result = bmesh.ops.convex_hull(mesh, input=mesh.verts, use_existing_faces=False) + BMVert = bmesh.types.BMVert + verts = itertools.takewhile(lambda x: isinstance(x, BMVert), result["geom"]) + physical.verts = [hsVector3(*i.co) for i in verts] def _export_sphere(self, bo, physical, local_space): """Exports sphere bounds based on the object""" diff --git a/korman/helpers.py b/korman/helpers.py index 9e16819..31c1d20 100644 --- a/korman/helpers.py +++ b/korman/helpers.py @@ -13,9 +13,22 @@ # You should have received a copy of the GNU General Public License # along with Korman. If not, see . +import bmesh import bpy +from contextlib import contextmanager import math +@contextmanager +def bmesh_from_object(bl): + """Converts a Blender Object to a BMesh with modifiers applied.""" + mesh = bmesh.new() + try: + # Empirical evidence indicates that this applies Blender Modifiers + mesh.from_object(bl, bpy.context.scene) + yield mesh + finally: + mesh.free() + class GoodNeighbor: """Leave Things the Way You Found Them! (TM)"""