The COLLADA 1.4.1 REVISION A Release Notes explains the curve interpolation semantics.
Is there something that needs further clarification?
The COLLADA 1.4.1 REVISION A Release Notes explains the curve interpolation semantics.
Is there something that needs further clarification?
Mark Barnes
http://mechnicality.com
I think so, yes. The documentation on Spline Curves is perfectly clear. However the documentation on Animation Curves is a bit vague. I understand the description of what's going on with the input and output values. Then in the description of Bezier animation curves the spec says:
The <spline> equation for Bezier curves is given asThe same equations for cubic Bézier and Hermite interpolation already defined for <spline> are to be used, with the following geometry vector, for parameter j, segment[i]:
For Bézier:
• P0 is (INPUT[i] , OUTPUT[j][i])
• C0 (or T0) is (OUT_TANGENT[0][i] , OUT_TANGENT[j][i])
• C1 (or T1) is (IN_TANGENT[0][i+1], IN_TANGENT[j][i+1])
• P1 is (INPUT[i+1], OUTPUT[j][i+1])
So I have my P0, C0, P1, and C1, but what s value do I use? Typically I'm given an input value and I want to find the corresponding output value. If I just evaluate B(s) using the input value I want then I'll get incorrect results. This is what I tried to show two posts ago. I need to solve B(s) to get the s that corresponds to the input value I'm looking for, then plug that s into B(s) to get the output value. That extra step isn't mentioned in the spec.B(s) = P0(1− s)^3 + 3C0s(1− s)^2 + 3C1s^2 (1− s) + P1s^3 ,s ∈ [0,1]
This is where you need to use a de Casteljau algorithm or other algorithms that are used for that exact purpose -> finding s and B(s) corresponding to the value you are looking for.
Regards
As I understand it, the de Casteljau algorithm is an alternative to Bernstein polynomials for evaluating Bezier curves. How would it help us find the roots of a cubic equation? Why not just use the method described here, say? (see Cardano's method)
But in any case, can we agree that the spec could be more clear about this? If I follow the spec exactly, I end up with a curve B(s) and no s to evaluate it with. I can compute the s given the input value I want to evaluate, but that step isn't mentioned at all. Shouldn't we add a description of that to the spec for completeness?
I think what we need is some sample code implementing the algorithm.Shouldn't we add a description of that to the spec for completeness?
here's our code to evaluate cubic Bezier curves using de Casteljau Subdivision, hoping this helps:
Code :#define INVERTPARAMCUBIC_TOL 1.0e-09 #define INVERTPARAMCUBIC_SMALLERTOL 1.0e-20 #define INVERTPARAMCUBIC_MAXIT 100 ... case SI_CUBIC: { CSLCubicKey *l_pPrevKey = ((CSLCubicKey*)(&GetCubicKeyListPtr()[prev_key])); CSLCubicKey *l_pNextKey = ((CSLCubicKey*)(&GetCubicKeyListPtr()[next_key])); float v1 = l_pPrevKey->m_fRightTanX + l_pPrevKey->m_fTime; // OUT_TANGENT[n].X float v2 = l_pNextKey->m_fLeftTanX + l_pNextKey->m_fTime; // IN_TANGENT[n+1].X // in_fTime = current_time // INPUT[n] = l_pPrevKey->m_fTime // INPUT[n+1] = l_pNextKey->m_fTime float u = InvertParamCubic ( in_fTime, l_pPrevKey->m_fTime, v1, v2, l_pNextKey->m_fTime ); v1 = l_pPrevKey->m_fRightTanY + l_pPrevKey->m_fValue; // OUT_TANGENT[n].Y v2 = l_pNextKey->m_fLeftTanY + l_pNextKey->m_fValue; // OUT_TANGENT[n+1].Y // // Bernstein Evaluation // // OUPUT[n] = l_pPrevKey->m_fValue // OUTPUT[n+1] = l_pNextKey->m_fValue float c = 3.0f*(v1 - l_pPrevKey->m_fValue); float e = 3.0f*(v2 - v1); m_fLastEvaluation = (((l_pNextKey->m_fValue - l_pPrevKey->m_fValue - e)*u + e - c)*u + c)*u + l_pPrevKey->m_fValue; if ( m_pParameter != NULL ) m_pParameter->SetFloatValue( m_fLastEvaluation ); break; } ... float InvertParamCubic ( float Param, float x0, float x1, float x2, float x3 ) { if (Param - x0 < INVERTPARAMCUBIC_SMALLERTOL) { return 0.0; } if (x3 - Param < INVERTPARAMCUBIC_SMALLERTOL) { return 1.0; } long cnt2 = 0; // de Casteljau Subdivision. float u = 0.0f; float v = 1.0f; while (cnt2 < INVERTPARAMCUBIC_MAXIT) { double a = (x0 + x1)*0.5f; double b = (x1 + x2)*0.5f; double c = (x2 + x3)*0.5f; double d = (a + b)*0.5f; double e = (b + c)*0.5f; double f = (d + e)*0.5f; if (fabs(f - Param) < INVERTPARAMCUBIC_TOL) { return ClampToZeroOne((u + v)*0.5f); } if (f < Param) { x0 = f; x1 = e; x2 = c; u = (u + v)*0.5f; } else { x1 = a; x2 = d; x3 = f; v = (u + v)*0.5f; } cnt2++; } return ClampToZeroOne((u + v)*0.5f); }