maya2egg and Tags

I’ve been looking into tagging objects in Maya and getting that data into the egg file. From searching the site and forums it seems like the main method available is the eggObjectTypes tag, which is nice but not easy to extend to other kinds of tagging without getting pretty kludgy.

After reading the source I discovered this other handy technique which I didn’t see mentioned in the manual. You can also just add arbitrary attributes, give them a name with the prefix “tag”, and they will also be exported.

Example:

in Maya:
Modify->Add Attribute

Long name: tagFoodType
Make Attribute: keyable
Data Type: enum
Enum Names:
Apple
Bulgogi
Cake
Dan Tat (Egg Custard)

The egg file will have something like this:

<Group> food1 {
  <Tag> FoodType {
    "Dan Tat (egg custard)"
  }
  <VertexPool> foodShape1.verts {
    <Vertex> 0 {
      -0.5 -1.11022e-16 0.5
      <Normal> { 0 1 0 }
      <RGBA> { 0.5 0.5 0.5 1 }
    }
...

Which you can then get in Panda like so:

a=loader.loadModel("tagtest2.egg")
a.reparentTo(render)

p=a.find("**/food*")
print p
p.listTags()
print p.getTag("FoodType")

HOWEVER,

this only works with Enum types. That’s fine for many cases, but in others you really need to be able to enter arbitrary values. this limitation seems to be only because it hasn’t been added to the exporter code.

in mayaegg/mayaNodeTree.cxx, starting at 380, here’s the bit that does the eggObjectTypes flag:

    if (node_desc->has_dag_path()) {
      // Check for an object type setting, from Oliver's plug-in.
      MObject dag_object = node_desc->get_dag_path().node();
      string object_type;
      LVector3d value;
      if (get_enum_attribute(dag_object, "eggObjectTypes1", object_type)) {
        egg_group->add_object_type(object_type);
      }

this explains why the attributes have to be named explicitly eggObjectTypes1, 2, and 3 …

a little further down:

      pvector<string> tag_attribute_names;
      get_tag_attribute_names(dag_object, tag_attribute_names);
      for (uint ti=0; ti < tag_attribute_names.size(); ti++) {
        if (get_enum_attribute(dag_object, tag_attribute_names[ti], object_type)) {
          egg_group->set_tag(tag_attribute_names[ti].substr(3), object_type);
        }
      }

get_enum_attribute() and get_tag_attribute_names() are in maya_funcs.cxx

it only bothers trying to read attributes which are enums and ignores everything else. There’s no reason why that has to be the case, it looks like all you’d have to do is call the other get_*_attribute functions in maya_funcs to extract other attribute types. Does that seem right or is it more complicated than that … ?

Fixed it, but need to clean this code up … just pasting it here before I forget what I was doing …

      for (uint ti=0; ti < tag_attribute_names.size(); ti++) {
        MStatus status;
        MFnDependencyNode node_fn(dag_object,&status);
        
        MObject attr = node_fn.attribute(tag_attribute_names[ti].c_str(),&status);
        MPlug plug = node_fn.findPlug(attr,false,&status);
        
        MFn::Type fnType = attr.apiType();
        std::cout << tag_attribute_names[ti] << " " << fnType << " " << attr.apiTypeStr() << "\n";
        
        if (fnType == MFn::kNumericAttribute)
        {
          status=plug.getValue(float_value);
          std::cout << "Value=" << float_value << "\n";
          sstr << float_value;
          string_value = sstr.str();
          egg_group->set_tag(tag_attribute_names[ti].substr(3), string_value);
          sstr.str("");
        }
        else if (fnType == MFn::kTypedAttribute)
        {
          status=plug.getValue(mstring);
          string_value = mstring.asChar();
          std::cout << "Value=" << string_value << "\n";
          egg_group->set_tag(tag_attribute_names[ti].substr(3),string_value);
        }
        else if (fnType == MFn::kEnumAttribute)
        {
          MFnEnumAttribute enum_attribute (attr,&status);
          
          status=plug.getValue(enumIndex);
          mstring = enum_attribute.fieldName(enumIndex,&status);
          string_value = mstring.asChar();
          std::cout << "Value=" << string_value << "\n";
          egg_group->set_tag(tag_attribute_names[ti].substr(3),string_value);            
        }     
      }

Hey, that’s cool. Sounds like a useful addition, thanks!

David