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
