How often update a scene ?

This topic is 2029 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

How often do I have to call the update function to render an animated scene ? If I call the update() function every millisecond the program get slow (obviously because of the recursive matrix calculation of each bone from the root all over again)... I call the update function right before it is rendered to the scene.. Any ideas ?

Share on other sites

Call it as often as you like but pass it the delta-time since the last render.

You can also take a look at Fix Your Timestep.

Share on other sites

If I even try to update the scene in bind pose where no animation occurs fps counter shows 1 . I have calculated the dt, before because I rendered static animation. I have to pass the animation time adding dt to it every time right ?

Edit: fps is too low . is it a possibility that the animation is just too complex ? I play batman and other games smoothly but this program fps 1 ?? Seriously ?

Edit2 : from what I am guessing now do I have to use dynamic programming to precalculate the values ?

Share on other sites

Hi,

Scenes should typically be updated as many times as possible, from the information you provided the problem you're having is not due to the frequency of updates but rather because of something else going on in the update function (or in fact any function being called every frame). Could be a very expensive function being called many times during each update or a recursion/iteration large enough to slow down the entire application.

Share on other sites

Hi,

Scenes should typically be updated as many times as possible, from the information you provided the problem you're having is not due to the frequency of updates but rather because of something else going on in the update function (or in fact any function being called every frame). Could be a very expensive function being called many times during each update or a recursion/iteration large enough to slow down the entire application.

Exactly multiplying every matrix from the scene node each time . Really expensive....

Share on other sites

Post the code where you measure the time between updates. Unless your update code is completely FUBAR, the matrix calculations even for the most complex node hierarchy don't take a second. It's much more likely you're measuring the time incorrectly, or something else is hanging up.

If you really want to find the problem, you need to profile your code - maybe as simple as sprinkling some debug output lines before a few calls in your update routine to report the time. Run a few frames and see where the time is being taken up.

Edited by Buckeye

Share on other sites

You should probably update about once a vblank, if possible, though you can get away with much less, and there isn't much point in updating any faster than that, as the user won't see it.  (Or they might if they have vsync disabled, but it will probably be garbled gunk at that point)

Share on other sites

Scenes should typically be updated as many times as possible

Scene should be updated as infrequently as possible. Common rates are 30-40 times per second.

Exactly multiplying every matrix from the scene node each time . Really expensive....

Then why are you doing it?
Why don’t you have dirty flags that allow you to update only what has changed (and things affected by those changes such as children nodes)?

I have to pass the animation time adding dt to it every time right ?

If by that you mean you have pass a delta time between frames so your animation can accumulate time and determine where it is in its timeline, yes, you would have to do this anyway.

L. Spiro

Share on other sites

Why don’t you have dirty flags that allow you to update only what has changed (and things affected by those changes such as children nodes)?

I am trying to do that currently. Trying to figure out how to tell before time if it will be changed or not...

Post the code where you measure the time between updates.

void GameTimer::Tick()
{
if( mStopped )
{
mDeltaTime = 0.0;
return;
}

__int64 currTime;
QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
mCurrTime = currTime;

// Time difference between this frame and the previous.
mDeltaTime = (mCurrTime - mPrevTime)*mSecondsPerCount;

// Prepare for next frame.
mPrevTime = mCurrTime;

// Force nonnegative.  The DXSDK's CDXUTTimer mentions that if the
// processor goes into a power save mode or we get shuffled to another
// processor, then mDeltaTime can be negative.
if(mDeltaTime < 0.0)
{
mDeltaTime = 0.0;
}
}


Its also taken from frank d luna. And I think it is not the source of the problem . Because if I use dt = 1/60.0f it does not effect at all.... Here is the matrix calculation calls which concern me....

