When rigging weapons or hard surface meshes with specific angles or orientations, I want to be able to quickly create a bone with the same orient of a selected mesh component. I want to ensure I have as precise a position and orientation as possible.
With the latest versions of Maya creating and manipulating pivots have become far easier with native tools. Though, I've yet to see a process to do exactly what I've been looking for. I've written a fairly simple script to achieve what I've found to be the most intuitive approach to creating a bone with the position and orientation that I desire.
Here is a brief walk through of how I create bones using a custom pivot. The script I use can be found below.
Character Model by Chris Wells
Showing posts with label Autodesk. Show all posts
Showing posts with label Autodesk. Show all posts
Saturday, September 29, 2018
Sunday, April 22, 2018
Fixing Mechanical joints For Rigging
For Lawbreakers we had a juggernaut class that featured two bipedal robots. The robots had a shared base skeleton hierarchy for animation purposes. However, they had custom joints to handle the visual differences in their armor and armor plating. In most cases the base bipedal skeleton worked just fine, but there were issues when the mechanical mesh joint visual pivots and the actual skeleton joints were inconsistent. We had a couple levels of customization and we had to make sure the joints were modeled consistently to make sure they would work with the rig and animation properly.
In the video below, I go over a process on how to correct the meshes for these issues specifically on the fingers joints.
The only thing missing in the video is the clean up of the temporary joints and freezing the mesh to preserve its new modified transform. Once that is done, you can bind the meshes back to the original skeletal hierarchy.
Labels:
3d,
Animation,
Art,
Autodesk,
Character,
Character TD,
Customization,
FBX,
Game,
GameDev,
Maya,
Rigging,
TechAnim,
TechArt,
Technical,
Video Game
Tuesday, April 4, 2017
Flexible FBX with FBX Python SDK
FBX issues and such
Python FBX SDK Uses
Listed below are just a few things that you can modify in an FBX file with the SDK- Adding or removing properties/attributes
- Removing Namespaces before importing or after exporting
- Removing objects that were not a part of the specifically selected objects but were associated
- Removing textures or renaming paths
- Rename objects in fbx scenes without having to re-export the file from the source
- You can modify most anything in an FBX scene, external from a DCC application
Setting up the Python FBX SDK
http://www.autodesk.com/products/fbx/overviewHit the "Get FBX SDK" link and on the next page look for Python Binding. Choose your flavor, Windows, Linux, or Mac, download and install/extract the package. If you need an earlier version for compatibility reasons go to the "SDK Archive" link. I'm still using 2014.1 and it works fine with Maya 2014/2015/2016 and UnrealEngine 4.x.
You will need to install the package you have chosen to download. This package has a lot of incredibly useful samples for getting started with FBX in python and getting an understanding of the FBX scene in general. If you are at all familiar working with Python in Motionbuilder, pyfbxsdk, it is almost exactly the same and this should be quite easy to pick up.
Installing for Maya
If you are working in the latest versions of Maya 2014 and higher you will want the files in lib/Python27_x64 or x86. There are three main files that you will want to point to or add to your existing python paths for Maya.Here is a snippet to add to a script or your startup for Maya.
import sys sys.path.append(r'/FBXPath')These are the files that are needed:
fbx.pyd
FbxCommon.py
fbxsip.pyd
Here is some startup code for the FBX Scene Wrapper Class.
import fbx import FbxCommon class FBX_Class(object): def __init__(self, filename): """ FBX Scene Object """ self.filename = filename self.scene = None self.sdk_manager = None self.sdk_manager, self.scene = FbxCommon.InitializeSdkObjects() FbxCommon.LoadScene(self.sdk_manager, self.scene, filename) self.root_node = self.scene.GetRootNode() self.scene_nodes = self.get_scene_nodes() fbx_scene = FBX_Class(r'c:\my_path\character.fbx') # instantiate the classThe main thing to be aware of with most classes, is that you have to instantiate them to access their internal methods. Here we need to pass an argument that is a string of the fbx file path and name. The _init_ method will automatically parse and load the fbx scene. The one thing when parsing a file that you care about is speed, luckily when working with the Fbx SDK, even in python, I find it to be incredibly fast even on large Fbx files.
Now that the fbx scene is loaded we can go nuts changing the fbx file however we want. At Boss Key, after exporting I run a post process to modify all the fbx files, be it a character skeletal mesh, a weapon, or an animation file. I remove namespaces, empty display layers, remove objects that are in exported hierarchies that I don't want importing into UE4, or cleaning up any properties when necessary.
import FBX_Scene
def clean_character_scene(fbx_file):
"""
Clean up character fbx file
"""
# open the fbx scenes and get the scene nodes
fbx_scene = FBX_Class(fbx_file)
if not fbx_scene:
return False
remove_names = []
keep_names = []
# remove invalid nodes noted by properties assigned in the DCC application
all_nodes = fbx_scene.get_scene_nodes()
for node in all_nodes:
export_property = fbx_scene.get_property(node, 'no_export')
if export_property:
property_value = fbx_scene.get_property_value(node, 'no_export')
if property_value == True:
node_name = node.GetName()
fbx_scene.scene.DisconnectSrcObject(node)
remove_names.append(node_name)
else:
node_name = node.GetName()
keep_names.append(node_name)
# remove the nodes from the scene by name
fbx_scene.remove_nodes_by_names(remove_names)
# remove display layers
# For some reason these change FbxCollection ID and NodeName
layer_objs = fbx_scene.get_class_nodes(fbx.FbxCollectionExclusive.ClassId)
if layer_objs:
remove_layers(fbx_scene, layer_objs)
# remove FbxContainers
nodes = fbx_scene.get_class_nodes(fbx.FbxObject.ClassId)
if nodes in nodes:
if node.GetClassId().GetName() == 'FbxContainer':
# disconnect the layer from the scene
node.DisconnectAllDstObject()
node.DisconnectAllSrcObject()
fbx_scene.scene.RootProperty.DisconnectSrcObject(node)
# remove display layers
display_layers = fbx_scene.get_type_objects(u'DisplayLayer')
if display_layers:
remove_layers(fbx_scene, display_layers)
# save the modified fbx scene
fbx_scene.save()
return True
Right after I run my custom fbx export method in Maya I will call a method, such as the one above, all in the same process. So when the artist is finished exporting they won't even know I opened up the fbx and modified it for the better.
The great thing about the FBX Python SDK is that you don't need a DCC application to run it. You can run standalone processes and modify all of your mocap or skeletal mesh files, renaming nodes, changing hierarchies or adding properties, all without having to return to the original DCC to reexport. Once you start working with the Fbx Python SDK you may never stop.
![]() |
| The Python SDK can process importing mocap before you actually import it into your scene and remove namespace issues. |
Once I got familiar enough with FBX SDK I started a project which became the Saints Row Mod Tools. I wrote the tool that converted fbx scenes into the file formats needed for Saints Row 3, and Saints Row IV for for modding purposes. Before we used custom plugins, tools and processes that would be far too complex to release to the community and support for multiple DCCs. Fbx covers all the bases so this was a worthwhile tool and the community seemed to appreciate it. If you want to download the python script that really digs into breaking down the fbx scene, feel free to hop over to the saintsrowmods forums and grab it.
My Public Gists (full examples from this post)
https://gist.github.com/Meatplowz
On a side note if you want to actually extend the plugins with C++ you can do so.
FBX SDK Plugin Extension
Let me know if you have any questions on the Fbx Python SDK. If you have any suggestions or tips yourself please share them as well.
Friday, March 6, 2015
Maya Callbacks and References
The scenario that I'm working with in Maya involves two referenced rigs and creating constraints and message attributes between them. Now since i'm using references in Maya, additional bones, controls or what have you may be created in either reference at any point in time. What I'm doing is creating parent constraints from one rig to the other and anytime new bones or controls are added to the on rig, I need to constrain it to the other rig with relative names automatically. This is where callbacks come into play.
After the scene is fully Open and all the references are loaded I need to check message attributes to see if one rig is "connected" to another. Here I'm using message attributes to point each rig to one another. The callback looks for this message, if found it will update the connections by creating new constraints for similarly named objects. Now I was originally using the kAfterOpen callback which should fire off after all references are loaded. It does work, but I changed to the scriptJob version, "SceneOpened", that seems to run later than the callback variant, even after viewport processing. The method being called in the callback runs and connects everything just fine. While the scene appeared to be functioning correctly, after saving and reloading the file later, all the constraints were broken and the attributes were missing. I started to panic thinking this was a new bug with saving and references. I posted on the Autodesk beta boards after trying multiple approaches to work around my problem.
I spent quite a while doing diffs on the maya ascii files. The file before the callback and the file after the callback. Here I started to notice differences in the referenceEdits. I didn't understand all the formatting so I went on a hunt for the information there. Sadly, the actual documentation that I found had no real detail in the places that I had question about. This archived Post from PosingMantis on cgsociety helped greatly. What I started to realize was that all the operations I was doing during callbacks, while still functioning in the scene afterwards, they were not saving in the referenceEdits.
Here's an example of what the connections in the refEdits look like before the callbacks. The referenced ball is parentConstrained to the referenced box.
After the callback ran, all of those reference edits were now missing, but like I said everything was still operating and working properly in the scene. This was incredibly misleading. I looked for some more documentation and I found the root of my problems.
File I/O callbacks don't record reference edits
If I was a good little tech artist I would have read ALL of the documentation on callbacks. I know what callbacks do, why would I think methods called from them wouldn't record referenceEdits. Sigh. There are specific callbacks you can run after a reference loads and you can record referenceEdits. kAfterSceneReadAndRecordEdits This one probably does precisely what I needed, the others fire off after every referenceLoads which I didn't need. However, after chatting with Brad Clark cofounder of @RigginDojo, I opted for creating a scriptNode that runs the same methods OnDemand after a "SceneOpened" scriptJob, and the scriptNode has a flag to "RecordReferenceEdits". I can also only create this in the scenes that need them.
This still may not be the best way to do it but right now it's what I needed to move forward. I hope this will be helpful to someone as none of the issues I noticed were directly obvious. Good luck!
Labels:
3d,
Animation,
api,
Art,
Autodesk,
callback,
Maya,
Python,
refEdits,
References,
Rigging,
scriptJob,
scriptNode,
Technical,
Tool,
Video Game
Location:
North Carolina, USA
Tuesday, January 29, 2013
Building a Scripted Plugin Modifier for Game Characters
In response to +David Moulder I have detailed a little more of our character "referencing" and scene building process, starting with our custom character modifier. I hope this is helpful.
All of our characters and animated objects have a custom scripted plugin modifier that sits on top of the character mesh modifier stack. It stores references to the skeleton and helper objects in the parameter blocks of the modifier. To store these object references you will see below the parameter type should probably be a #maxObjectTab type. If you are looking for something similar to the message attributes in Maya the #maxObject parameter type, or what 3dsmax calls weak referencing, is as close as you are going to get. Paul Neale has a pretty good tutorial for weak referencing.
I went ahead and wrote up some functional code below to help provide a basic understanding of scripted plugin modifiers and weak referencing. If you evaluate this code a new modifier will appear in the modifier list named "AnimExportTest". It does not modify your mesh/object it is only a container for storing references and variables relative to your character.
Our version of this modifier has many more methods, attributes and options for storing animation and other references. This is more or less the core interface for evaluating incoming animatable assets to make sure they are properly setup for animation and exporting when building an animation scene, as noted in my previous post.
You may chose to build a similar interface but rather than a modifier it can be a custom shape object that lives in your scene. It's pretty much the same thing just where it lives is different.
Custom Attributes & adding Assets
When adding an asset I will merge the entire scene and inspect this custom modifier to make sure it has everything I need for animation. If it passes the validation process I will collect a list of only the objects necessary for animation and delete the remaining unnecessary objects that came into the scene. Once I have identified the valid objects I will apply a "namespace" prefix to them based on the supplied asset name. I will then stamp additional attributes onto all of the valid objects to sort them and identify them as a unique asset within the scene. You can see my post on Tech-Artists.Org for more on custom attributes. Below is an example of setting the custom asset attributes on the incoming objects.
A Bulk of the Work
Now that you have brought in a character asset into your scene in a clean and managed fashion the heavy lifting is done by your scene manager. Adding and Deleting should then become fairly trivial as your asset objects should be clearly identified. However, the swapping of your animated characters requires your tool to do much more in the way of saving animation, link constraints and export data defined in your scene. This of course relies heavily on your control rig system be it CAT, custom, or god forbid Biped +Brad Clark. Once you have a proper save and load, swapping assets should become a "breeze". I will note that 80% of my Asset Manager code is handling the saving and loading of animation. You may find many cases where you have to do a lot of code to preserve the state of your animation in relation to other objects or characters in your scene.
Feel free to ask any additional questions. I will try to follow up.
Until next time.
UPDATE: Fixed some script errors in the plugin modifier. It will now refresh the ui when you reopen it.
All of our characters and animated objects have a custom scripted plugin modifier that sits on top of the character mesh modifier stack. It stores references to the skeleton and helper objects in the parameter blocks of the modifier. To store these object references you will see below the parameter type should probably be a #maxObjectTab type. If you are looking for something similar to the message attributes in Maya the #maxObject parameter type, or what 3dsmax calls weak referencing, is as close as you are going to get. Paul Neale has a pretty good tutorial for weak referencing.
Weak References
I went ahead and wrote up some functional code below to help provide a basic understanding of scripted plugin modifiers and weak referencing. If you evaluate this code a new modifier will appear in the modifier list named "AnimExportTest". It does not modify your mesh/object it is only a container for storing references and variables relative to your character.
plugin Modifier AnimExportTest
name:"AnimExportTest"
extends:EmptyModifier
--- The id here must be unique run genclassid() to generate a unique id for your plugin
classId:#(0x2c608fe8, 0x14804a99)
version:1
(
-- set the file path parameter
fn set_path &path =
(
local file_path = getSaveFilename filename:"C:" types:"Meshx(*.meshx)|*.meshx|ALL|*.*"
if file_path != undefined do (
path = file_path
)
)
-- add object weak references to the parameters
fn add_bones objs =
(
for obj in objs do (
-- this is how you create a weak reference to an object/node
add_obj = (nodeTransformMonitor node:obj forwardTransformChangeMsgs:false)
append this.p_bones add_obj
)
)
-- object selection filter
-- boolean check to see if the incoming object has what you are looking for
fn bone_filter obj =
(
is_valid = True
-- make sure the object is our type of bone
if ( not superclassof obj == helper ) do (
is_valid = False
)
-- make sure object name has namespace identifier ":"
if ( not matchpattern obj.name pattern:"*:*") do (
is_valid = False
)
-- make sure the object or object name doesnt already exist in our list
for bone_obj in this.p_bones do (
-- since this is a weak reference get the .node to query the actual object
if ( bone_obj.node == obj ) do (
is_valid = False
exit
)
)
-- return bool
is_valid
)
--- Store any variable,object references, export paths, values necessary to this modifier
Parameters export_params
(
p_export_mesh type:#string default:""
p_export_rig type:#string default:""
p_bones type:#maxObjectTab tabSize:0 tabSizeVariable:true
p_bone_names type:#stringTab tabSize:0 tabSizeVariable:true
)
-- rollout ui creation
rollout ro_export "Export Paths"
(
Group "Export Paths" (
Button bn_export_mesh "Export Mesh" width:100
Button bn_export_rig "Export Rig" width:100
)
--- Functions to set paths
On bn_export_mesh pressed do (
set_path &this.p_export_mesh
)
--- Functions to set paths
On bn_export_rig pressed do (
set_path &this.p_export_rig
)
)
-- export objects menu
rollout ro_export_bones "Export Objects"
(
Group "Export Bones" (
MultiListBox lbox_bones "" width:140 height:20
Button bn_add_bones "+" across:2
Button bn_remove_bones "-"
)
-- Update the rollout interface
fn update_ui =
(
local bone_names = #()
for obj in this.p_bones do (
-- since this is a weak reference get the .node to query the actual object name
append bone_names obj.node.name
)
lbox_bones.items = bone_names
)
--- Functions to add and remove bones
on bn_add_bones pressed do (
--- object picker dialog
new_bones = selectByName filter:bone_filter
if ( new_bones != undefined ) do (
add_bones new_bones
)
-- update the interface
update_ui()
)
-- Update the interface when the rollout is opened
on ro_export_bones open do (
update_ui()
)
)
)
![]() |
| Custom Test Modifier |
![]() |
| Custom Character Modifier by +Nathaniel Albright |
You may chose to build a similar interface but rather than a modifier it can be a custom shape object that lives in your scene. It's pretty much the same thing just where it lives is different.
Custom Attributes & adding Assets
When adding an asset I will merge the entire scene and inspect this custom modifier to make sure it has everything I need for animation. If it passes the validation process I will collect a list of only the objects necessary for animation and delete the remaining unnecessary objects that came into the scene. Once I have identified the valid objects I will apply a "namespace" prefix to them based on the supplied asset name. I will then stamp additional attributes onto all of the valid objects to sort them and identify them as a unique asset within the scene. You can see my post on Tech-Artists.Org for more on custom attributes. Below is an example of setting the custom asset attributes on the incoming objects.
-- Asset Attributes
-- This attribute block should probably live in your library code
--- so that it is always accessible.
my_asset_data = attributes asset_data
attribid:#(0x6664296c, 0x5dec7a0)
version:1
(
parameters asset_data
(
asset_name type:#string default:"none"
asset_id type:#integer default:0
asset_type type:#string default:"Character"
)
)
-- Loop through all the incoming objects and apply the custom attribute
-- Apply attribute class to an object
add_attribute = custAttributes.add obj my_asset_data baseobject:True
-- update attribute data with your unique asset name, asset Id
-- and anything additional you need to track
obj.asset_name = obj.supplied_asset_name
obj.asset_id = unique_asset_id
A Bulk of the Work
Now that you have brought in a character asset into your scene in a clean and managed fashion the heavy lifting is done by your scene manager. Adding and Deleting should then become fairly trivial as your asset objects should be clearly identified. However, the swapping of your animated characters requires your tool to do much more in the way of saving animation, link constraints and export data defined in your scene. This of course relies heavily on your control rig system be it CAT, custom, or god forbid Biped +Brad Clark. Once you have a proper save and load, swapping assets should become a "breeze". I will note that 80% of my Asset Manager code is handling the saving and loading of animation. You may find many cases where you have to do a lot of code to preserve the state of your animation in relation to other objects or characters in your scene.
Feel free to ask any additional questions. I will try to follow up.
Until next time.
UPDATE: Fixed some script errors in the plugin modifier. It will now refresh the ui when you reopen it.
Saturday, September 1, 2012
3dsmax Animation Referencing and Scene Building
Having worked on many game titles in the past its quite clear that scene building and having a way to reference or quickly update characters and rigs is very important. If you work in 3dsmax you are probably quite aware and envious of the referencing capabilities that exist in Maya. This functionality is clearly missing from 3dsmax and may likely never appear. Sure there are Xrefs but be my guest if you choose to use them and discover you don't get nearly what you need with the added benefits of instability.
So out of necessity I started work on what ultimately became our Animation Asset Manager ( AM ). The tool merges assets, Characters, Weapons, Vehicles, Props, Environments, etc. in a quick and efficient manner. Straight ahead file merging can result in a very messy file, as 3dsmax does not have native "namespace" functionality, and there may end up being a lot of object name collisions and rig linking errors. The Asset Manager handles all of these issues and bundles all of the incoming file objects into one "Asset". Now working in hugely complex scenes is quite easy as thousands of objects can now be represented as one Asset.
Adding an Asset
What actually happens behind the scenes is a bit more complex. The incoming file is first validated to make sure it is export ready. If the AM finds everything it needs for that asset type then it will fully merge the file. After merging, the incoming objects are checked and objects unnecessary for animation/export purposes are removed, shaders are converted to standard materials, all objects are stamped with Asset Attributes, and finally object names and layers are properly namespaced. The attributes that were added to each object were done to easily classify the objects under one "Asset". When the AM updates it scans the scene and represents each asset properly by querying the object attributes. In the past I used very light-weight user defined properties but I have converted to custom attributes as these can be properly transported between DCC apps and maintained in the FBX file format.
So out of necessity I started work on what ultimately became our Animation Asset Manager ( AM ). The tool merges assets, Characters, Weapons, Vehicles, Props, Environments, etc. in a quick and efficient manner. Straight ahead file merging can result in a very messy file, as 3dsmax does not have native "namespace" functionality, and there may end up being a lot of object name collisions and rig linking errors. The Asset Manager handles all of these issues and bundles all of the incoming file objects into one "Asset". Now working in hugely complex scenes is quite easy as thousands of objects can now be represented as one Asset.
Adding an Asset
- The artist chooses the asset type to add
- Selects a file from a list of assets or locate a specific file on disk
- Provide a unique name to represent the Asset
- Add the number of asset instances
![]() |
| AssetManager - Add Character Asset |
![]() |
| AssetManager - Asset Objects |
Swapping an Asset - Poor Man's Referencing
As characters, weapons or props are updated the animators need to be able to easily update to the new asset when necessary. Cosmetic changes don't always mean an update needs to happen but specific rig changes may require updates. Scene callbacks are put in place to verify animated assets in files are up to date in regards to explicit external file references that are checked on scene open. The AM ensures that these objects can be swapped and any animation existing in the file is maintained, this is where a great deal of the code in this tool comes into play. This includes full character animation, IK objects, morph animation, external link constraints and any other custom animations related to the asset. We employ our own save animation functions to handle everything outside of the basic biped motion to ensure keys and motions are maintained between potentially different objects. However, making sure everything transfers properly is reliant upon making sure all animated assets are marked up properly during asset creation, another topic for another time.
Weapon Updating
Weapons are connected to our characters in a specific manner and in the past allowing animator's to do this by hand resulted in inconsistent errors and issues between DCC app and the game. The AM brings the updated weapons into the file and makes sure the weapon's are aligned and linked properly to the character. Updating the weapons is just as easy as hitting the update button when necessary. The weapon is removed from the file, the source asset file is synced in source control, and finally updated into the current animation file.
Demonstration Video
You can watch a demonstration of the scene building and swap process below. The tool and functionality was developed and improved upon over the course of a couple projects. It was used to construct animation scenes and cinematics from our latest title Saints Row: The Third
![]() |
| AssetManager - Update Weapons |
Demonstration Video
You can watch a demonstration of the scene building and swap process below. The tool and functionality was developed and improved upon over the course of a couple projects. It was used to construct animation scenes and cinematics from our latest title Saints Row: The Third
Animation Asset Manager - Randall Hess from Randall Hess on Vimeo.
Saturday, January 28, 2012
Game Skeleton Builder via Biped
Animators using 3dsmax may want to use Biped as their control skeleton but for games you do not necessarily want to use this as your exported skeleton. Ryan Griffin on G+ has recently posed a question regarding building a skeleton based off of a biped. As we have done this for quite some time at Volition I felt I could offer some assistance here using Maxscript.
First we want to create a structure representing the bone data that will be used to create the skeleton. A struct in maxscript is somewhat similar to class objects that exists in other languages such as python or C#. Check out Duber's Blog for a more in depth look on maxscript structs.
Next we create a recursive function that will return the data representing each biped bone name, the parent bone name, and the bone transform. Notice that I am ignoring certain biped helper objects that don't necessarily need to become bones in our skeleton.
First we want to create a structure representing the bone data that will be used to create the skeleton. A struct in maxscript is somewhat similar to class objects that exists in other languages such as python or C#. Check out Duber's Blog for a more in depth look on maxscript structs.
struct bone_info (bone_name, parent_name, bone_xform)
Next we create a recursive function that will return the data representing each biped bone name, the parent bone name, and the bone transform. Notice that I am ignoring certain biped helper objects that don't necessarily need to become bones in our skeleton.
-- recursive function to get biped children objects
fn get_bip_children bip_obj bone_data =
(
-- make sure the current biped object has children
if (bip_obj.children != undefined) do (
-- loop through all of the current bone's children
for child in bip_obj.children do (
-- ignore these biped objects
match_footsteps = matchpattern child.name pattern:"*footsteps"
match_nubs = matchpattern child.name pattern:"*nub"
-- do not add certain objects as bones, this is a preference
if (not match_footsteps) and (not match_nubs) do (
-- create an object for the current child bone
new_bone = bone_info child.name bip_obj.name child.transform
-- update the bone_data array with the current child
append bone_data new_bone
-- see if the current child has and children
if (child.children != undefined) do (
get_bip_children child bone_data
)
)
)
)
return bone_data
)
Next up is the main function that collects the biped bone data, creates the new bones and rebuilds the hierarchy. Something that I should point out here. I am creating the actual bones using point helper objects. Almost any object in max can be used as an animatable bone and work with the Skin modifier to deform meshes. One thing to keep in mind is that I avoid creating max bones using the bone() creation method. This tends to be slow and I have found to crash Skin. You may choose to use bonesys.createbone as an alternative.
-- create a skeleton from a biped skeleton
fn create_skeleton bip prefix =
(
-- get the biped root node
bip_root = bip.controller.rootnode
local bone_data = #()
-- create an object for the root bone
root_bone = bone_info bip_root.name undefined bip_root.transform
append bone_data root_bone
-- get bone data (names and hierarchy) from the biped
bone_data = get_bip_children bip_root bone_data
-- make sure bone data is valid
if (bone_data.count > 0) do (
-- create the bones
for b in bone_data do (
bone_name = substitutestring b.bone_name "Bip" prefix
-- using a point object here, this can be changed to any object type
-- do not use bone()!, that is really slow and crashes skin
new_bone = point name:bone_name size:5 box:on cross:off
)
-- update the hierarchy and set the transforms on the newly created bones
for b in bone_data do (
-- only update the bone parent if it actually has a parent
if (b.parent_name != undefined) then (
bone_name = substitutestring b.bone_name "Bip" prefix
parent_name = substitutestring b.parent_name "Bip" prefix
bone_node = getnodebyname bone_name
parent_node = getnodebyname parent_name
-- set the bone parent then set the transform
if (isvalidnode bone_node) and (isvalidnode parent_node) do (
bone_node.parent = parent_node
bone_node.transform = b.bone_xform
)
) else (
-- get the bone object
bone_name = substitutestring b.bone_name "Bip" prefix
bone_node = getnodebyname bone_name
-- set the bone transform without a parent
if (isvalidnode bone_node) do (
bone_node.transform = b.bone_xform
)
)
)
messageBox "Creating Skeleton Complete!" title:"Create Skeleton"
)
)
This is the opening of the script that will make sure the user has a single biped object selected and provide the prefix name that will precede the new bone names.
if (selection.count == 1) and (classof selection[1] == Biped_Object) then ( -- create the skeleton with a new prefix create_skeleton selection[1] "Guy" ) else ( messageBox "Select a single biped node" title:"Create Skeleton" )Now since we used point helpers to create the bones you may want to display these objects with links and make them look more like max bones. To do this you can go to the display panel under link display at the bottom and check both options. The final result with a little object coloring should look like this. There are many other things you can do once you create this skeleton such as constrain these bones directly to the biped, create additional helper bones to represent bone twists or add your own custom constraints to transform these bones any way you like. You can download the full script here. biped_create_skeleton.ms
Subscribe to:
Posts (Atom)








