Browse Source

Merge pull request #290 from Jrius/matrix_anim_fix

Matrix anim fix
pull/297/head
Adam Johnson 3 years ago committed by GitHub
parent
commit
7458e4664f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 70
      korman/exporter/animation.py
  2. 5
      korman/exporter/camera.py
  3. 2
      korman/exporter/convert.py
  4. 2
      korman/exporter/material.py
  5. 2
      korman/exporter/mesh.py
  6. 2
      korman/exporter/physics.py
  7. 2
      korman/exporter/utils.py
  8. 5
      korman/properties/modifiers/avatar.py
  9. 6
      korman/properties/modifiers/gui.py
  10. 8
      korman/properties/modifiers/water.py
  11. 2
      korman/properties/prop_camera.py

70
korman/exporter/animation.py

@ -58,7 +58,7 @@ class AnimationConverter:
if isinstance(bo.data, bpy.types.Camera):
applicators.append(self._convert_camera_animation(bo, so, obj_fcurves, data_fcurves, anim_name, start, end))
else:
applicators.append(self._convert_transform_animation(bo, obj_fcurves, bo.matrix_basis, start=start, end=end))
applicators.append(self._convert_transform_animation(bo, obj_fcurves, bo.matrix_local, bo.matrix_parent_inverse, start=start, end=end))
if bo.plasma_modifiers.soundemit.enabled:
applicators.extend(self._convert_sound_volume_animation(bo.name, obj_fcurves, bo.plasma_modifiers.soundemit, start, end))
if isinstance(bo.data, bpy.types.Lamp):
@ -143,7 +143,7 @@ class AnimationConverter:
# If we exported any FOV animation at all, then we need to ensure there is an applicator
# returned from here... At bare minimum, we'll need the applicator with an empty
# CompoundController. This should be sufficient to keep CWE from crashing...
applicator = self._convert_transform_animation(bo, obj_fcurves, bo.matrix_basis,
applicator = self._convert_transform_animation(bo, obj_fcurves, bo.matrix_local, bo.matrix_parent_inverse,
allow_empty=has_fov_anim, start=start, end=end)
camera = self._mgr.find_create_object(plCameraModifier, so=so)
camera.animated = applicator is not None
@ -338,9 +338,16 @@ class AnimationConverter:
applicator.channel = channel
yield applicator
def _convert_transform_animation(self, bo, fcurves, xform, *, allow_empty: Optional[bool] = False,
def _convert_transform_animation(self, bo, fcurves, default_xform, adjust_xform, *, allow_empty: Optional[bool] = False,
start: Optional[int] = None, end: Optional[int] = None) -> Optional[plMatrixChannelApplicator]:
tm = self.convert_transform_controller(fcurves, bo.rotation_mode, xform, allow_empty=allow_empty,
if adjust_xform != mathutils.Matrix.Identity(4):
self._exporter().report.warn(("{}: Transform animation is not local and may export incorrectly. " +
"Please use Alt-P -> Clear Parent Inverse before animating objects to avoid issues.").format(bo.name), indent=1)
else:
# Adjustment matrix is identity, just pass None instead...
adjust_xform = None
tm = self.convert_transform_controller(fcurves, bo.rotation_mode, default_xform, adjust_xform, allow_empty=allow_empty,
start=start, end=end)
if tm is None and not allow_empty:
return None
@ -351,20 +358,62 @@ class AnimationConverter:
channel = plMatrixControllerChannel()
channel.controller = tm
applicator.channel = channel
channel.affine = utils.affine_parts(xform)
channel.affine = utils.affine_parts(default_xform)
return applicator
def convert_transform_controller(self, fcurves, rotation_mode: str, xform, *,
def convert_transform_controller(self, fcurves, rotation_mode: str, default_xform, adjust_xform, *,
allow_empty: Optional[bool] = False,
start: Optional[int] = None,
end: Optional[int] = None) -> Union[None, plCompoundController]:
if not fcurves and not allow_empty:
return None
pos = self.make_pos_controller(fcurves, "location", xform.to_translation(), start=start, end=end)
rot = self.make_rot_controller(fcurves, rotation_mode, xform, start=start, end=end)
scale = self.make_scale_controller(fcurves, "scale", xform.to_scale(), start=start, end=end)
if adjust_xform is not None:
# We have to edit the keyframes to make the anim local..
# In many cases this should work fine, but sometimes scale and rotation might
# still cause issues. Also, euler angles need to be converted to quaternion
# and back to eulers, which could cause issues. Not much we can do about it.
adjust_rotation = adjust_xform.to_quaternion()
adjust_scale = adjust_xform.to_scale()
# Helpers to adjust keyframes in case animation is not local (adjust_xform == identity)
def convert_pos_keyframe(pos):
# Position: can transform to local space without issues.
return tuple(adjust_xform * mathutils.Vector(pos))
def convert_rot_keyframe(rot):
# Rotation: may cause issues if scale is present.
if isinstance(rot, mathutils.Quaternion): # quaternion from an axis-angle
return adjust_rotation * rot
elif isinstance(rot, mathutils.Euler):
return (adjust_rotation * rot.to_quaternion()).to_euler(rot.order)
else: # tuple
if len(rot) == 4: # quat in a tuple
return (adjust_rotation * mathutils.Quaternion(rot))[:]
else: # XYZ euler in a tuple
rot = mathutils.Euler(rot, "XYZ").to_quaternion()
return (adjust_rotation * rot).to_euler("XYZ")[:]
def convert_scale_keyframe(scale):
# Scale: very likely to cause issues.
return [a * b for a, b in zip(adjust_scale, scale)]
convert_pos = convert_pos_keyframe
convert_rot = convert_rot_keyframe
convert_scale = convert_scale_keyframe
else:
# Don't change the keyframes at all, so we don't risk screwing them up.
convert_pos = None
convert_rot = None
convert_scale = None
pos = self.make_pos_controller(fcurves, "location", default_xform.to_translation(),
convert=convert_pos, start=start, end=end)
rot = self.make_rot_controller(fcurves, rotation_mode, default_xform,
convert=convert_rot, start=start, end=end)
scale = self.make_scale_controller(fcurves, "scale", default_xform.to_scale(),
convert=convert_scale, start=start, end=end)
if pos is None and rot is None and scale is None:
if not allow_empty:
return None
@ -490,7 +539,8 @@ class AnimationConverter:
default_xform = (default_xform[1], default_xform[0].x, default_xform[0].y, default_xform[0].z)
if convert is not None:
convert = lambda x: convert(mathutils.Quaternion(x[1:4], x[0]))[:]
convert_original = convert
convert = lambda x: convert_original(mathutils.Quaternion(x[1:4], x[0]))[:]
else:
convert = lambda x: mathutils.Quaternion(x[1:4], x[0])[:]

5
korman/exporter/camera.py

@ -132,7 +132,7 @@ class CameraConverter:
# specifying an actual center allows you to do interesting things like animate the center...
# Fascinating! Therefore, we will expose the Plasma Object...
if props.circle_center is None:
brain.center = hsVector3(*bo.location)
brain.center = hsVector3(*bo.matrix_world.translation)
else:
brain.centerObject = self._mgr.find_create_key(plSceneObject, bl=props.circle_center)
# This flag has no effect in CWE, but I'm using it for correctness' sake
@ -204,7 +204,8 @@ class CameraConverter:
# path object, but it makes more sense to me to just animate the camera with
# the details of the path...
pos_fcurves = tuple(i for i in helpers.fetch_fcurves(bo, False) if i.data_path == "location")
pos_ctrl = self._exporter().animation.convert_transform_controller(pos_fcurves, bo.rotation_mode, bo.matrix_basis)
pos_ctrl = self._exporter().animation.convert_transform_controller(pos_fcurves, bo.rotation_mode,
bo.matrix_local, bo.matrix_parent_inverse)
if pos_ctrl is None:
raise ExportError("'{}': Rail Camera lacks appropriate rail keyframes".format(bo.name))
path = plAnimPath()

2
korman/exporter/convert.py

@ -245,7 +245,7 @@ class Exporter:
ci = self.mgr.add_object(ci_cls, bl=bl, so=so)
# Now we have the "fun" work of filling in the CI
ci.localToWorld = utils.matrix44(bl.matrix_basis)
ci.localToWorld = utils.matrix44(bl.matrix_world)
ci.worldToLocal = ci.localToWorld.inverse()
ci.localToParent = utils.matrix44(bl.matrix_local)
ci.parentToLocal = ci.localToParent.inverse()

2
korman/exporter/material.py

@ -779,7 +779,7 @@ class MaterialConverter:
# will probably want to steal it for diabolical purposes... In MOUL, root objects are
# allowed, but that introduces a gotcha with regard to animated roots and PotS. Also,
# sharing root objects with a DCM seems to result in bad problems in game O.o
pl_env.position = hsVector3(*viewpt.location)
pl_env.position = hsVector3(*viewpt.matrix_world.translation)
if layer is not None:
layer.UVWSrc = plLayerInterface.kUVWReflect

2
korman/exporter/mesh.py

@ -658,7 +658,7 @@ class MeshConverter(_MeshManager):
# FIXME: Can some of this be generalized?
geospan.props |= (plGeometrySpan.kWaterHeight | plGeometrySpan.kLiteVtxNonPreshaded |
plGeometrySpan.kPropReverseSort | plGeometrySpan.kPropNoShadow)
geospan.waterHeight = bo.location[2]
geospan.waterHeight = bo.matrix_world.translation[2]
return [_GeoSpan(bo, blmat, geospan)], None
else:
geospans = [None] * len(materials)

2
korman/exporter/physics.py

@ -93,7 +93,7 @@ class PhysicsConverter:
if so.sim is None:
simIface = self._mgr.add_object(pl=plSimulationInterface, bl=bo)
physical = self._mgr.add_object(pl=plGenericPhysical, bl=bo, name=name)
physical = self._mgr.add_object(pl=plGenericPhysical, bl=bo)
simIface.physical = physical.key
physical.object = so.key

2
korman/exporter/utils.py

@ -103,8 +103,8 @@ def temporary_mesh_object(source : bpy.types.Object) -> bpy.types.Object:
obj = bpy.data.objects.new(source.name, source.to_mesh(bpy.context.scene, True, "RENDER"))
obj.draw_type = "WIRE"
obj.matrix_basis, obj.matrix_world = source.matrix_basis, source.matrix_world
obj.parent = source.parent
obj.matrix_local, obj.matrix_world = source.matrix_local, source.matrix_world
bpy.context.scene.objects.link(obj)
try:

5
korman/properties/modifiers/avatar.py

@ -64,10 +64,7 @@ class PlasmaLadderModifier(PlasmaModifierProperties):
ladderVec = self.facing_object.matrix_world.translation - bo.matrix_world.translation
else:
# Make our own artificial target -1.0 units back on the local Y axis.
world = bo.matrix_world.copy()
world.invert()
target = bo.location - (mathutils.Vector((0.0, 1.0, 0.0)) * world)
ladderVec = target - bo.matrix_local.translation
ladderVec = mathutils.Vector((0, -1, 0)) * bo.matrix_world.inverted()
mod.ladderView = hsVector3(ladderVec.x, ladderVec.y, 0.0)
mod.ladderView.normalize()

6
korman/properties/modifiers/gui.py

@ -230,7 +230,7 @@ class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
if self.clickable_region is None:
with utils.bmesh_object("{}_Journal_ClkRgn".format(self.key_name)) as (rgn_obj, bm):
bmesh.ops.create_cube(bm, size=(6.0))
bmesh.ops.transform(bm, matrix=mathutils.Matrix.Translation(bo.location - rgn_obj.location),
bmesh.ops.transform(bm, matrix=mathutils.Matrix.Translation(bo.matrix_world.translation - rgn_obj.matrix_world.translation),
space=rgn_obj.matrix_world, verts=bm.verts)
rgn_obj.plasma_object.enabled = True
rgn_obj.hide_render = True
@ -466,8 +466,8 @@ class PlasmaLinkingBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
if self.clickable_region is None:
with utils.bmesh_object("{}_LinkingBook_ClkRgn".format(self.key_name)) as (rgn_obj, bm):
bmesh.ops.create_cube(bm, size=(6.0))
rgn_offset = mathutils.Matrix.Translation(self.clickable.location - bo.location)
bmesh.ops.transform(bm, matrix=rgn_offset, space=bo.matrix_world, verts=bm.verts)
rgn_offset = mathutils.Matrix.Translation(self.clickable.matrix_world.translation - rgn_obj.matrix_world.translation)
bmesh.ops.transform(bm, matrix=rgn_offset, space=rgn_obj.matrix_world, verts=bm.verts)
rgn_obj.plasma_object.enabled = True
rgn_obj.hide_render = True
yield rgn_obj

8
korman/properties/modifiers/water.py

@ -114,7 +114,7 @@ class PlasmaSwimRegion(idprops.IDPropObjectMixin, PlasmaModifierProperties, bpy.
losdbs = ["kLOSDBSwimRegion"]
member_group = "kGroupLOSOnly" if exporter.mgr.getVer() != pvMoul else "kGroupStatic"
if bo.plasma_modifiers.water_basic.enabled:
exporter.physics.generate_flat_proxy(bo, so, z_coord=bo.location[2],
exporter.physics.generate_flat_proxy(bo, so, z_coord=bo.matrix_world.translation[2],
member_group=member_group,
losdbs=losdbs)
else:
@ -125,7 +125,7 @@ class PlasmaSwimRegion(idprops.IDPropObjectMixin, PlasmaModifierProperties, bpy.
# Detector region bounds
if self.region is not None:
region_so = exporter.mgr.find_create_object(plSceneObject, bl=self.region)
# Good news: if this phys has already been exported, this is basically a noop
member_group = "kGroupDetector" if exporter.mgr.getVer() == "pvMoul" else "kGroupLOSOnly"
exporter.physics.generate_physical(self.region, region_so,
@ -258,7 +258,7 @@ class PlasmaWaterModifier(idprops.IDPropMixin, PlasmaModifierProperties, bpy.typ
# Stuff we expose
state = waveset.state
state.rippleScale = self.ripple_scale
state.waterHeight = bo.location[2]
state.waterHeight = bo.matrix_world.translation[2]
state.windDir = wind_dir
state.specVector = hsVector3(self.noise / 100.0, self.specular_start, self.specular_end)
state.specularTint = hsColorRGBA(*self.specular_tint, alpha=self.specular_alpha)
@ -273,7 +273,7 @@ class PlasmaWaterModifier(idprops.IDPropMixin, PlasmaModifierProperties, bpy.typ
state.envCenter = dem.position
state.envRefresh = dem.refreshRate
else:
state.envCenter = hsVector3(*bo.location)
state.envCenter = hsVector3(*bo.matrix_world.translation)
state.envRefresh = 0.0
state.envRadius = self.envmap_radius

2
korman/properties/prop_camera.py

@ -225,7 +225,7 @@ class PlasmaCameraProperties(bpy.types.PropertyGroup):
"""Gets the circle camera radius for this camera when it is attached to the given Object"""
assert bo is not None
if self.circle_center is not None:
vec = bo.location - self.circle_center.location
vec = bo.matrix_world.translation - self.circle_center.matrix_world.translation
return vec.magnitude
return self.circle_radius_value

Loading…
Cancel
Save