void Bones::UpdateNode(float AnimationTime, const aiNode *pNode, const XMFLOAT4X4 parentMatrix) //Bone Index, Parent Matrix (Transformation)
{
const char *name = pNode->mName.C_Str();
const aiAnimation *pAnimation = m_pScene->mAnimations[0];
XMFLOAT4X4 temp;
AItoXM(pNode->mTransformation, temp);

const aiNodeAnim* pNodeAnim = FindNodeAnim(pAnimation, name);

if (pNodeAnim) {
aiVector3D Scaling;
CalcInterpolatedScaling(Scaling, AnimationTime, pNodeAnim);
XMMATRIX ScalingM;
ScalingM = XMMatrixScaling(Scaling.x, Scaling.y, Scaling.z);
ScalingM = XMMatrixTranspose(ScalingM);

aiQuaternion RotationQ;
CalcInterpolatedRotation(RotationQ, AnimationTime, pNodeAnim);
XMMATRIX RotationM;
XMFLOAT4 temp = XMFLOAT4(RotationQ.x, RotationQ.y, RotationQ.z, RotationQ.w);
RotationM = XMMatrixRotationQuaternion(temp2);
RotationM = XMMatrixTranspose(RotationM);

aiVector3D Translation;
CalcInterpolatedPosition(Translation, AnimationTime, pNodeAnim);
XMMATRIX TranslationM;
TranslationM = XMMatrixTranslation(Translation.x, Translation.y, Translation.z);
TranslationM = XMMatrixTranspose(TranslationM);

NodeTransformation = TranslationM * RotationM * ScalingM;
}

XMMATRIX finalTransform = XMLoadFloat4x4(&parentMatrix) * NodeTransformation;

if (mBoneInfoMap.find(name) != mBoneInfoMap.end())
{
debug << "entered" << std::endl;
int boneID = mBoneInfoMap[name];
XMMATRIX temp2 = finalTransform * XMLoadFloat4x4(&mBoneInfo[boneID].offsetMatrix);
temp2 = XMMatrixTranspose(temp2);
XMStoreFloat4x4(&mBoneInfo[boneID].Transform, temp2);
}

XMFLOAT4X4 temp3;
XMStoreFloat4x4(&temp3, finalTransform);

for (int i = 0; i < pNode->mNumChildren; i++)
{
UpdateNode(AnimationTime, pNode->mChildren[i], temp3);
}
}

const aiNodeAnim *Bones::FindNodeAnim(const aiAnimation *pAnimation, const std::string NodeName)
{
for (UINT i = 0; i < pAnimation->mNumChannels; i++) {
const aiNodeAnim* pNodeAnim = pAnimation->mChannels[i];

if (std::string(pNodeAnim->mNodeName.data) == NodeName) {
return pNodeAnim;
}
}

return NULL;
}

void Bones::CalcInterpolatedRotation(aiQuaternion &out, float AnimationTime, const aiNodeAnim *pNodeAnim)
{
if (pNodeAnim->mNumRotationKeys == 1) {
out = pNodeAnim->mRotationKeys[0].mValue;
return;
}

UINT RotationIndex = FindRotation(AnimationTime, pNodeAnim);
UINT NextRotationIndex = (RotationIndex + 1);
assert(NextRotationIndex < pNodeAnim->mNumRotationKeys);
float DeltaTime = pNodeAnim->mRotationKeys[NextRotationIndex].mTime - pNodeAnim->mRotationKeys[RotationIndex].mTime;
float Factor = (AnimationTime - (float)pNodeAnim->mRotationKeys[RotationIndex].mTime) / DeltaTime;
assert(Factor >= 0.0f && Factor <= 1.0f);
const aiQuaternion& StartRotationQ = pNodeAnim->mRotationKeys[RotationIndex].mValue;
const aiQuaternion& EndRotationQ = pNodeAnim->mRotationKeys[NextRotationIndex].mValue;
aiQuaternion::Interpolate(out, StartRotationQ, EndRotationQ, Factor);
out = out.Normalize();
}

UINT Bones::FindRotation(float AnimationTime, const aiNodeAnim *pNodeAnim)
{
assert(pNodeAnim->mNumRotationKeys > 0);

for (UINT i = 0; i < pNodeAnim->mNumRotationKeys - 1; i++) {
if (AnimationTime < (float)pNodeAnim->mRotationKeys[i + 1].mTime) {
return i;
}
}

assert(0);
}

UINT Bones::FindPosition(float AnimationTime, const aiNodeAnim *pNodeAnim)
{
for (UINT i = 0; i < pNodeAnim->mNumPositionKeys - 1; i++) {
if (AnimationTime < (float)pNodeAnim->mPositionKeys[i + 1].mTime) {
return i;
}
}

assert(0);

return 0;
}

