Fri, Apr 22nd, 2016
posted by jjburton 12:04 PM

 

proximeshwrap

So, finally wrapped up my work for Morpheus 2 in regards to the wrap setups. As you can see from the last two trips on the rabbit trail(Step 1, Step 2), this wasn’t exactly a simple process.

The point of all of this is to be able to bake blendshapes reliably to nonconforming geo while affecting only the regions we want without having to go in and tweak things by hand. This will prove more and more useful as customization option expand. Why bother with this? Wrap deformers are exceedingly slow. Being able to replace them with skinning data and copying blendshapes between meshes will make your animations play faster and feel more interactive. The final solution was to create proximity geo which is localized to the area I want to affect the nonconforming target mesh. The proximesh is wrapped to the base driver and the target is wrapped to the proximesh.

target –[wraps to]—>> proximesh –[wraps to]–>> base

Here’s a general breakdown of the baking function:

  1. Given a source mesh that has the blendshapes and a nonconforming target mesh we want them on…
  2. Go through all blendshape channels on the source mesh and…
    1. Get their connections/values
    2. Break all connections/zero values so we have clean channels to push our specific shapes to our target mesh
  3. Generate a proximesh of the source with the area we want influencing our nonconforming mesh
  4. Generate a duplicate target mesh so we’re not messing with that mesh
  5. Wrap the proximesh to the source mesh
  6. Wrap the duplicate target mesh to the base mesh
  7. Go through all the blendshape channels on the source mesh and…
    1. Turn a channel on
    2. Duplicate our wrapped target mesh to create a new mesh with the blendshape data on it pushed through by the wrap
    3. If we’re going to cull no change shapes – check each generated shape against the target mesh to figure out when are not moving any verts and delete those offenders
  8. Go through all the original blendshape channels again and rewire them as they were before our function
  9. Delete the wraps and temporary geo
  10. If desired, create a new blendshape node with our final list of baked targets on our nonconforming base mesh
  11. If desired wire the new blendshape node to match the original one we baked from so the channels follow one another.

Easy peasy:)

Functions created while working through it:

  •  cgm.lib.deformers
    • proximityWrapObject — This was the solution in the end to getting rid of movement in the mesh in areas I didn’t want affected.
    • influenceWrapObject — See step one above. Dead end but might prove useful in the future
    • bakeBlendShapeNodesToTargetObject — Greatly expanded this during this little journey
      • Added wrapMethod — influence wrap and proximity wrap and associated flags
      • Added cullNoChangeGeo — removes baked targets that don’t move the base mesh within the given tolerance
  •  cgm.core.lib.geo_Utils
    • is_equivalent — Function comparing points of to pieces of geometry to see if their components match in object space. Useful for culling out empty blendshape targets that have been baked. Supports tolerance in checking as well
    • get_proximityGeo — In depth function for returning geo within range of a source/target object setup. Search by boundingbox and raycasting to find geo within the source. Can return objects,faces,edges,verts or proximity geo which is new geo from the targets that corresponds to the search return

Lessons Learned for wraps in general

  • The maya command call to create a node is mc.CreateWrap (in 2011 at least). I hope later versions made it easier as
  • The object you wrap your target two gets two attributes (dropoff and smoothness) that dicatate how the wrap on your target is affected. No idea why it took me this long in maya to notice that in the docs.
  • Simply using Maya wrapDeformer to wrap an object to another when the object to be wrapped doesn’t conform to the target geo is a bad idea. You’ll get movement in your wrap geo where you don’t want it.

Long story short. The wrap problem is resolved for Morpheus 2.0.

For now. 🙂

Be Sociable, Share!
Wed, Apr 20th, 2016
posted by jjburton 02:04 PM

So the rabbit trail from over the weekend proved to not be the answer to my original problem as hoped. Namely I was still getting geo movement from far off regions when baking blendshapes to non-similar geo (think a sphere placed on a body).

As such, my next plan to resolve this was to create a specific conforming geo piece to wrap to then wrap my nonconforming object to. To do this, I need a way to  find the geo closest to my geo I wanted to transfer the blendshapes too and so wrote a new function for this that would:

  • Search target geo against a source geo piece to find geo from each target within the source by two methods:
    • boundingBox.contains – by vert
    • rayCasting  – by the compass vectors to make sure it is completely within the sourceObject
  • Translate that data to verts,edges, faces
  • Have a method to expand that data:
    • selection traversing
    • softSelection radius

