[sldev] Help with VWR-332 (Re: Investigating how the viewer creates object)

Ziggy Puff ziggy at planetziggy.com
Sun Jun 3 18:37:04 PDT 2007


I'd submitted VWR-332 a while back, and today I thought I'd try and 
figure it out myself. Since I just downloaded the code, this description 
helps a lot. VWR-332 appears to be an issue in how scripted prim 
movement is rendered, specifically, the interpolation applied to 
rotation and translation. If anyone has pointers on where to look, I 
would really appreciate that. I found the LLVOVolume class, and 
LLCriticalDamp (though that's probably used for physical movement?). 
There are lerp and slerp functions in LLQuaternion, and there's 
LLDrawable::updateXform which seems to calculate damping/interpolation 
for translations and rotations. Right now I'm trying to figure out how 
all of these fit together, and which portions I should be looking at.

https://jira.secondlife.com/browse/VWR-332

Thanks,
Ziggy


Able Whitman wrote:
> With an eye towards figuring out how to implement visual object muting 
> (VWR-1017), I decided to look into how the viewer handles sim 
> notifications of new objects for it to render. I don't know how 
> interesting or useful this is, but I thought I'd share what I've 
> learned. If it would be helpful, I'd be happy to make a wiki entry 
> with this information.
>
> In summary, the process by which the viewer handles new object 
> notifications (as well as existing object updates) works like this:
>
> * register_viewer_callbacks() in llstartup.cpp registers an handler 
> for the ObjectUpdate message (defined in message_template.msg)
> * the viewer receives an ObjectUpdate message from a sim
> * the message is handled by process_object_update() in llviewermessage.cpp
> * the message is passed to gObjectList.processObjectUpdate() in 
> llviewerobjectlist.cpp
> * if the object is a new object, gObjectList.createObject() is called
>   - the object params are passed to the static 
> LLViewerObject::createObject() in llviewerobject.cpp
>   - LLViewerObject::createObject() examines the type of object to 
> create, and calls a specific constructor of a descendant of 
> LLViewerObject
>   - for prims, flexi-prims, and sculpties, the class in question is 
> LLVOVolume
> * gObjectList.processObjectUpdate() passes the message to 
> processUpdateCore()
> * processUpdateCore() passes the message to processUpdateMessage() on 
> the instance returned by LLViewerObject::createObject()
>   - for all LLViewerObject objects:
>     . the region and coordinates for the object are obtained
>     . object params like scale, material, touch (click) actions, and 
> attached sounds are processed
>     . object rotation, velocity, acceleration, angular velocity, hover 
> text, particle system settings, parent object, etc. are processed
>   - for LLVOVolume objects:
>     . scuplted prim settings and texture are processed
>     . animated textures are processed
>     . prim parameters like hollow, shear, twist, taper, skew, etc. are 
> processed by the static LLVolumeMessage::unpackVolumeParams()
>     . prim textures are updated by LLVOVolume::updateTEData()
> * processUpdateCore() adds the object to the list of active viewer 
> objects, and also to the render pipeline via gPipeline.addObject()
>
> The process by which the viewer handles object deletion notifications 
> works like this:
>
> * register_viewer_callbacks() in llstartup.cpp registers an handler 
> for the KillObject message (defined in message_template.msg)
> * the viewer receives a KillObject message from a sim
> * the message is handled by process_kill_object() in 
> llviewermessage.cpp, which loops through all objects to be killed as 
> listed in the message
> * if an object to be killed is selected, it is unselected via 
> gSelectMgr->removeObjectFromSelections()
> * the viewer object to be killed is found via gObjectList.findObject()
> * the object is killed by calling gObjectList.killObject()
>
> Thoughts on Implementing Object Muting:
>
> It seems like the straightforward approach would be something like this:
> * add a flag to the LLVOVolume class (perhaps BOOL mIsVisuallyMuted or 
> similar) which defaults to FALSE
> * in LLVOVolume::processUpdateMessage(), use the prim region, 
> coordinates, object id, and owner id to determine whether to flag the 
> object as muted or not
> * if the object is muted, override the object audio and click (touch) 
> settings so that the viewer's version of the object doesn't play sound 
> or respond to touch events
> * hook into LLVOVolume::updateTextures() to force the object to use 
> the default texture for all faces if the object is muted
> * also hook into LLPrimitive::unpackTEMessage() to force any texture 
> updates for the object sent from the sim result in "new" textures also 
> being forced to be the default texture
>
> Note that the default texture is the static LLViewerImage* 
> LLViewerImage::sDefaultImagep, which uses the IMG_DEFAULT texture 
> LLUUID (d2114404-dd59-4a4d-8e6c-49359e91bbf0, which seems to be the 
> default grey texture).
>
> I make a quick-and-dirty hack similar to the above to the LLVOAvatar 
> class, which forced every avatar to have their skin and clothing 
> rendered with the default grey texture. It was in the process of 
> making this hack that I discovered that hooking updateTextures() is 
> not enough, and that unpackTEMessage() was also necessary.
>
> Open issues I haven't investigated yet:
> * how to store and persist the list of filters to use to determine 
> which objects are muted
> * how to hook into the viewer UI to enable users to mark object as 
> muted or unmuted
> * how to determine whether a given region and coordinate, whether that 
> point exists within a given parcel or not
>
> I plan to look into how the existing muting mechanism works, to see 
> how feasible it would be to extend this to support visual muting of 
> object as well. I'm also going to look into how the viewer determines 
> the boundaries for parcels in a region, to see if there is a way to 
> quickly and efficiently check whether a point exists within a given 
> parcel or not, since I believe that muting object by parcel is the 
> most effective way to choose objects to mute.
>
> More Details on Object Creation:
>
> The viewer is notified buy the simulator of new objects to draw by a 
> variety of messages, most of them similar to the ObjectUpdate message 
> (defined in message_template.msg). These are the messages that appear 
> to be related to sim notifications of object that need to be drawn by 
> the viewer:
>
> * ObjectUpdate
>   - handled by process_object_update() in llviewermessage.cpp
> * ObjectUpdateCompressed
>   - handled by process_compressed_object_update() in llviewermessage.cpp
> * ObjectUpdateCached
>   - handled by process_cached_object_update() in llviewermessage.cpp
> * ImprovedTerseObjectUpdate
>   - handled by process_terse_object_update() in llviewermessage.cpp
>   - essentially the same handling code as ObjectUpdateCompressed
> * KillObject
>
> It's not entirely clear to me what what specific circumstances cause 
> the various ObjectUpdate messages to be generated, but for now I'm 
> mostly concerned with the general process for creating and updating 
> objects.
>
> Message handlers are configured by register_viewer_callbacks() in 
> llstartup.cpp. All of the ObjectUpdate-related messages call through 
> to LLViewerObjectList::processObjectUpdate() in llviewerobjectlist.cpp 
> with a little or no message-specific preprocessing.
>
> In LLViewerObjectList::processObjectUpdate():
>
> * the handle for the region that the object is in is decoded
> * this handled is validated against a list of regions known to the viewer
> * the viewer looks up the object in its list of known objects
>   - the global viewer object list is an LLViewerObjectList named 
> gObjectList
>   - lookups for known objects via gObjectList->findObject()
> * if the object already exists, the viewer updates its localid (which 
> I think is session-specific)
>   - the localid will also be updated if the object has moved from one 
> region to another
> * if the object doesn't exist, the viewer creates it
>
> Object creation occurrs in LLViewerObjectList::createObject(), which 
> just does some pre-processing and calls down to the static method 
> LLViewerObject::createObject() in llviewerobject.cpp. Based on the 
> type of object specified in the ObjectUpdate message, createObject() 
> call constructors for one of the following classes:
>
> LLVOVolume, LLVOAvatar, LLVOGrass, LLVOTree, LLVOTextBubble, 
> LLVOClouds, LLVOSurfacePatch, LLVOSky, LLVOStars, LLVOWater, 
> LLVOGround, LLVOPartGroup
>
> All of these classes derive (eventually) from LLViewerObject, which 
> itself derives from LLPrimitive.  Of these classes, the most 
> interesting one is LLBVOVolume, which is the class that encapsulates 
> what we generally think of as "prims". This includes all basic prim 
> types, plus flexi-prims and sculpted prims. Once the existing 
> LLViewerObject is updated, or a new one is created, 
> processUpdateObject() calls into 
> LLViewerObjectList::processUpdateCore() in llviewerobjectlist.cpp.
>
> The first thing processUpdateCore() does is call the instance method 
> processUpdateMessage() on the LLViewerObject instance returned from 
> LLViewerObject::createObject(). (If the object already existed, this 
> method is called on the existing instance of the object found via 
> gObjectList->findObject().)
>
> In the case of prim objects, the method called is 
> LLVOVolume::processUpdateMessage(), which immediately calls into the 
> base implementation on LLViewerObject::processUpdateMessage().
>
> The base implmenentation of processUpdateMessage():
>
> * first determines the region the object is in and its coordinates in 
> that region
> * processes properties common to all the different 
> ObjectUpdate-related messages: object id, parent id, material, 
> attached sound, click (touch) action,  scale, etc.
> * processes properties specific to the different types of 
> ObjectUpdate-related messages
>
> There is rather a mess of code which handles the special cases of 
> ObjectUpdate messages--cached, compressed, terse, or improved terse 
> message types. The special cases are handled by nested switch and 
> if/then blocks, with a lot of magic numbers and a good deal of code 
> specific to more-derived LLViewerObject types. This section of code 
> alone is more than 1,000 lins long, and parts of it probably should be 
> moved into the derived implementations of processUpdateMessage(). (The 
> whole base implementation of this method is about 1,200 lines, so the 
> special-cased section is likely ripe for refactoring.)
>
> The derived LLVOVolume::processUpdateMessage():
>
> * processes scuplted prim settings and textures
> * processes animated textures
> * processes prim parameters like hollow, shear, twist, taper, skew, 
> etc. via the static method LLVolumeMessage::unpackVolumeParams()
> * updates prim textures via LLVOVolume::updateTEData()
>
> Finally, processUpdateCore() adds the prim to the list of active 
> viewer object (if the object is indeed active) and then calls the 
> updateTextures() method on the instance of LLViwerObject for the 
> object. Then the object is added to the render pipeline by calling 
> gPipeline.addObject().
>
>
> --Able
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Click here to unsubscribe or manage your list subscription:
> /index.html
>   




More information about the SLDev mailing list