Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Professional Discussion / Force Bone Animation Update Before Sync ?

Author
Message
MMM
17
Years of Service
User Offline
Joined: 21st Jan 2009
Location: NSW, Australia
Posted: 12th Jan 2013 01:53 Edited at: 12th Jan 2013 01:54
I need to forcibly update bone animations without or before a SYNC command. Here is why:


Whenever we call a bone-animated object to be updated (using any of the DBPro or EnAn playback commands) we require a SYNC or a FASTSYNC for the update to be applied. It is common to read back the positions and rotations of bones in a skeleton using the limb position xyz() and limb direction xyz() commands and use that information to position and rotate a collision box. But because the bones are only updated with a SYNC or FASTSYNC, the collision box position and rotation updates will always be an apparent single frame behind the source-model visuals. This is not such an issue when "playing" an object because interpolation smoothes the bone and collision box positions and rotations - but it can become an issue when "setting the object frame" because the difference in values can be massive. The problem only lasts for a single frame - but that can mean the difference between a bullet collision and a miss.


I am using Enhanced Animations, so the following is for coders who understand something about that system - where "limbs" and "bones" are the same thing:


EnAn can do what I want by updating an OAC model using the enan_oacupdate command. It can then read back the new bone positions and rotations before the SYNC using the enan_oacgetlimbposxyz() and enan_oacgetlimbrotxyz(). Alternatively, it can read straight from an animation file using the enan_animgetkeyposxyz() and enan_animgetkeyrotxyz() command. But the returned positions and rotations from these EnAn commands don't make any sense to me; the help files call them "offsets" which I assume means the returned values are offsets from their parent limbs. The above-mentioned DBPro commands return world coordinates (which is awesome and very useful) but how can I turn these EnAn "offsets" into world coordinates?

I've tried adding together the offsets of the target bone and all its sequencial parents but I think I've gotten the maths wrong. I don't even know if that method would work.

Has anyone done this before?
Rudolpho
20
Years of Service
User Offline
Joined: 28th Dec 2005
Location: Sweden
Posted: 12th Jan 2013 13:37
Quote: "I've tried adding together the offsets of the target bone and all its sequencial parents"

You should add the object position to them as well I'd imagine.


"Why do programmers get Halloween and Christmas mixed up?"
Mage
Valued Member
19
Years of Service
User Offline
Joined: 3rd Feb 2007
Location:
Posted: 12th Jan 2013 16:49
I ran into this problem recently when attaching a camera to the player character in my game. I am using Enhanced Animations but to make the character aim up and down I rotate limbs manually with the regular commands.

When I attach a camera to the head, it causes problems where the camera doesn't maintain its place correctly. The game positions the camera on a limb, but when sync is called it moves that limb and draws the screen in one go. The result is the camera is never in the proper position.

My solution so far has been to avoid relying on limb positions directly.

I am vaguely aware of Lee posting about updating the animation in a separate function call. However, I can't remember if this was DGDK, maybe mentioning internal functions inside of DBP, or an undocumented feature.

Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 13th Jan 2013 00:54
What happens if you use a separate camera to update the animation, then pause the animation, pick up the values you want then sync the main camera? Since you're not using the render output of the first camera you could render to a very low res image, e.g. 64x64, or not render at all(?).

I've no idea whether this is actually possible though.
MMM
17
Years of Service
User Offline
Joined: 21st Jan 2009
Location: NSW, Australia
Posted: 13th Jan 2013 06:36 Edited at: 13th Jan 2013 06:37
Quote: "You should add the object position to them as well I'd imagine."


That's fair. I have been testing with the source model at default position and rotation (0,0,0 and 0,0,0) to avoid this step for now. But that would indeed be necessary beyond the test.

@Mage: yeah, that's the problem. I've previously managed it by listing all the necesarry bone rot/pos-xyz values in an array, saving the array as a memblock inside the collision box .DBO (using an editor) then extracting the memblock in-game, and converting back to array format to be read like an in-built animation - so instead of referencing the bone position for the current frame, you'd referencce the current frame in the array. That works sure enough, but it gets costly holding dozens of these arrays in memory when using dozens of different models - particularly as the data is essentially a replica of the data already held by DBPro somewhere in its memory. Plus these silly problems usually have five-line solutions I'm just not aware of.

Quote: "What happens if you use a separate camera to update the animation, then pause the animation, pick up the values you want then sync the main camera?"


Crucially, only the "sync" and "fastsync" commands will update the bones - not the "sync camera" utility command - so I'm having some difficulty building a test for this. The following code achieves what I want - but is it really updating the bones by syncing the dummy camera or does it just "appear" to do that?



Have I got my "sync mask" wrong or something?
Mage
Valued Member
19
Years of Service
User Offline
Joined: 3rd Feb 2007
Location:
Posted: 13th Jan 2013 06:39
Quote: "What happens if you use a separate camera to update the animation, then pause the animation, pick up the values you want then sync the main camera? Since you're not using the render output of the first camera you could render to a very low res image, e.g. 64x64, or not render at all(?).

I've no idea whether this is actually possible though. "


I'm not certain, but I wouldn't even try. It would cause an unacceptable performance loss in my situation.

It's a creative idea however.

