Question about using Bezier interpolations with ColladaMax

Would someone be kind enough to point me in the right direction here? I’ve been working on a simple COLLADA viewer and can’t seem to get my animations correct when using Bezier curves. I’ve seen the page here, but with the output from 3DS MAX I seem to be missing something. For example, if I’m translating along the X axis from 100 to 200 units. The in/out tangent values I get in my exported COLLADA document are all less than one, so if I try to use them as offsets to the keyed in/out values, I end up with an incorrect curve (after plugging in the values).

I guess my actual question is: how do I compute the second and third Bezier control points using what I’m given from ColladaMax?

Any help or pointers in the right direction would be much appreciated, thanks.


I’m afraid this is old code that I assumed worked in the exporter. I just verified your statement and it does seem to give strange values. Even the importer cannot handle Max’s tangents: they are all forced to zero, right now.

I’ll look into improving this situation for the next version of ColladaMax.


Thank you for looking into this. It seems it’s exporting the tangent values that Max uses directly (they match up with what I see in the key properties) instead of control points (or offsets) directly. I’ve tried a few things, but can’t quite seem to get the right curve, apart from the degenerate case of when the tangents are 0.

Thanks again, I appreciate any improvements that can be made to this.

I’ve been playing around with the plugin and have a hackish fix for at least part of the Bezier tangent stuff. At around line 1898 in ColladaExporter.cpp, I’ve changed the else clause to be:

// Figure out which value in the list we are interested in 
int subanimIndex = (int) subanim; 
if (subanimIndex < 0 || subanimIndex >= v.Count()) subanimIndex = 0; 
// Write out the one wanted value 
if (vString.length() > 0) vString.append(' '); vString.append(ap.mapper->Map(v[subanimIndex])); 
if (hasTangents && subanimIndex < it.Count()) 
	if (itString.length() > 0) itString.append(' '); 
	if (otString.length() > 0) otString.append(' '); 
	if (false == isBezierKey) { 
	} else { 
		float origVal1 = ap.mapper->Map(it[subanimIndex]); 
		float origVal2 = ap.mapper->Map(ot[subanimIndex]); 
		if (i < numKeys) { 
			IBezFloatKey bfk; 
			ki->GetKey(i, &bfk); 
			if (i < numKeys) { 
				TimeValue lastTime = maxc->GetKeyTime(i-1); 
				TimeValue nextTime = maxc->GetKeyTime(i+1); 
				float dt; 
				float dy; 
				dt = (lastTime - bfk.time) * bfk.inLength; 
				dy = bfk.intan * dt; 
				dt = (nextTime - bfk.time) * bfk.outLength; 
				dy = bfk.outtan * dt; 
			} else { 
			}//if (i < numKeys) 
		} else { 
		}//if (i < numKeys) 
	}//if (false == isBezierKey) 
}//if (hasTangents && subanimIndex < it.Count())

I’m sure there’s a more elegant way of doing it, and I didn’t explore enough to discover everywhere this change needs to happen, but calculating the Y offset is pretty straightforward.

I also want to explain the reason I have two checks for (i<numKeys) is because for some reason after the call to GetKey(), the value of ‘i’ was changed to some huge number, crashing 3DS MAX. So while not a good solution, and probably only solving the race condition for me, that’s why I have those two checks.

Hopefully this was helpful and enough to encourage someone who’s more familiar with the code than I to come up with a proper fix :). thanks again.

Hi Camennie,

I’m currently looking into this issue as well. On the import side, I am correcting some issue with the animation curve merging algorithm of FCollada. On the export side, I’ve checked your code and I based my solution on it. Thanks for sharing code with everyone.

Right now, I’m hoping to have a new release of ColladaMax this week that will fix the export/import of animation tangents along with other user-provided/requested fixes.


Thanks for looking into this and the quick response. I noticed after I made my post that the value of “dy” needs to be converted from radians to degrees if we’re dealing with rotations at the time. I simply looked for when sampleType was equal to IGAME_ROT and converted “dy” to degrees when that was the case.

I’ll be looking forward to the upcoming release. Thanks again!