void Bones::CalcInterpolatedPosition(aiVector3D &out, float AnimationTime, const aiNodeAnim *pNodeAnim)
{
if (pNodeAnim->mNumPositionKeys == 1) {
out = pNodeAnim->mPositionKeys[0].mValue;
return;
}

UINT PositionIndex = FindPosition(AnimationTime, pNodeAnim);
UINT NextPositionIndex = (PositionIndex + 1);
assert(NextPositionIndex < pNodeAnim->mNumPositionKeys);
float DeltaTime = (float)(pNodeAnim->mPositionKeys[NextPositionIndex].mTime - pNodeAnim->mPositionKeys[PositionIndex].mTime);
float Factor = (AnimationTime - (float)pNodeAnim->mPositionKeys[PositionIndex].mTime) / DeltaTime;
assert(Factor >= 0.0f && Factor <= 1.0f);
const aiVector3D& Start = pNodeAnim->mPositionKeys[PositionIndex].mValue;
const aiVector3D& End = pNodeAnim->mPositionKeys[NextPositionIndex].mValue;
aiVector3D Delta = End - Start;
out = Start + Factor * Delta;
}

UINT Bones::FindScaling(float AnimationTime, const aiNodeAnim *pNodeAnim)
{
assert(pNodeAnim->mNumScalingKeys > 0);

for (UINT i = 0; i < pNodeAnim->mNumScalingKeys - 1; i++) {
if (AnimationTime < (float)pNodeAnim->mScalingKeys[i + 1].mTime) {
return i;
}
}

assert(0);

return 0;
}

void Bones::CalcInterpolatedScaling(aiVector3D &out, float AnimationTime, const aiNodeAnim *pNodeAnim)
{
if (pNodeAnim->mNumScalingKeys == 1) {
out = pNodeAnim->mScalingKeys[0].mValue;
return;
}

UINT ScalingIndex = FindScaling(AnimationTime, pNodeAnim);
UINT NextScalingIndex = (ScalingIndex + 1);
assert(NextScalingIndex < pNodeAnim->mNumScalingKeys);
float DeltaTime = (float)(pNodeAnim->mScalingKeys[NextScalingIndex].mTime - pNodeAnim->mScalingKeys[ScalingIndex].mTime);
float Factor = (AnimationTime - (float)pNodeAnim->mScalingKeys[ScalingIndex].mTime) / DeltaTime;
assert(Factor >= 0.0f && Factor <= 1.0f);
const aiVector3D& Start = pNodeAnim->mScalingKeys[ScalingIndex].mValue;
const aiVector3D& End = pNodeAnim->mScalingKeys[NextScalingIndex].mValue;
aiVector3D Delta = End - Start;
out = Start + Factor * Delta;
}

void Bones::XMBones()
{
mBoneTransforms.clear();
for (int i = 0; i < mBoneInfo.size(); i++)
{
XMFLOAT4X4 temp;
XMStoreFloat4x4(&temp, XMMatrixIdentity());
mBoneTransforms.push_back(mBoneInfo[i].Transform);
}
}


Share on other sites

Some issues I see that can be more or less removed easily:

1.) Using strings as keys is slow when the strings are compared character-wise.

2.) Looking up an animation node for each bone on every iteration is ineffective. Instead use a runtime instance and bind on creation.

XMMatrixTranspose(TranslationM) * XMMatrixTranspose(RotationM) * XMMatrixTranspose(ScalingM)

use the equivalent

XMMatrixTranspose(Scaling * Rotation * Translation)

4.) What exactly do all the conversions between XMFLOAT4x4 and XMMATRIX?

5.) Do not iterate the animation tracks over and over again to look up the current keyframes. Remember the latest used pair of keyframes per track as starting points for the next look-ups.

An optimization is to take advantage of the knowledge about semantics of scaling, rotation, and translation and the belonging structure of the respective matrices. Assuming that XMMATRIX::operator* is implemented the usual way, you can reduce the amount of memory accesses, scalar multiplications and additions significantly when dropping all multiplications by 0 or 1 and all additions of 0 by not using the full matrix product.

Another thing is aiQuaternion::Interpolate. I don't know how it is implemented, but I would expect aiQuaternion to be a unit quaternion, so that its interpolation gives / should give you a unit quaternion back. Then there is no need to normalize it again explicitly.
Edited by haegarr

• Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 14
• 18
• 19
• 11
• 9