Mage
Valued Member
19
Years of Service
User Offline
Joined: 3rd Feb 2007
Location:
Posted: 13th Jan 2013 06:42
Quote: "@Mage: yeah, that's the problem. I've previously managed it by listing all the necesarry bone rot/pos-xyz values in an array, saving the array as a memblock inside the collision box .DBO (using an editor) then extracting the memblock in-game, and converting back to array format to be read like an in-built animation - so instead of referencing the bone position for the current frame, you'd referencce the current frame in the array. That works sure enough, but it gets costly holding dozens of these arrays in memory when using dozens of different models - particularly as the data is essentially a replica of the data already held by DBPro somewhere in its memory. Plus these silly problems usually have five-line solutions I'm just not aware of."


Yeah that seems like a awful lot of work and not a lot of benefits.

MMM
17
Years of Service
User Offline
Joined: 21st Jan 2009
Location: NSW, Australia
Posted: 13th Jan 2013 11:50 Edited at: 13th Jan 2013 12:00
Right on both counts, Mage, but I think there might be more to this. So I've been testing this through a little trial and error:

First, I was wrong about the "sync camera" command; it will indeed update bones when called, just like "sync" and "fastsync" will. But all these commands will only update bones in models which are included in the chosen camera's individual view matrix. So basically, the camera must literally be looking at an object if its "sync" is going to update its bones - otherwise it simply skips the bone update altogether.

For all cameras, the view matrix is basically a spacial log of any model within its forward hemisphere. So any model in front of directly left, right, up and down from the camera is included, regardless of whether it is hidden, out of range, out of FOV or any other user setting. Furthermore, this matrix is rebuilt for every camera during every frame, regardless of whether the camera actually syncs or not. So even if you do not sync your camera, it will still suffer the draw-lag of any objects in its forward hemisphere - even if those objects are masked or hidden. What the hell, right?

(more knowledgeable people will confirm whether the matrix is based on objects or polygons - either way, the affect on bones is clear)

So building on GG's suggestion, my solution is to use a dummy camera with the "sync camera" command to update the bones. For any non-collision-check frames, this camera is exiled to a far corner of the game world and pointed out into empty space (so as to record absolutely nothing in its view matrix). Whenever a collision check is required, the camera is positioned in the appropriate place just long enough to "sync camera" then exiled again; so the 30-40% frame drop I experience from viewing a non-fastbone animated object twice in one update is contained in a single frame and pretty much invisible.

The results are good, if a little awkward. I've got this itching sense of dejavu over this solution - feel certain I've read this somewhere before.

I hope this little ditty explains what I mean. Maybe you guys could just check this for blatant code problems? I don't expect you to actually run it (you'd need your own models, anyway). Thanks guys.


Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 13th Jan 2013 13:04
Quote: "So building on GG's suggestion, my solution is to use a dummy camera with the "sync camera" command to update the bones. "


Quote: "I'm not certain, but I wouldn't even try. It would cause an unacceptable performance loss in my situation.

It's a creative idea however."


I'm amazed this worked at all.

The technical name for the technique is "creative hack".

It would be nice to have a more elegant way of doing the same thing.

One final thing to investigate is the difference between using the pairs sync mask/sync or sync mask/sync versus the simpler sync camera. I'm not too sure about the different side effects of those combinations.
MMM
17
Years of Service
User Offline
Joined: 21st Jan 2009
Location: NSW, Australia
Posted: 14th Jan 2013 01:56
Quote: "One final thing to investigate is the difference between using the pairs sync mask/sync or sync mask/sync versus the simpler sync camera."


To be honest, today I'm getting a whole different set of readings from my tests compared to yesterday - higher frame rates and fewer fluctuations due to multiple cameras. Cannot explain it. Still, the best setup seems to be...



...for the dummy camera update. Surprised that works. Doesn't seem to render an image at all. Good thing, I guess.

The main camera sync depends on how you're using the camera. Ideally I'd stick to specifying the specific camera with "sync camera" or using a sync mask.

Still want to push these tests to see how many updates a single loop can handle - but at least the principle works. Thanks for the help!
MMM
17
Years of Service
User Offline
Joined: 21st Jan 2009
Location: NSW, Australia
Posted: 15th Jan 2013 08:56
I feel obliged to post my final findings on this.

The system discussed so far gets current-frame bone position and rotation updates before the visual sync is called. The purpose is to position per-limb collision boxes with current-frame accuracy. This is best used for one-off collision checks like bullet-collision instead of more constant checks like wall-collision.

But it can actually be used for more constant collision checks too - with a few modifications.

To get constant updates, you'll need to use "sync camera" instead of the "sync mask / fastsync" method for the dummy camera. I believe this is because fastsync updates the bones without updating the "play" function - but I'm not sure.

Usually syncing a bone-animated object twice in one frame would drop the FPS by about %50 on a powerful machine - which could usually only be fixed with timer-based animation and v-sync. But using the fastbone.fx shader on the source model solves the lag issue completely - no lag at all occurs simply because the GPU can better handle the pipeline. Remeber, the objects are invisible to the dummy camera to avoid drawing the scene twice - but the dummy camera still knows the objects are there because they are within its forward view arc.

Leave it at that and you'll find your model playing at twice the speed you intended (two updates per frame) just as GG rightly pointed out. You can solve this by playing the object backwards for a single interpolated frame. You just call the playback command whenever the dummy camera is synced. The code is:



...and account for your own render pipeline.

Login to post a reply

Server time is: 2026-07-07 18:44:39
Your offset time is: 2026-07-07 18:44:39