Lessons learned:

  • bounding box checking is much much faster so use that mode unless you just have to have a more precise idea of what verts are inside the mesh.
  • Not a lot of specific info I could find on some of these concepts and so wanted to share to save someone else time and deadends

Here’s part one of this issue which is housed at cgm.core.lib.geo_Utils.get_contained. There are too many dependencies to include them all but you can get this gist from the code.

Up next is setting up a new wrap setup with this data. Will post when that’s done.

 

Be Sociable, Share!
Sun, Apr 17th, 2016
posted by jjburton 07:04 PM

On yet another rabbit trail of problem solving on Morpheus 2.0, I came across an issue where wrap deformers weren’t working as needed. Namely transferring blendshapes from one mesh to another when the shape of the target mesh wasn’t like the original. Even geo changes in regions no where near the ‘to bake’ geo were affecting it.

So did some googling and came across a concept I’d not used before – namely using a mesh to deform another with a skinCluster.

Neat, so how do we do it?

  1. Get your target and source mesh ready
  2. Create a joint and skinCluster your target mesh to it
  3. Add the driving mesh to the skinCluster with the useGeometry flag ( sample code for this line below).
    1. polySmoothness flag. This controls the smoothness of the mesh deformation of the target mesh.
    2. A polySmoothness of 0 is the closest to a standard wrap deformer
    3. In my initial testing I found that this flag could only be set consistently on creation. Editing the flag could push the smoothness up but not down (in 2011 at least).
  4. Make sure the useComponents attribute on the skinCluster is set to True. If you don’t see the deformation doing anything this is the likely culprit.

I wrote a script to set this up but it’s still wip. It’s a function found here: cgm.lib.deformers.influenceWrapObject. Because of the issue noted in step 3.2, I added the polySmoothness as a creation flag.

This method of wrapping is much more localized than wrap deformers when the mesh isn’t close AND provides an easy way to paint weights for the deformation.

Acknowledgements:

Be Sociable, Share!
Thu, Apr 14th, 2016
posted by jjburton 08:04 AM

This post is to remind us how to do this. J had a computer issue and had to reinstall Windows:)

  1. Follow this tutorial – https://confluence.atlassian.com/bitbucket/set-up-ssh-for-mercurial-728138122.html
  2. Make some coffee, you earned it.

If you get the “server’s host key is not cached…” error when attempting to push from SourceTree:

  1. Command prompt
  2. Go to Program Files (x86)/PuTTY
  3. “plink -agent bitbucket.org”
  4. Hit ‘y’

 

Be Sociable, Share!
Fri, Feb 19th, 2016
posted by jjburton 10:02 AM

Sometimes you need to get stuff back to earlier versions of Maya and ignore version just doesn’t work. I needed to get a load of 2016 geo back to 2011. Here’s what worked:

  1. Export geo to a clean file in your current version of Maya
  2. If you can’t export it as an .ma file, run scene optimize on the mb file making sure to remove unknown nodes
  3. Save as an .ma
  4. In a text editor change the 2016(or whatever version you’re going from) to 2011(or whatever version you’re going to). Save it
  5. Open in the earlier version of Maya

-j@cgm

 

 

Be Sociable, Share!
Sat, Feb 13th, 2016
posted by jjburton 08:02 PM

Released a build of Morpheus 2 this week and immediately ran into some issues with the marking menu and hot keys. I’d been using zooToolbox’s setup for years for hot keys but it didn’t work with 2016 so I dug in.

Maya 2016 has a pretty neat new editor but it’s still probably more steps than most of our users could reliably follow so wanted to get the button push setup back.

There a few things to remember when working with hot keys and in this order…

  1. runTimeCommand– This is the code that gets run. It can be python or mel
  2. nameCommand — This is required for a hot key to be setup properly
  3. hotkeySet — This is something new with 2016 and needs to be set to a new set to be able to add a new hot key because the default set is unchangable
  4. savePrefs — after setting up your hotkey, you must save the prefs or the newly created hotkeys go away (not sure if this is new to 2016 or not)

Lessons learned:

  • hotkeySets — were added in 2016. Any hotkey work you do post 2016 needs to account for them. I ended up having my stuff use the existing set if it wasn’t the default and create a new one if the default is the current one
  • hotkey -shiftModifier flag — this was added in 2016
  • Pushing dicts into mc/cmds calls — In general, something like mc.command(**_d) works with _d being your dict. However on mc.hotkey I found that the keyShortcut flag needed to be in the dict and at the start of the call to work: mc.hotkey(_k, **_d).

I ended up writing a handler and gui to set stuff up. I’ll swing back and talk about it another time if there’s interest.

