Ordering of transforms in <node> element

Hi,

While working today I found a problem I can’t seem to resolve. I exported a model to test my transform hierarchy and animation code and I discovered that some of the nodes in the resulting DAE file have transforms arranged in an order I have not seen before (and hadn’t planned for unfortunately).

Here’s an example of one of the problem nodes:


        <node id="Head" name="Head" type="NODE">
          <translate sid="translate">0 6.738570 0</translate>
          <translate sid="rotatePivot">0 -0.528158 0</translate>
          <rotate sid="rotateZ">0 0 1.000000 0</rotate>
          <rotate sid="rotateY">0 1.000000 0 0</rotate>
          <rotate sid="rotateX">1.000000 0 0 0</rotate>_
          <translate sid="rotatePivotInverse">0 0.528158 0</translate>
          <translate sid="scalePivot">0 -0.528158 0</translate>
          <translate sid="scalePivotInverse">0 0.528158 0</translate>
          <instance_geometry url="#HeadShape-lib">
            <bind_material>
              <technique_common>
                <instance_material symbol="initialShadingGroup" target="#lambert1"/>
              </technique_common>
            </bind_material>
          </instance_geometry>
 

As you can see this node has a couple <translate/> elements, then the <rotate/> elements and then some more <translate/> elements. In the past I’ve typlically just seen a single translate then three rotates (and maybe sometimes there’s a scale element if I’ve modified the model scale). I understand why the exported model has the above sequence of transforms (I changed the rotation pivots on some of the nodes in the model) but my problem is determining what the ordering is through the DOM API. I know I can use domNode::getTranslate_array and domNode::getRotate_array but how can I tell when the translations and rotations are interleaved like they are above? I guess I could just use getContents and hope the contents array is ordered properly but I hate to do that if there’s a real solution I just can’t find.

Thanks,
Thayer

Actually getContents is exactly what you are supposed to use.
And yes it is ordered correctly. the contents array is the way the DOM keeps order for elements with xs:choice groups (like node). The DOM, upon load, will even fix the order of elements that are incorrect, so when you work with the document they are in valid order and will save out in valid order.

When you iterate over the elements in the contents array it is pretty simple to figure out what they are. you can switch on element->getElementType(). The values returned are in the COLLADA_TYPE namespace, ie COLLADA_TYPE::ROTATE. Or you can strcmp the elements name or type, or compare metas with daeSafeCast< type >( element ). The later one works like dynamic_type< type > in that it will return NULL if the cast would fail.

-Andy

Glad to hear I’m not too far off the mark then. This morning I ended up implementing a loop over all the contents with a dynamic_cast to determine object type.

Now I’ve got another issue, or rather, I’ve solved another problem I think. It’s a little off topic for this thread but since I’ve got you here. I’ve been working to integrate refinery in command line mode with some Makefiles to automate some of my asset processing. I tried executing a macro from the command line like this:

refinery.bat -m mymacro -i input.dae -i output.dae

Even though refinery never printed any errors it also never created the file output.dae. Executing this through the debugger and setting breakpoints in LibLoader::loadDocument() and saveDocument() I found that saveDocument was failing because the docStr argument was always the same as the toStr argument. Since no document called output.dae existed in the database this always failed.

I checked out Refinery.java where this gets called from and found that in the case of macro parsing the code was always passing the output file name as both arguments to saveDocument. To fix this I copied some of the code from the case that handles execution of an individual conditioner. Here’s the relevant code with my changes highlighted (sort of):


		case ExMacro:
			//System.out.println("ExMacro #1");
			main.loadMacros();
			//System.out.println("ExMacro #2");
			try {

				MacroTemplate mb = main.availableMacroList.getMacroBaseFromLibName(clp.getMacroName());
				if (mb == null)
				{
					mb = new MacroTemplate(new File(clp.getMacroName()));
				}
			    //System.out.println("ExMacro #3");
				PipelineMacro macro = new PipelineMacro(main, mb);
			    //System.out.println("ExMacro #4");

				if (clp.getInputFileNumber() != macro.getInputNumber())
				{
					System.err.println("Error: you gave " + clp.getInputFileNumber() + " input files but " + macro.getName() + " takes " + macro.getInputNumber());
					break;
				}
				Iterator<String> inIt = clp.getInputFiles();
				int mfileN = 0;
				while (inIt.hasNext())
				{
					String input = inIt.next();
					macro.setInput(mfileN, input);
					mfileN++;

					LibLoader.loadDocument(input);
				}

--->          Iterator<String> mOutFilesIt = clp.getOutputFiles();
--->          mfileN = 0;
--->          while (mOutFilesIt.hasNext())
--->          {
--->              macro.setOutput(mfileN, mOutFilesIt.next());
--->              mfileN++;
--->           }

				macro.executeSolo(clp.getLibArgs());

				//System.out.println("after execute");
				
                Iterator<String> outIt = clp.getOutputFiles();
				mfileN = 0;
				while (outIt.hasNext())
				{
					String fname = outIt.next();
					//System.out.println("Output to be saved: " + fname);
--->                                  LibLoader.saveDocument(macro.getOutput(mfileN), fname);
					mfileN++;
				}
			} catch (Exception e1) {
				System.err.println("Error : " + e1.getMessage());
			}
			break;


That seems to make things work for me though I’m not sure if it will work in all situations.

-Thayer

macro is type PipelineMacro and PipelineMacro.setOutput does nothing but return false.

The second change I think is what did it. But I see a situation where it may assert / throw an exception. If on the command line you specify more output files than needed. You should break after macro.getOutputNumber(). For the inputs it doesn’t matter because all the extra inputs specified don’t do anything, the function just returns false.

Thanks for finding this. I’ll make the change and it will be updated on SF sometime soon.

Thanks,
-Andy

Hi,

I recently downloaded the new refinery version, in order to update my assets pipeline, and I just realized that the afore mentioned problem still occurs. Using refinery from command line to run a macro, the output is not written.
Is there a quick turn around for this particular problem?

Thank you,

bruno

It looks like the code never made it into Refinery. I submitted a bug on SourceForge: http://sourceforge.net/tracker/index.ph … tid=886114

In the meantime, thayer_andrews’ last post describes how to fix the problem. You’ll need to rebuild refinery.jar.

Thank you sthomas. I’ll try to patch the code with the above.

Has anyone actually added this to the distro yet? I just wasted a few hours baffled at it not working, only to find this post from a year ago. Unless I’m missing how people are using the refinery, It seems like command line macro support is an essential component if you want the refinery to be part of a content pipeline.
While admittedly it looks like a minor fix, patching it means keeping our own version of the code and I can no longer just hand people on my team the standard refinery installer.

-Gedalia