Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fit Shape теперь учитывает размеры меша #806

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions io_scene_xray/ops/edit_helpers/bone_shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ def vfunc(vtx_a, vtx_b, func):
matrix = mathutils.Matrix.Identity(4)
matrix_inverted = matrix
else:
matrix = hobj.matrix_local
matrix = hobj.matrix_world
matrix_inverted = matrix
try:
matrix_inverted = matrix.inverted()
Expand All @@ -311,15 +311,15 @@ def vfunc(vtx_a, vtx_b, func):
multiply = utils.version.get_multiply()

if stype == '1': # box
obb_mat = utils.bone.get_obb(bone, False, self.min_weight)
obb_mat = utils.bone.get_obb(bone, False, self.min_weight, in_world_coordinates=True)

if obb_mat and self.mode == 'OBB':
hobj.matrix_local = obb_mat
hobj.matrix_world = obb_mat

else:

# generate aabb
verts, weights = utils.bone.bone_vertices(bone)
verts, weights = utils.bone.bone_vertices(bone, in_world_coordinates=True)
for index, vtx in enumerate(verts):
weight = weights[index]
if weight >= self.min_weight:
Expand All @@ -330,15 +330,15 @@ def vfunc(vtx_a, vtx_b, func):
if vmax.x > vmin.x:
vcenter = (vmax + vmin) / 2
vscale = (vmax - vmin) / 2
hobj.matrix_local = multiply(
hobj.matrix_world = multiply(
matrix,
mathutils.Matrix.Translation(vcenter),
utils.bone.convert_vector_to_matrix(vscale)
)

else:
vertices = []
verts, weights = utils.bone.bone_vertices(bone)
verts, weights = utils.bone.bone_vertices(bone, in_world_coordinates=True)
for index, vtx in enumerate(verts):
weight = weights[index]
if weight >= self.min_weight:
Expand All @@ -354,7 +354,7 @@ def vfunc(vtx_a, vtx_b, func):
if stype == '2': # sphere
for vtx in vertices:
radius = max(radius, (vtx - vcenter).length)
hobj.matrix_local = multiply(
hobj.matrix_world = multiply(
matrix,
mathutils.Matrix.Translation(vcenter),
utils.bone.convert_vector_to_matrix((
Expand All @@ -365,17 +365,17 @@ def vfunc(vtx_a, vtx_b, func):
)

elif stype == '3': # cylinder
obb_mat = utils.bone.get_obb(bone, True, self.min_weight)
obb_mat = utils.bone.get_obb(bone, True, self.min_weight, in_world_coordinates=True)

if obb_mat and self.mode == 'OBB':
hobj.matrix_local = obb_mat
hobj.matrix_world = obb_mat

else:

# generate aabb
for vtx in vertices:
radius = max(radius, (vtx - vcenter).xy.length)
hobj.matrix_local = multiply(
hobj.matrix_world = multiply(
matrix,
mathutils.Matrix.Translation(vcenter),
utils.bone.convert_vector_to_matrix((
Expand Down
8 changes: 5 additions & 3 deletions io_scene_xray/utils/bone.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def _bone_objects(bone):
break


def bone_vertices(bone):
def bone_vertices(bone, in_world_coordinates=False):
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я бы сделал True, но оно где-то в OGF используется, а мне так не хочется лезть в это древнее зло)

verts = []
weights = []
for obj, vgi in _bone_objects(bone):
Expand All @@ -146,6 +146,8 @@ def bone_vertices(bone):
bmsh.from_object(obj, bpy.context.view_layer.depsgraph)
else:
bmsh.from_object(obj, bpy.context.scene)
if in_world_coordinates:
bmsh.transform(obj.matrix_world)
layer_deform = bmsh.verts.layers.deform.verify()
mesh.fix_ensure_lookup_table(bmsh.verts)
for vtx in bmsh.verts:
Expand All @@ -156,10 +158,10 @@ def bone_vertices(bone):
return verts, weights


def get_obb(bone, for_cylinder, min_weight):
def get_obb(bone, for_cylinder, min_weight, in_world_coordinates=False):
# create convex hull mesh for obb generation
bm = bmesh.new()
verts, weights = bone_vertices(bone)
verts, weights = bone_vertices(bone, in_world_coordinates)
for index, vert in enumerate(verts):
weight = weights[index]
if weight >= min_weight:
Expand Down
26 changes: 15 additions & 11 deletions tests/cases/test_bone_edit_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ def test_edit_shape(self):
directory=self.binpath(),
files=[{'name': 'test_fmt_armature.object'}]
)
msh = bpy.data.objects['Plane']
msh.location.z += 0.1
msh.scale *= 0.75
arm = bpy.data.objects['test_fmt_armature.object']
arm.scale *= 2
set_active_object(arm)
bone = arm.data.bones['Bone']
arm.data.bones.active = bone
Expand All @@ -40,17 +44,17 @@ def test_edit_shape(self):

helper.location = helper.scale = (1, 2, 3)
bpy.ops.io_scene_xray.edit_bone_shape_fit()
self.assertLess(helper.location.length, 0.1, msg='fit shape location')
self.assertLess(helper.scale.length, 0.1, msg='fit shape size')
self.assertAlmostEqualV(helper.location, (0, 0, 0.1), 1e-3, msg='fit shape location')
self.assertAlmostEqualV(helper.scale, (0.022, 0.022, 0.008), 1e-3, msg='fit shape size')
self.assertIsNotNone(get_object_helper(bpy.context), msg='a helper still shown')

bpy.ops.io_scene_xray.edit_bone_shape_apply()
self.assertIsNone(get_object_helper(bpy.context), msg='a helper is hidden')
self.assertTrue(_has_nonzero(bone.xray.shape.box_rot), msg='has box_rot')
self.assertFalse(_has_nonzero(bone.xray.shape.box_trn), msg='has zero box_trn')
self.assertTrue(_has_nonzero(bone.xray.shape.box_hsz), msg='has box_hsz')
scale = bone.xray.shape.get_matrix_basis().to_scale().to_tuple()
self.assertGreater(scale, (0.999, 0.999, 0.999), msg='close to 1:1 scale')
self.assertAlmostEqualV(bone.xray.shape.box_rot, (+1,0,0, 0,0,+1, 0,-1,0), 0.02, msg='has box_rot')
self.assertAlmostEqualV(bone.xray.shape.box_trn, (0, 0.1, 0), 1e-3, msg='has box_trn')
self.assertAlmostEqualV(bone.xray.shape.box_hsz, (0.022, 0.022, 0.008), 1e-3, msg='has box_hsz')
scale = bone.xray.shape.get_matrix_basis().to_scale()
self.assertAlmostEqualV(scale, (1, 1, 1), 1e-3, msg='close to 1:1 scale')
self.assertLess(reapply_max_difference(bone.xray.shape), 0.1, msg='box reapplies almost the same')

bone.xray.shape.type = '2'
Expand All @@ -59,9 +63,9 @@ def test_edit_shape(self):
helper = bpy.context.active_object
helper.location = helper.scale = (1, 2, 3)
bpy.ops.io_scene_xray.edit_bone_shape_fit()
self.assertLess(helper.location.length, 0.1, msg='fit shape sphere location')
self.assertAlmostEqualV(helper.location, (0, 0, 0.1), 1e-3, msg='fit shape sphere location')
bpy.ops.io_scene_xray.edit_bone_shape_apply()
self.assertGreater(bone.xray.shape.sph_rad, 0.01, msg='has sph_rad')
self.assertAlmostEqual(bone.xray.shape.sph_rad, 0.073, delta=1e-3, msg='has sph_rad')
self.assertLess(reapply_max_difference(bone.xray.shape), 0.1, msg='sphere reapplies almost the same')

bone.xray.shape.type = '3'
Expand All @@ -70,9 +74,9 @@ def test_edit_shape(self):
helper = bpy.context.active_object
helper.location = helper.scale = (1, 2, 3)
bpy.ops.io_scene_xray.edit_bone_shape_fit()
self.assertLess(helper.location.length, 0.1, msg='fit shape cylinder location')
self.assertAlmostEqualV(helper.location, (0, 0, 0.1), 1e-3, msg='fit shape cylinder location')
bpy.ops.io_scene_xray.edit_bone_shape_apply()
self.assertGreater(bone.xray.shape.cyl_hgh, 0.01, msg='has cyl_hgh')
self.assertAlmostEqual(bone.xray.shape.cyl_hgh, 0.016, delta=1e-3, msg='has cyl_hgh')
self.assertLess(reapply_max_difference(bone.xray.shape), 0.1, msg='cylinder reapplies almost the same')

op_edit()
Expand Down
12 changes: 12 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import bpy
import bmesh
import addon_utils
import mathutils

# addon modules
import io_scene_xray
Expand Down Expand Up @@ -172,6 +173,17 @@ def assertReportsNotContains(self, report_type=None, re_message=None):
report
))

def assertAlmostEqualV(self, first, second, delta, msg=None):
class V:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может однобуквенные идентификаторы лучше не создавать? И в таких именах assertAlmostEqualV писать в конце подробнее: assertAlmostEqualVec?

def __init__(self, v):
self.vec = mathutils.Vector(v)
def __sub__(self, right):
return (self.vec - right.vec).length
def __repr__(self):
return 'V' + repr(self.vec.to_tuple())

return self.assertAlmostEqual(V(first), V(second), msg=msg, delta=delta)

def getFullLogAsText(self):
return bpy.data.texts['xray_log'].as_string()

Expand Down