Back to Morpheus…

 

 

Be Sociable, Share!
Sat, Feb 13th, 2016
posted by jjburton 07:02 PM

Because google doesn’t always get them the first go…

Be Sociable, Share!
Sat, Feb 6th, 2016
posted by jjburton 10:02 PM

As I’ve been closing in on finishing Morpheus 2 I found myself in need of a distributable skin data system to be able to apply skinning information to Morphy meshes after they’d been customized and no longer matched up with the base mesh. Not being able to find a good way of doing it in natively to Maya and not finding any open source options, writing our own was the only way forward.

Thanks to Alex Widener and Chad Vernon for some tech help along the way.

Before delving in here, here’s some lessons learned along the way.

  • mc.setAttr — found this to be a unreliable method of setting weights via the ‘head_geo_skinNode.weightList[0].weights[0]’ call convention. Just didn’t seem to set properly via any call but the api.
  • mc.skinPercent — call is hopelessly slow and should never be used for intensive work. A query loop went from 78 seconds to run to 1.3 simply using an api weights data call even with having to re-parse the weights data to a usable format.
  • weights — speaking of, this was an obtuse concept to me. This is regards to the doubleArray list used with  an MFnSkinCluster. In short the easist way to get to a spot in this data set is as follows:
    • weights.set(value, vertIdx*numInfluences+jointIdx)
    • weights — doubleArray list instance
    • value is the given value you want
    • vertex index * the number of incluences + the joint index = the index in the array
  • Normalizing skin data — You usually want your skin values to add up to 1.0, so here’s a chunk to help

The initial list or requirements for the functions were as follows:

  • Readable data format — decided on configobj having used it with some red9 stuff and finding it easy to use.
  • Export/import data sets
  • Work completely from the data file for reference (no source skin necessary)
  • Work with different vertex counts if similar shape
  • Used indexed data sets for easy remapping of influences

With that being said. Here’s the demo file link and you’ll need the latest cgm package to follow along. Open up a python tab in the script editor and try these things one line at a time.

This is a first pass on this thing till Morphy 2 is done.

Cheers!
j@cgm

Be Sociable, Share!
Mon, Oct 19th, 2015
posted by jjburton 12:10 PM

So for Morpheus 2, the customization asset uses a blendshape head that needed to be connected to a unified body for the setup to work right. To do that I wanted to do wrap on a blendshape going into the unified body geo blendshape setup. However, we only wanted the head verts affected. If you’re not doing a procedural setup, you can simply paint out the other verts on the blendshape’s channel. Looking into a procedural solution required finding a few code chunks.

Googling on this stuff produced few helpful results so hopefully this can help someone else should they find themselves looking into these things.

First chunk we needed was the setAttr command on setting specific blendshape target weights. This one was a hard one to track down for whatever reason but here it is:

The components of this chunk are as follows:

  • unifiedBridge_blendshape — this is the blendshape node
  • inputTarget[0] — this is the index of the shape on the blendshape node we want
  • inputTargetGroup[1] –As best I understand it this is the target information for 1, or when the shape is fully on
  • targetWeights[563] — this is the vertex id of the vertice in question
  • 1.0 — value to set

As I had a head mesh that was gonna deform that same head that had been unified with the body to have a single mesh for easier skinning/shaping use, I needed the verts I wanted to mask on (for the head verts) and off (for the rest). So first all the verts are turned off, then the verts we wanted turned back on are done so with something like this:

This is utilized with some modification during the setup process for a customization asset.

Have a great day!
j@cgm

 

Be Sociable, Share!
Mon, Mar 2nd, 2015
posted by jjburton 01:03 PM

So,  a chat with a good buddy (Scott Englert) on the topic brought up one more item I’d neglected to rule out in the previous bit of research.

Flush prefs.

Dur…

So I did and the issue vanished, which led me to delve into what script or preference was causing issues. Did this by re-adding files and scripts to figure out what it was. As it happens it wasn’t a specific file but an import that did it. In the end, I found 2 issues at play – one of which is solved but broke my unit tests so I’m waiting to for Red9 to figure out how to resolve. In this case it was registering ‘transform’ as a nodeType in r9Meta stuff in one of my __init__ files.

Hopefully finding this will make the red9 stuff which we love all the better once it’s resolved and keep others from bounding into the time sucking vortex that resulted.

Lesson learned – if something is acting weird, clear prefs and see if it fixes it and if it does, start adding stuff back till you find the culprit.

 

Be Sociable, Share!