implement collision primitives
This commit is contained in:
parent
e9f442d052
commit
3d0e9b98ee
|
@ -18,7 +18,7 @@ class CollisionPrimitiveShape(Enum):
|
||||||
# ELLIPSOID = 1
|
# ELLIPSOID = 1
|
||||||
CYLINDER = 2
|
CYLINDER = 2
|
||||||
# MESH = 3
|
# MESH = 3
|
||||||
CUBE = 4
|
BOX = 4
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ModelTransform:
|
class ModelTransform:
|
||||||
|
@ -47,10 +47,10 @@ class GeometrySegment:
|
||||||
class CollisionPrimitive:
|
class CollisionPrimitive:
|
||||||
""" Class representing a 'SWCI' section in a .msh file. """
|
""" Class representing a 'SWCI' section in a .msh file. """
|
||||||
|
|
||||||
collision_primitive_shape: CollisionPrimitiveShape
|
shape: CollisionPrimitiveShape = CollisionPrimitiveShape.SPHERE
|
||||||
radius: float
|
radius: float = 0.0
|
||||||
height: float
|
height: float = 0.0
|
||||||
length: float
|
length: float = 0.0
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Model:
|
class Model:
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
Model objects. """
|
Model objects. """
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
import math
|
||||||
from typing import List, Set, Dict, Tuple
|
from typing import List, Set, Dict, Tuple
|
||||||
from itertools import zip_longest
|
from itertools import zip_longest
|
||||||
from .msh_model import *
|
from .msh_model import *
|
||||||
|
@ -44,6 +45,9 @@ def gather_models() -> List[Model]:
|
||||||
mesh_scale = convert_vector_space(get_object_worldspace_scale(obj))
|
mesh_scale = convert_vector_space(get_object_worldspace_scale(obj))
|
||||||
scale_segments(mesh_scale, model.geometry)
|
scale_segments(mesh_scale, model.geometry)
|
||||||
|
|
||||||
|
if get_is_collision_primitive(obj):
|
||||||
|
model.collisionprimitive = get_collision_primitive(obj)
|
||||||
|
|
||||||
models_list.append(model)
|
models_list.append(model)
|
||||||
|
|
||||||
return models_list
|
return models_list
|
||||||
|
@ -163,6 +167,56 @@ def get_is_model_hidden(obj: bpy.types.Object) -> bool:
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_is_collision_primitive(obj: bpy.types.Object) -> bool:
|
||||||
|
""" Gets if a Blender object represents a collision primitive. """
|
||||||
|
|
||||||
|
name = obj.name.lower()
|
||||||
|
|
||||||
|
return name.startswith("p_")
|
||||||
|
|
||||||
|
def get_collision_primitive(obj: bpy.types.Object) -> CollisionPrimitive:
|
||||||
|
""" Gets the CollisionPrimitive of an object or raises an error if
|
||||||
|
it can't. """
|
||||||
|
|
||||||
|
primitive = CollisionPrimitive()
|
||||||
|
primitive.shape = get_collision_primitive_shape(obj)
|
||||||
|
|
||||||
|
if primitive.shape == CollisionPrimitiveShape.SPHERE:
|
||||||
|
# Tolerate a 5% difference to account for icospheres with 2 subdivisions.
|
||||||
|
if not (math.isclose(obj.dimensions[0], obj.dimensions[1], rel_tol=0.05) and
|
||||||
|
math.isclose(obj.dimensions[0], obj.dimensions[2], rel_tol=0.05)):
|
||||||
|
raise RuntimeError(f"Object '{obj.name}' is being used as a sphere collision "
|
||||||
|
f"primitive but it's dimensions are not uniform!")
|
||||||
|
|
||||||
|
primitive.radius = max(obj.dimensions[0], obj.dimensions[1], obj.dimensions[2]) * 0.5
|
||||||
|
elif primitive.shape == CollisionPrimitiveShape.CYLINDER:
|
||||||
|
if not math.isclose(obj.dimensions[0], obj.dimensions[1], rel_tol=0.001):
|
||||||
|
raise RuntimeError(f"Object '{obj.name}' is being used as a cylinder collision "
|
||||||
|
f"primitive but it's X and Y dimensions are not uniform!")
|
||||||
|
primitive.radius = obj.dimensions[0] * 0.5
|
||||||
|
primitive.height = obj.dimensions[2] * 0.5
|
||||||
|
elif primitive.shape == CollisionPrimitiveShape.BOX:
|
||||||
|
primitive.radius = obj.dimensions[0] * 0.5
|
||||||
|
primitive.height = obj.dimensions[2] * 0.5
|
||||||
|
primitive.length = obj.dimensions[1] * 0.5
|
||||||
|
|
||||||
|
return primitive
|
||||||
|
|
||||||
|
def get_collision_primitive_shape(obj: bpy.types.Object) -> CollisionPrimitiveShape:
|
||||||
|
""" Gets the CollisionPrimitiveShape of an object or raises an error if
|
||||||
|
it can't. """
|
||||||
|
|
||||||
|
name = obj.name.lower()
|
||||||
|
|
||||||
|
if "sphere" in name or "sphr" in name or "spr" in name:
|
||||||
|
return CollisionPrimitiveShape.SPHERE
|
||||||
|
if "cylinder" in name or "cyln" in name or "cyl" in name:
|
||||||
|
return CollisionPrimitiveShape.CYLINDER
|
||||||
|
if "box" in name:
|
||||||
|
return CollisionPrimitiveShape.BOX
|
||||||
|
|
||||||
|
raise RuntimeError(f"Object '{obj.name}' has no primitive type specified in it's name!")
|
||||||
|
|
||||||
def convert_vector_space(vec: Vector) -> Vector:
|
def convert_vector_space(vec: Vector) -> Vector:
|
||||||
return Vector(vec.xzy)
|
return Vector(vec.xzy)
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,12 @@ def _write_modl(modl: Writer, model: Model, index: int, material_index: Dict[str
|
||||||
with geom.create_child("SEGM") as segm:
|
with geom.create_child("SEGM") as segm:
|
||||||
_write_segm(segm, segment, material_index)
|
_write_segm(segm, segment, material_index)
|
||||||
|
|
||||||
# TODO: Collision Primitive
|
if model.collisionprimitive is not None:
|
||||||
|
with modl.create_child("SWCI") as swci:
|
||||||
|
swci.write_u32(model.collisionprimitive.shape.value)
|
||||||
|
swci.write_f32(model.collisionprimitive.radius)
|
||||||
|
swci.write_f32(model.collisionprimitive.height)
|
||||||
|
swci.write_f32(model.collisionprimitive.length)
|
||||||
|
|
||||||
def _write_tran(tran: Writer, transform: ModelTransform):
|
def _write_tran(tran: Writer, transform: ModelTransform):
|
||||||
tran.write_f32(1.0, 1.0, 1.0) # Scale, ignored by modelmunge
|
tran.write_f32(1.0, 1.0, 1.0) # Scale, ignored by modelmunge
|
||||||
|
|
Loading…
Reference in New Issue