First of all, a question: Would it make any sense to start a "VOS
Development" mailing list separate from this discussion one? I hate clogging
the list with all my posts about build problems and such, but also don't
feel good about just sending it directly to the main developers -- there may
be other people out there looking at the code who would be interested.

Secondly, my movement interpolation modifications are going pretty well. My
local branch is now at the point where it officially "works" and correctly
interpolates the movement and rotation for any vobject that moves (including
other avatars and things like the doors in Peter's demo world) -- but
there's still some things that need to be cleaned up and fleshed out, so
it's not quite ready to be revision-bundled and submitted yet.

However, I thought it would be good to send an email summarizing the basic
design I'm using, for comments/suggestions. So here goes:

The algorithm itself is a familiar one from any modern online game: to
interpolate, you must add some visible lag -- enough so you can get at least
two network updates before having to display the movement from the first
one -- and keep a history buffer of movement updates for all moving objects.
Then you can interpolate between the updates in the history buffer. (There's
another method known as extrapolation, where you add no lag, and you either
send velocity vectors along with position, or discern velocity from previous
updates, and keep moving the objects out along their current path. However,
while this works when everyone's going pretty straight, it can lead to
distracting artifacts when there's lots of starting and stopping or changing
direction.) Since there's already network lag, lagging a little bit more is
an acceptable tradeoff for much smoother looking motion.

There's one big difference between the network activity of games like
Half-Life 2 and of VOS: Online games usually use a known, fixed update
heartbeat, and differences in packet arrival times are generally due to
network jitter, server lag, or dropped packets. As far as I could tell, VOS
has no such update clock, and my measurements of movement arrival intervals
varied between 30ms and 240ms for just walking an avatar across the screen
on the interreality world server. Usually the history buffer size is around
2x the update period, but 500ms of lag would have been a bit much. So I
chose a default buffer size of 250ms for now (Half-Life 2 uses 100ms) -- but
that can be changed by the application (and in the future, perhaps an
adaptive buffer size would be doable -- not sure if it's worth the effort,
though). The variable update period doesn't affect the algorithm greatly,
but a few things are affected -- for instance, when an object starts moving
from standing still, I don't know whether that update represents 30ms of
movement or 240ms. I assume worst case for now and interpolate starting
movements over the full 250ms, which looks fine in most cases, but also
leads to a weird "slow-start" effect in others (such as jumping). I may tune
this parameter a bit before submitting my changes.

Another thing to worry about is teleportation -- not as common in VOS as in
FPS games (you teleport when you die), but it happens. You can always "Warp
to starting point" in Ter'Angreal, for instance. But visually you'd want the
teleport to look like a teleport, not like the object is zooming across the
sector really fast. The way I'm addressing this is having a "maximum
velocity" specified. Any object travelling faster than this between two
points is assumed to be teleporting, and is "snapped" to its position. There
is a default maximum velocity, and it can also be set per-object. In the
future, other ways to explicitly specify a teleport event might be possible.

I should also mention that interpolation can be enabled or disabled
globally, and I've added a menu item to my local Ter'Angreal to do this
(mostly so I can do a before/after comparison, but some people may want to
disable interpolation for some reason). It can also be disabled
per-object -- for example, you don't want to do interpolation on your own
avatar.

OK. For the actual code design, I've created a new class,
HistoryBufferEntry, and two inheritors of that class, PositionBufferEntry
and OrientationBufferEntry. The parent class keeps the timestamp for the
entry and has utility functions relating to time. The children classes keep
a csVector3 and a csQuaternion respectively, along with functions to
interpolate between two entries. csMetaObject3D gets a couple deques holding
vRefs to HistoryBufferEntries -- one for positions and one for orientations.
If interpolation is enabled, instead of snapping right to a new position as
soon as a property update is received, it pushes it on to the deque (i use
deque instead of queue for the at() function -- I need access to both the
element on the front and the one right behind it to interpolate between
them).

Instead of calculating interpolations for all objects all the time -- I
imagined a world filled with thousands of moving objects -- I made
csVosObject3D an iMeshDrawCallback and do the interpolation for an object
within BeforeDrawing(). One thing I wasn't sure about was when BeforeDrawing
gets called and when it doesn't. The always helpful and precise CrystalSpace
API documentation simply says "Note that this function will be called even
if the object is not visible. In general it is called if there is a likely
probability that the object is visible (i.e. it is in the same sector as the
camera for example)." Well, it turns out that "in the same sector" isn't
*really* the spec for when it gets called, as sometimes just being outside
the camera frustrum is enough to not call it. Well! This is a problem, since
the position of the mesh won't get updated unless it's called, so it may
never move into the camera frustrum. To solve this, I'm keeping a global
list of objects with non-empty position buffers in csVosA3DL, and every
Process event I'm going through that list and moving objects to their "key
frames" (actual updates received) at the appropriate times (and then
removing those key frames from the history buffers).

And that's about it. I still have some things to work on (I haven't actually
done the key-frame updates in csVosA3DL yet; I started with the assumption
that syncPosition and syncOrientation only occurred on new property updates,
and then discovered that's not the case, and have to fix some things; I
haven't decided just how to deal with a doMoveTo applied to an object being
interpolated; model animation isn't in sync with the movement (it's not
being lagged); "teleport detection" isn't implemented yet; I need to handle
Ter'Angreal "grabbing" properly; etc) so it'll probably be another week or
so before I'm ready to submit it. But the basics are working, and it looks
pretty nice :)

-Ken


_______________________________________________
vos-d mailing list
[email protected]
http://www.interreality.org/cgi-bin/mailman/listinfo/vos-d

Reply via email to