mirror of https://github.com/H-uru/korman.git
Adam Johnson
11 years ago
7 changed files with 256 additions and 0 deletions
@ -0,0 +1,116 @@ |
|||||||
|
# This file is part of Korman. |
||||||
|
# |
||||||
|
# Korman is free software: you can redistribute it and/or modify |
||||||
|
# it under the terms of the GNU General Public License as published by |
||||||
|
# the Free Software Foundation, either version 3 of the License, or |
||||||
|
# (at your option) any later version. |
||||||
|
# |
||||||
|
# Korman is distributed in the hope that it will be useful, |
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
# GNU General Public License for more details. |
||||||
|
# |
||||||
|
# You should have received a copy of the GNU General Public License |
||||||
|
# along with Korman. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
|
||||||
|
import mathutils |
||||||
|
from PyHSPlasma import * |
||||||
|
import weakref |
||||||
|
|
||||||
|
from . import utils |
||||||
|
|
||||||
|
class PhysicsConverter: |
||||||
|
def __init__(self, exporter): |
||||||
|
self._exporter = weakref.ref(exporter) |
||||||
|
|
||||||
|
def _convert_mesh_data(self, bo, physical, indices=True): |
||||||
|
mesh = bo.data |
||||||
|
mesh.update(calc_tessface=True) |
||||||
|
|
||||||
|
mat = bo.matrix_world |
||||||
|
if not self._mgr.has_coordiface(bo): |
||||||
|
physical.rot = utils.quaternion(mat.to_quaternion()) |
||||||
|
physical.pos = utils.vector3(mat.to_translation()) |
||||||
|
|
||||||
|
# Physicals can't have scale... |
||||||
|
scale = mat.to_scale() |
||||||
|
if scale[0] == 1.0 and scale[1] == 1.0 and scale[2] == 1.0: |
||||||
|
# Whew, don't need to do any math! |
||||||
|
vertices = [hsVector3(i.co.x, i.co.y, i.co.z) for i in mesh.vertices] |
||||||
|
else: |
||||||
|
# Dagnabbit... |
||||||
|
vertices = [hsVector3(i.co.x * scale.x, i.co.y * scale.y, i.co.z * scale.z) for i in mesh.vertices] |
||||||
|
|
||||||
|
if indices: |
||||||
|
indices = [] |
||||||
|
for face in mesh.tessfaces: |
||||||
|
v = face.vertices |
||||||
|
if len(v) == 3: |
||||||
|
indices += v |
||||||
|
elif len(v) == 4: |
||||||
|
indices += (v[0], v[1], v[2],) |
||||||
|
indices += (v[0], v[2], v[3],) |
||||||
|
return (vertices, indices) |
||||||
|
else: |
||||||
|
return vertices |
||||||
|
|
||||||
|
def generate_physical(self, bo, so, name=None): |
||||||
|
"""Generates a physical object for the given object pair""" |
||||||
|
if so.sim is None: |
||||||
|
if name is None: |
||||||
|
name = bo.name |
||||||
|
|
||||||
|
simIface = self._mgr.add_object(pl=plSimulationInterface, bl=bo) |
||||||
|
physical = self._mgr.add_object(pl=plGenericPhysical, bl=bo, name=name) |
||||||
|
|
||||||
|
so.sim = simIface.key |
||||||
|
simIface.physical = physical.key |
||||||
|
physical.object = so.key |
||||||
|
physical.sceneNode = self._mgr.get_scene_node(bl=bo) |
||||||
|
else: |
||||||
|
simIface = so.sim.object |
||||||
|
physical = simIface.physical.object |
||||||
|
if name is not None: |
||||||
|
physical.key.name = name |
||||||
|
|
||||||
|
return (simIface, physical) |
||||||
|
|
||||||
|
def export(self, bo, physical, bounds): |
||||||
|
getattr(self, "_export_{}".format(bounds))(bo, physical) |
||||||
|
|
||||||
|
def _export_box(self, bo, physical): |
||||||
|
"""Exports box bounds based on the object""" |
||||||
|
physical.boundsType = plSimDefs.kBoxBounds |
||||||
|
|
||||||
|
vertices = self._convert_mesh_data(bo, physical, indices=False) |
||||||
|
physical.calcBoxBounds(vertices) |
||||||
|
|
||||||
|
def _export_hull(self, bo, physical): |
||||||
|
"""Exports convex hull bounds based on the object""" |
||||||
|
physical.boundsType = plSimDefs.kHullBounds |
||||||
|
|
||||||
|
vertices = self._convert_mesh_data(bo, physical, indices=False) |
||||||
|
# --- TODO --- |
||||||
|
# Until we have real convex hull processing, simply dump the verts into the physical |
||||||
|
# Note that PyPRP has always done this... PhysX will optimize this for us. So, it's not |
||||||
|
# the end of the world (but it is evil). |
||||||
|
physical.verts = vertices |
||||||
|
|
||||||
|
def _export_sphere(self, bo, physical): |
||||||
|
"""Exports sphere bounds based on the object""" |
||||||
|
physical.boundsType = plSimDefs.kSphereBounds |
||||||
|
|
||||||
|
vertices = self._convert_mesh_data(bo, physical, indices=False) |
||||||
|
physical.calcSphereBounds(vertices) |
||||||
|
|
||||||
|
def _export_trimesh(self, bo, physical): |
||||||
|
"""Exports an object's mesh as exact physical bounds""" |
||||||
|
physical.boundsType = plSimDefs.kExplicitBounds |
||||||
|
|
||||||
|
vertices, indices = self._convert_mesh_data(bo, physical) |
||||||
|
physical.verts = vertices |
||||||
|
physical.indices = indices |
||||||
|
|
||||||
|
@property |
||||||
|
def _mgr(self): |
||||||
|
return self._exporter().mgr |
@ -0,0 +1,92 @@ |
|||||||
|
# This file is part of Korman. |
||||||
|
# |
||||||
|
# Korman is free software: you can redistribute it and/or modify |
||||||
|
# it under the terms of the GNU General Public License as published by |
||||||
|
# the Free Software Foundation, either version 3 of the License, or |
||||||
|
# (at your option) any later version. |
||||||
|
# |
||||||
|
# Korman is distributed in the hope that it will be useful, |
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
# GNU General Public License for more details. |
||||||
|
# |
||||||
|
# You should have received a copy of the GNU General Public License |
||||||
|
# along with Korman. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
|
||||||
|
import bpy |
||||||
|
from bpy.props import * |
||||||
|
from PyHSPlasma import * |
||||||
|
|
||||||
|
from .base import PlasmaModifierProperties |
||||||
|
|
||||||
|
# These are the kinds of physical bounds Plasma can work with. |
||||||
|
# This sequence is acceptable in any EnumProperty |
||||||
|
bounds_types = ( |
||||||
|
("box", "Bounding Box", "Use a perfect bounding box"), |
||||||
|
("sphere", "Bounding Sphere", "Use a perfect bounding sphere"), |
||||||
|
("hull", "Convex Hull", "Use a convex set encompasing all vertices"), |
||||||
|
("trimesh", "Triangle Mesh", "Use the exact triangle mesh (SLOW!)") |
||||||
|
) |
||||||
|
|
||||||
|
def _set_phys_prop(prop, sim, phys, value=True): |
||||||
|
"""Sets properties on plGenericPhysical and plSimulationInterface (seeing as how they are duped)""" |
||||||
|
sim.setProperty(prop, value) |
||||||
|
phys.setProperty(prop, value) |
||||||
|
|
||||||
|
|
||||||
|
class PlasmaCollider(PlasmaModifierProperties): |
||||||
|
pl_id = "collision" |
||||||
|
|
||||||
|
bl_category = "Physics" |
||||||
|
bl_label = "Collision" |
||||||
|
bl_icon = "MOD_PHYSICS" |
||||||
|
bl_description = "Simple physical collider" |
||||||
|
|
||||||
|
bounds = EnumProperty(name="Bounds Type", description="", items=bounds_types) |
||||||
|
|
||||||
|
avatar_blocker = BoolProperty(name="Blocks Avatars", description="Object blocks avatars", default=True) |
||||||
|
camera_blocker = BoolProperty(name="Blocks Camera", description="Object blocks the camera", default=True) |
||||||
|
|
||||||
|
friction = FloatProperty(name="Friction", min=0.0, default=0.5) |
||||||
|
restitution = FloatProperty(name="Restitution", description="Coefficient of collision elasticity", min=0.0, max=1.0) |
||||||
|
terrain = BoolProperty(name="Terrain", description="Object represents the ground", default=False) |
||||||
|
|
||||||
|
dynamic = BoolProperty(name="Dynamic", description="Object can be influenced by other objects (ie is kickable)", default=False) |
||||||
|
mass = FloatProperty(name="Mass", description="Mass of object in pounds", min=0.0, default=1.0) |
||||||
|
start_asleep = BoolProperty(name="Start Asleep", description="Object is not active until influenced by another object", default=False) |
||||||
|
|
||||||
|
def created(self, obj): |
||||||
|
self.display_name = "{}_Collision".format(obj.name) |
||||||
|
|
||||||
|
def export(self, exporter, bo, so): |
||||||
|
simIface, physical = exporter.physics.generate_physical(bo, so, self.display_name) |
||||||
|
|
||||||
|
# Common props |
||||||
|
physical.friction = self.friction |
||||||
|
physical.restitution = self.restitution |
||||||
|
|
||||||
|
# Collision groups and such |
||||||
|
if not self.avatar_blocker: |
||||||
|
physical.collideGroup = plSimDefs.kGroupLOSOnly |
||||||
|
|
||||||
|
if self.dynamic: |
||||||
|
physical.memberGroup = plSimDefs.kGroupDynamic |
||||||
|
physical.mass = self.mass |
||||||
|
_set_phys_prop(plSimulationInterface.kStartInactive, simIface, physical, value=self.start_asleep) |
||||||
|
else: |
||||||
|
physical.memberGroup = plSimDefs.kGroupStatic |
||||||
|
|
||||||
|
# Line of Sight DB |
||||||
|
if self.camera_blocker: |
||||||
|
physical.LOSDBs |= plSimDefs.kLOSDBCameraBlockers |
||||||
|
# This appears to be dead in CWE, but we'll set it anyway |
||||||
|
_set_phys_prop(plSimulationInterface.kCameraAvoidObject, simIface, physical) |
||||||
|
if self.terrain: |
||||||
|
physical.LOSDBs |= plSimDefs.kLOSDBAvatarWalkable |
||||||
|
|
||||||
|
# Pass this off to the PhysicsConverter to export the meat |
||||||
|
exporter.physics.export(bo, physical, self.bounds) |
||||||
|
|
||||||
|
@property |
||||||
|
def requires_actor(self): |
||||||
|
return self.dynamic |
@ -0,0 +1,40 @@ |
|||||||
|
# This file is part of Korman. |
||||||
|
# |
||||||
|
# Korman is free software: you can redistribute it and/or modify |
||||||
|
# it under the terms of the GNU General Public License as published by |
||||||
|
# the Free Software Foundation, either version 3 of the License, or |
||||||
|
# (at your option) any later version. |
||||||
|
# |
||||||
|
# Korman is distributed in the hope that it will be useful, |
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
# GNU General Public License for more details. |
||||||
|
# |
||||||
|
# You should have received a copy of the GNU General Public License |
||||||
|
# along with Korman. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
|
||||||
|
def collision(modifier, layout, context): |
||||||
|
layout.prop(modifier, "bounds") |
||||||
|
layout.separator() |
||||||
|
|
||||||
|
split = layout.split() |
||||||
|
col = split.column() |
||||||
|
col.prop(modifier, "avatar_blocker") |
||||||
|
col.prop(modifier, "camera_blocker") |
||||||
|
col.prop(modifier, "terrain") |
||||||
|
|
||||||
|
col = split.column() |
||||||
|
col.prop(modifier, "friction") |
||||||
|
col.prop(modifier, "restitution") |
||||||
|
layout.separator() |
||||||
|
|
||||||
|
split = layout.split() |
||||||
|
col = split.column() |
||||||
|
col.prop(modifier, "dynamic") |
||||||
|
row = col.row() |
||||||
|
row.active = modifier.dynamic |
||||||
|
row.prop(modifier, "start_asleep") |
||||||
|
|
||||||
|
col = split.column() |
||||||
|
col.active = modifier.dynamic |
||||||
|
col.prop(modifier, "mass") |
Loading…
Reference in new issue