def make_pyramid_mesh(side=20.0): """Create a pyramid from vertices and faces.""" mesh = rt.mesh() mesh.numverts = 4 mesh.numfaces = 4 halfside = side / 2.0 rt.SetVert(mesh, 1, rt.Point3(0.0, 0.0, side)) rt.SetVert(mesh, 2, rt.Point3(-halfside, -halfside, 0.0)) rt.SetVert(mesh, 3, rt.Point3(-halfside, halfside, 0.0)) rt.SetVert(mesh, 4, rt.Point3(halfside, 0.0, 0.0)) rt.setFace(mesh, 1, 1, 2, 3) set_edge_visibility(mesh, 1, True, True, False) rt.setFace(mesh, 2, 1, 3, 4) set_edge_visibility(mesh, 2, True, True, False) rt.setFace(mesh, 3, 1, 4, 2) set_edge_visibility(mesh, 2, True, True, False) rt.setFace(mesh, 4, 2, 3, 4) set_edge_visibility(mesh, 2, True, True, False) rt.update(mesh) return mesh
def mirrorNode(node, mirrorAxis): original_parent = node.GetParent() if MAXVERSION() < MAX2017: temp_mesh = MaxPlus.Factory.CreateGeomObject(MaxPlus.ClassIds.Sphere) temp_parent = MaxPlus.Factory.CreateNode(temp_mesh) else: temp_parent = rt.sphere() node.SetParent(temp_parent) rtNode = rt.getNodeByName(temp_parent.GetName()) p = rt.Point3(1, 1, 1) if mirrorAxis == "X": p = rt.Point3(-1, 1, 1) elif mirrorAxis == "Y": p = rt.Point3(1, -1, 1) elif mirrorAxis == "Z": p = rt.Point3(1, 1, -1) else: print("Error axis do not match") rt.scale(rtNode, p) node.SetParent(original_parent) MaxPlus.INode.Delete(temp_parent) if MAXVERSION() < MAX2017 else rt.delete( temp_parent)
def showcase_materials(materials): """Create a teapot sample and a visible label for each provided material""" num_materials = len(materials) diff = 360.0 / num_materials teapot_radius = 5.0 radius = 50.0 text_radius = 90.0 index = 0 i = 0 for mat in materials: position = rt.Point3(radius, 0, 0) rot = rt.angleAxis(i, rt.Point3(0, 0, 1)) teapot = rt.teapot() teapot.radius = teapot_radius teapot.position = position teapot.rotation = rot teapot.Material = mat print_material_properties(mat) create_text(text_radius, 0, rot, mat.name) if index < 24: rt.setMeditMaterial(index + 1, mat) index += 1 i += diff
def main(): """Demonstrate cloning""" rt.resetMaxFile(rt.Name('noPrompt')) obj = rt.sphere(radius=3) create_instance_clones(obj, 10, rt.Point3(5, 0, 0)) rt.MaxOps.CloneNodes(obj, cloneType=INST, offset=rt.Point3(0, 25, 0), expandHierarchy=True)
def color_pyramid_mesh(mesh): '''Add two color vertices, and refer them in the faces (color the pyramid).''' rt.setNumCPVVerts(mesh, 2, True) rt.setVertColor(mesh, 1, rt.Point3(255, 0, 0)) rt.setVertColor(mesh, 2, rt.Point3(0, 0, 255)) rt.buildVCFaces(mesh) rt.setVCFace(mesh, 1, 1, 1, 2) rt.setVCFace(mesh, 2, 1, 2, 2) rt.setVCFace(mesh, 3, 2, 2, 2) rt.setVCFace(mesh, 4, 1, 1, 1) rt.setCVertMode(mesh, True) rt.update(mesh)
def create_spheres(): '''Create a scene made of spiralling spheres.''' sphere = rt.sphere(radius=6.0) revolutions = 9 * 360 radius = 40.0 z_sphere = 0.0 # cloning the original sphere to create the spiral effect for i in range(0, revolutions, 20): # the maxscript CloneNodes method accepts a named argument called 'newNodes' # the argument must be sent by reference as it serves as an output argument # since the argument is not also an input argument, we can simply initialize # the byref() object as 'None' # the output argument along with the call result is then returned in a tuple # note: 'newNodes' returns an array of cloned nodes # in the current case, only one element is cloned result, nodes = rt.MaxOps.CloneNodes(sphere, cloneType=INST, newNodes=pymxs.byref(None)) radians = math.radians(i) x_sphere = radius * math.cos(radians) y_sphere = radius * math.sin(radians) # note: 'newNodes' returned an array of cloned nodes # in the current case, only one element is cloned nodes[0].Position = rt.Point3(x_sphere, y_sphere, z_sphere) z_sphere += 1.0 radius -= 0.20
def zdepthchannel(): '''Access the Z-Depth Channel''' prev_renderer = rt.renderers.current rt.renderers.current = rt.Default_Scanline_Renderer() voxelbox = re.compile("^VoxelBox") for tbd in filter(lambda o: voxelbox.match(o.name), list(rt.objects)): rt.delete(tbd) zdepth_name = rt.Name("zdepth") rbmp = rt.render(outputsize=rt.Point2(32, 32), channels=[zdepth_name], vfb=False) z_d = rt.getChannelAsMask(rbmp, zdepth_name) rt.progressStart("Rendering Voxels...") for y in range(1, rbmp.height): print("y =", y) if not rt.progressupdate(100.0 * y / rbmp.height): break pixel_line = rt.getPixels(rbmp, rt.Point2(0, y - 1), rbmp.width) z_line = rt.getPixels(z_d, rt.Point2(0, y - 1), rbmp.width) for x in range(1, rbmp.width): print("x =", x, z_line[x].value) box = rt.box(width=10, length=10, height=(z_line[x].value / 2)) box.pos = rt.Point3(x * 10, -y * 10, 0) box.wirecolor = pixel_line[x] box.name = rt.uniqueName("VoxelBox") rt.progressEnd() rt.renderers.current = prev_renderer
def _create_curve( shape_name, shape_data, curve_size, translate_offset, scale, order, mirror, nurbs_set=None): nurbs_set = nurbs_set or rt.NURBSSet() new_shapes = list() curve_cvs = shape_data['cvs'] degree = shape_data['degree'] curve_order = degree + 1 total_knots = curve_order + len(curve_cvs) transformed_cvs = list() cvs = [CurveCV(pt) for pt in copy(curve_cvs)] for i, cv in enumerate(cvs): cv *= curve_size * scale.reorder(order) cv += translate_offset.reorder(order) cv *= CurveCV.mirror_vector()[mirror] cv = cv.reorder(order) transformed_cvs.append(cv) knots = shape_data.get('knots', None) if not knots: # TODO: Check is this is valid knots = tuple([float(i) for i in range(total_knots)]) curve = rt.NURBSCVCurve(name=shape_name, order=curve_order, numCVs=len(cvs), numKnots=len(knots)) for i, knot in enumerate(knots): rt.setKnot(curve, i + 1, knot) for i, cv in enumerate(cvs): new_cv = rt.NURBSControlVertex(rt.Point3(*cv)) rt.setCV(curve, i + 1, new_cv) rt.appendObject(nurbs_set, curve) new_shapes.append(curve) return nurbs_set, new_shapes
def create_expose_transform( pos=None, size=1.0, is_center_marker=True, is_axis_tripod=False, is_cross=False, is_box=False, color=None): """ Creates a new expose transform node in the scene :param pos: :param size: :param is_center_marker: :param is_axis_tripod: :param is_cross: :param is_box: :param color: :return: """ pos = pos or [0, 0, 0] if rt.classOf(pos) != rt.Point3: pos = rt.Point3(*pos) if color and rt.classOf(color) != rt.color: color = rt.color(*color) if not color: color = rt.green expose_transform = rt.ExposeTM( pos=pos, size=size, centermarker=is_center_marker, axistripod=is_axis_tripod, cross=is_cross, box=is_box) expose_transform.wirecolor = color return expose_transform
def create_circle_control(name, init_pos=None, radius=10, color=None, axis='z'): """ Creates a circle control :param name: str :param init_pos: list(float, float, float) or None :param radius: float :param color: list(float, float, float) or rt.Point3 :param axis: str """ pos = init_pos or [0, 0, 0] if rt.classOf(pos) != rt.Point3: pos = rt.Point3(*pos) if color and rt.classOf(color) != rt.color: color = rt.color(*color) if not color: color = rt.yellow rt.setCommandPanelTaskMode(rt.Name('modify')) ctrl_name = rt.uniquename(name) base_circle = rt.circle(name=ctrl_name, radius=radius, steps=6, pos=pos) if str(axis).lower() == 'x': xform_mod = rt.xform() rt.addModifier(base_circle, xform_mod) rt.setProperty(xform_mod.gizmo, 'rotation', rt.eulerAngles(0, 90, 0)) elif str(axis).lower() == 'y': xform_mod = rt.xform() rt.addModifier(base_circle, xform_mod) rt.setProperty(xform_mod.gizmo, 'rotation', rt.eulerAngles(90, 0, 0)) base_circle.wirecolor = color rt.convertTo(base_circle, rt.SplineShape) return base_circle
def create_gizmo_control(name, init_pos=None, radius=10, color=None): """ Creates a gizmo control :param name: str :param init_pos: :param radius: :param color: :return: """ pos = init_pos or [0, 0, 0] if rt.classOf(pos) != rt.Point3: pos = rt.Point3(*pos) if color and rt.classOf(color) != rt.color: color = rt.color(*color) if not color: color = rt.yellow circle_a = create_circle_control(name=name, radius=radius, color=color, init_pos=pos, axis='x') circle_b = create_circle_control(name=name, radius=radius, color=color, init_pos=pos, axis='y') circle_c = create_circle_control(name=name, radius=radius, color=color, init_pos=pos, axis='z') gizmo_ctrl = add_shape(circle_a, circle_b) gizmo_ctrl = add_shape(gizmo_ctrl, circle_c) return gizmo_ctrl
def create_text(pos, message): """Create a text.""" tex = rt.text() tex.size = Y_STEP tex.text = message tex.position = rt.Point3(pos.x, pos.y - OBJECT_DIMENSION, pos.z) tex.wirecolor = rt.Color(255, 128, 255)
def get_pole_vector_position(bone_a, bone_b, bone_c, pole_vector_distance=1.0, create_locator=False): """ Calculates the correct pole vector position NOTE: Given nodes must be coplanar (must be on the same plane) :param bone_a: :param bone_b: :param bone_c: :param pole_vector_distance: :param create_locator: :return: """ bone_a_pos = rt.Point3(*bone_a.position) bone_b_pos = rt.Point3(*bone_b.position) bone_c_pos = rt.Point3(*bone_c.position) # get initial vectors ab_vec = bone_b_pos - bone_a_pos ac_vec = bone_c_pos - bone_a_pos # calculate projection length ab_ac_dot = rt.dot(ab_vec, ac_vec) proj = float(ab_ac_dot) / float(rt.length(ac_vec)) # calculate project vector by normalizing ac_vec and multiplying # that normalized vector by the projection length ac_vec_normalized = rt.normalize(ac_vec) proj_vec = ac_vec_normalized * proj # get the vector from the projected vector to the bone_b position b_proj_vec = bone_b_pos - (bone_a_pos + proj_vec) # calculate final pole vector position b_proj_vec *= pole_vector_distance final_pos = b_proj_vec + bone_b_pos if create_locator: test_point_helper = node_utils.create_point_helper( size=15.0, is_center_marker=False, is_box=True) rt.setProperty(test_point_helper, 'position', final_pos) return test_point_helper return final_pos
def create_borg(obj, num, spacing): """Create a bunch of clones of the provided object""" for i in range(num): for j in range(num): for k in range(num): if i or j or k: point = rt.Point3(i * spacing, j * spacing, k * spacing) rt.MaxOps.CloneNodes(obj, cloneType=INST, offset=point)
def getAvgPosFromVertex(self, object, vertIndexList): sumPos = rt.Point3(0, 0, 0) for v in vertIndexList: sumPos += object.verts[v].pos avgPos = sumPos / len(vertIndexList) return avgPos
def create_text(xpos, ypos, rot, message): """Create a visible label on the ground for a given teapot""" tex = rt.text() tex.size = 10 tex.text = message tex.position = rt.Point3(xpos, ypos, 0) tex.rotation = rot tex.wireColor = rt.Color(255, 128, 255)
def main(): """Create a mesh, color it, and output information about its maps.""" # reset the scene rt.resetMaxFile(rt.Name('noPrompt')) # create a mesh mesh = make_pyramid_mesh() print("Updating the color per vertex channel") rt.setNumCPVVerts(mesh, 2) rt.buildVCFaces(mesh) rt.setVertColor(mesh, 1, rt.Color(255, 0, 0)) rt.setVertColor(mesh, 2, rt.Color(0, 0, 255)) rt.setVCFace(mesh, 1, rt.Point3(1, 1, 2)) rt.setVCFace(mesh, 2, rt.Point3(1, 2, 2)) rt.setVCFace(mesh, 3, rt.Point3(2, 2, 2)) rt.setVCFace(mesh, 4, rt.Point3(1, 1, 1)) rt.setCVertMode(mesh, True) rt.update(mesh) output_channels(mesh)
def tree_of_spheres(parent, width, xinc, depth, maxdepth): """Create a tree of spheres.""" if depth == maxdepth: return for i in range(width): sphere = create_sphere() pos = parent.pos sphere.pos = rt.Point3(pos.x + i * xinc, 0, pos.z + 15) sphere.Parent = parent tree_of_spheres(sphere, width, xinc * width, depth + 1, maxdepth)
def reset_pivot_to_origin(node_name, align_to_world=False): """ Resets the pivot of the given node to the origin of the world :param node_name: :param align_to_world: """ node = node_utils.get_pymxs_node(node_name) node.pivot = rt.Point3(0, 0, 0) if align_to_world: rt.WorldAlignPivot(node)
def draw_line_between_two_points(point_a, point_b): """ Draws a spline curve where point_a is its starting point and point_b its end point :param point_a: list(float, float, float) or rt.Point3 :param point_b: list(float, float, float) or rt.Point3 :return: str, name of the new spline """ if rt.classOf(point_a) != rt.Point3: point_a = rt.Point3(*point_a) if rt.classOf(point_b) != rt.Point3: point_b = rt.Point3(*point_b) spline = rt.SplineShape(pos=point_a) rt.addNewSpline(spline) rt.addKnot(spline, 1, rt.Name('corner'), rt.Name('line'), point_a) rt.addKnot(spline, 1, rt.Name('corner'), rt.Name('line'), point_b) rt.updateShape(spline) return spline
def layout_objects(title, cases, y_position, x_offset_text=-45): """Layout a list of nodes in a line""" create_text(rt.Point3(x_offset_text, y_position, 0), title) x_position = 0.0 for gen in cases: gen.Position = rt.point3(x_position, y_position, 0) x_position += X_STEP if (x_position % 260.0) < 0.001: x_position = 0.0 y_position += Y_STEP return y_position
def animate_transform(thing): '''Records an animation on the provided object''' # select the object to animate so we will see the keyframes in the timeslider rt.select(thing) # animate with mx.animate(True): with mx.redraw(True): with mx.attime(30): thing.pos = rt.Point3(50, 0, 0) with mx.attime(60): thing.Pos = rt.Point3(100, 50, 0) with mx.attime(90): thing.Pos = rt.Point3(50, 100, 0) with mx.attime(120): thing.Pos = rt.Point3(0, 100, 0) with mx.attime(150): thing.Pos = rt.Point3(-50, 50, 0) with mx.attime(180): thing.Pos = rt.Point3(0, 0, 0)
def TransformPosition(self, position, weightList, transformList, frames): outPositionList = [] for f in range(0, frames): # transform the vertex for given frame p = rt.Point3(0, 0, 0) for w in range(0, len(weightList)): p += position * rt.inverse(transformList[w][0]) * transformList[w][f] * weightList[w] # and store them in outPositionList outPositionList.append(p) return outPositionList
def findVertWithMaxError(self, regularAllVertPosList, referenceAllVertPosList): print 'findVertWithMaxError' maxError = 0 maxErrorVertexIndex = 0 maxErrorVertPos = rt.Point3(0,0,0) for v in range(1, len(regularAllVertPosList)): error = self.computeErrorForOneVert(regularAllVertPosList[v], referenceAllVertPosList[v]) # print 'v, error',v, error if error > maxError: maxError = error maxErrorVertexIndex = v maxErrorVertPos = regularAllVertPosList[v][0] # print 'maxErrorVertexIndex ', maxErrorVertexIndex # print 'maxError ', maxError return maxErrorVertexIndex, maxErrorVertPos, maxError
def create_box_control(name, init_pos=None, length=10, width=10, height=10, color=None): """ Creates a box control :param name: str :param init_pos: :param length: :param width: :param height: :param color: :return: """ pos = init_pos or [0, 0, 0] if rt.classOf(pos) != rt.Point3: pos = rt.Point3(*pos) if color and rt.classOf(color) != rt.color: color = rt.color(*color) if not color: color = rt.yellow rt.setCommandPanelTaskMode(rt.Name('modify')) base_box = rt.Box( lengthsegs=1, widthsegs=1, heightsegs=1, length=length, width=width, height=height, mapcoords=True, pos=pos, isSelected=True) rt.select(base_box) rt.convertTo(base_box, rt.PolyMeshObject) rt.subobjectLevel = 2 edge_bitarray = rt.BitArray() edge_indices = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] edge_bitarray.count = len(edge_indices) for i, index in enumerate(edge_indices): edge_bitarray[i] = index base_box.EditablePoly.SetSelection(rt.Name('Edge'), edge_bitarray) ctrl_name = rt.uniquename(name) base_box.EditablePoly.createShape(ctrl_name, False, base_box) rt.subobjectLevel = 0 rt.delete(base_box) box_ctrl = rt.getNodeByName(ctrl_name) rt.convertTo(box_ctrl, rt.SplineShape) box_ctrl.wirecolor = color rt.CenterPivot(box_ctrl) transform.reset_xform_and_collapse(box_ctrl, freeze=True) return box_ctrl
def addNewHelperBoneToWorstVertexList(self): worstVertIndex, worstVertPos, worstError = \ self.computeUtil.findVertWithMaxError(self.regularMeshData.allVertPosList, self.referenceMeshData.allVertPosList) neighborVertsCore = self.vertUtil.getNeighborVertex( self.regularMeshData.obj, worstVertIndex) neighborVertsOuter = [] for v in neighborVertsCore: neighbors = self.vertUtil.getNeighborVertex( self.regularMeshData.obj, v) for n in neighbors: if self.util.findInList(neighborVertsCore, n) == -1: neighborVertsOuter.append(n) neighborVertsOuter2 = [] for v in neighborVertsOuter: neighbors = self.vertUtil.getNeighborVertex( self.regularMeshData.obj, v) for n in neighbors: if self.util.findInList(neighborVertsCore + neighborVertsOuter, n) == -1: neighborVertsOuter2.append(n) neighborVertsOuterAll = self.util.makeUnique(neighborVertsOuter + neighborVertsOuter2) avgPos = self.vertUtil.getAvgPosFromVertex(self.regularMeshData.obj, neighborVertsCore) newBn = rt.Point(position=avgPos, wireColor=rt.Point3(0, 255, 0), size=8, box=True, cross=False, name='Point_') newBn.Name = self.option.helperBonePrefix + newBn.Name + str( len(self.regularMeshData.helperBoneList)) # newBn.parent = rt.getNodeByName('Bip001 L UpperArm') return newBn, neighborVertsCore, neighborVertsOuterAll
def create_circle_with_triangle_control(name, init_pos=None, radius=10, corner_radius=0, color=None, axis='z'): """ Creates a circle with a triangle inside control :param name: str :param init_pos: :param radius: :param corner_radius: :param color: :param axis: :return: """ pos = init_pos or [0, 0, 0] if rt.classOf(pos) != rt.Point3: pos = rt.Point3(*pos) if color and rt.classOf(color) != rt.color: color = rt.color(*color) if not color: color = rt.yellow circle_ctrl = create_circle_control(name, init_pos=pos, radius=radius, color=color, axis=axis) triangle_ctrl = rt.Ngon( radius=radius, cornerRadius=corner_radius, nsides=3, circular=False, scribe=1, pos=pos, isSelected=True) xform_mod = rt.xform() rt.addModifier(triangle_ctrl, xform_mod) rt.setProperty(xform_mod.gizmo, 'rotation', rt.eulerAngles(0, 0, -90)) if str(axis).lower() == 'x': xform_mod = rt.xform() rt.addModifier(triangle_ctrl, xform_mod) rt.setProperty(xform_mod.gizmo, 'rotation', rt.eulerAngles(0, -90, 0)) elif str(axis).lower() == 'y': xform_mod = rt.xform() rt.addModifier(triangle_ctrl, xform_mod) rt.setProperty(xform_mod.gizmo, 'rotation', rt.eulerAngles(-90, 0, 0)) final_ctrl = add_shape(circle_ctrl, triangle_ctrl) return final_ctrl
def move_node(node_name, amount=None, move_vertices=False, use_local_axis=True): """ Moves given node :param node_name: :param amount: :param move_vertices: :param use_local_axis: :return: """ node_to_move = node_utils.get_pymxs_node(node_name) if not node_to_move: return amount = amount or [0, 0, 0] if rt.classOf(amount) != rt.Point3: amount = rt.Point3(*amount) if move_vertices: xform_mod = rt.xform() rt.addModifier(node_to_move, xform_mod) rt.setProperty(xform_mod.gizmo, 'position', amount) rt.CollapseStack(node_to_move) else: if use_local_axis: coordsys = getattr(rt, '%coordsys_context') local_coordsys = rt.Name('local') prev_coordsys = coordsys(local_coordsys, None) # store current coordsys rt.move(node_to_move, amount) # this is done in local axis coordsys(prev_coordsys, None) # restore previous coordsys else: rt.move(node_to_move, amount)
def create_rectangle_control(name, init_pos=None, length=10.0, width=10.0, corner_radius=0.0, color=None, axis='z'): """ Creates a rectangle control :param name: str :param init_pos: :param length: :param width: :param corner_radius: :param color: :param axis: :return: """ pos = init_pos or [0, 0, 0] if rt.classOf(pos) != rt.Point3: pos = rt.Point3(*pos) if color and rt.classOf(color) != rt.color: color = rt.color(*color) if not color: color = rt.yellow rt.setCommandPanelTaskMode(rt.Name('modify')) ctrl_name = rt.uniquename(name) base_rectangle = rt.rectangle(name=ctrl_name, length=length, width=width, cornerRadius=corner_radius, pos=pos) base_rectangle.wirecolor = color if str(axis).lower() == 'x': xform_mod = rt.xform() rt.addModifier(base_rectangle, xform_mod) rt.setProperty(xform_mod.gizmo, 'rotation', rt.eulerAngles(0, 90, 0)) elif str(axis).lower() == 'y': xform_mod = rt.xform() rt.addModifier(base_rectangle, xform_mod) rt.setProperty(xform_mod.gizmo, 'rotation', rt.eulerAngles(90, 0, 0)) rt.convertTo(base_rectangle, rt.SplineShape) return base_rectangle
def stepOneAxis(self, step, bnName, boneXF, a, f, vertIndexSet, mode='translate'): boneNewXF = rt.Matrix3(boneXF[0], boneXF[1], boneXF[2], boneXF[3]) if mode == 'translate': if a == 0: translationVector = rt.Point3(step, 0, 0) elif a == 1: translationVector = rt.Point3(0, step, 0) else: translationVector = rt.Point3(0, 0, step) boneNewXF = rt.translate(boneNewXF, translationVector) elif mode == 'rotate': if a == 0: rotMatrix = rt.rotateXMatrix(step) elif a == 1: rotMatrix = rt.rotateYMatrix(step) else: rotMatrix = rt.rotateZMatrix(step) # translate the matrix back to origin boneNewXFTranslation = boneNewXF.translation boneNewXF = rt.translate(boneNewXF, -boneNewXFTranslation) # make the rotation and translate it back boneNewXF = boneNewXF * rotMatrix boneNewXF = rt.translate(boneNewXF, boneNewXFTranslation) postSimError = 0 simVertSetPos = [] for v in vertIndexSet: preSimVertPos = self.regularMeshData.allVertPosList[v][f] weight = 0 for vertBoneIndex in range( 0, len(self.regularMeshData.allVertBoneList[v])): if self.regularMeshData.allVertBoneList[v][ vertBoneIndex].Name == bnName: weight = self.regularMeshData.allWeightList[v][ vertBoneIndex] simVertPos = preSimVertPos * (1 - weight) + preSimVertPos * rt.inverse( boneXF) * boneNewXF * weight simVertSetPos.append(simVertPos) referenceVertPos = self.referenceMeshData.allVertPosList[v][f] postSimError += self.computeUtil.computeErrorForOnePos( simVertPos, referenceVertPos) return boneNewXF, simVertSetPos, postSimError