High Level Overview
"Comforting Lies" -- By Bill Yerazunis and Barry Perlman
["Comforting Lies" was chosen as a subtitle by Bill to emphatically denote the high-level nature of this document. For the sake of clarity at this level, many of the details are glossed over in the main body of the text. Many are clarified via annotations. - Ed.]
This document gives a high-level overview of the entire OPEN COMMUNITY system from the point of view appropriate to an application designer and application programmer.
Open Community is a software library , callable from ANSI C or Java, designed to provide many of the essential services necessary to make real-time multi-user cooperative environments possible. Open Community takes care of issues like network communications, real-time audio transport, application-neutral transport of large or complicated objects such as VRML models, and region-of-interest filtering.
Applications linked to the Open Community library see these services as a specialized form of shared memory in the form of an object database, called the World Model, that is replicated in each application*. All objects in the world model are instances of classes provided by the Open Community library or user-defined classes derived from the Open Community base classes. These replicated objects are called ãsharedä.
[ * Comforting lie: actually, the database is only partially replicated in each application, it just looks like it's replicated. ]
The world model is partitioned into locales, and each applicationâs copy of the World Model contains only those locales that are relevant to the applicationâs current state. There is no central server and no need for any application to have an all-locales copy of the world model, so the world model can be much larger than any machine's virtual memory and each machine needs to operate on only a tiny fraction of the overall world model network traffic.
The rest of this document gives high-level overviews of the following
topics:
Table of contents:
Because this document is a high-level overview, many simplifications are made and many comforting lies are told; please forgive us if they cause you trouble.
Here's a very oversimplified view of how Open Community works:

In this drawing, we see that we have multiple user processes ãAä, ãBä and ãCä, all able to read and write from the shared object database, and all able to speak on and listen to the shared audio party line.
Of course, this is a greatly oversimplified view of Open Community, but it does bring out the following very important features:
Similarly, Open Community Audio has the similar properties:
[* Comforting lie. Actually, in a well-designed world, the object is visible only to those people near enough to see the object. This makes no difference as far as any user can tell, but a big difference in efficiency and network traffic.]
[** Comforting lie. Actually, in a well-designed world, sounds are heard only by those people near enough to hear them. This makes no difference as far as any user can tell, but a big difference in efficiency and network traffic.]
Of course, objects far from you in virtual space will appear very tiny on your screen, and people speaking far away will be heard only softly if at all. We should also mention now that locales break up this huge space so that it is possible to have privacy even in Open Community. Locales also make Open Community much more efficient, because they can limit the amount of visual and audio data that each user program must examine to render the visual image and audio sound effects.
It's also important to remember that although we've used the terms "data" and "audio" above, Open Community does not care what kind of data is being shared. 3D graphical objects and real-time sounds are only a few examples of the data that can be shared with Open Community. It is possible to extend the shared objects in Open Community by extending Open Community itself with either native methods (written in C) or Java methods.
The major oversimplifications of this diagram are that it ignores
These topics are discussed below.
The Open Community World Model
The world model contains a large number of objects with different properties.
(There are some other objects in the Open Community world model that are more subtle, such as Locales, Beacons, and Actors. These are explained later in this document, or in the other design documents.)
Consider the case of a Open Community session that has in it a piece of scenery, such as a shrub. It would be possible to transmit the full details of the shrub via the network as a part of the Open Community world model, but it would be inefficient. Furthermore, if there were a hundred identical shrubs, each shrub would be transmitted separately, increasing memory requirements and network bandwidth unnecessarily.
Instead of completely describing the shrub, a Open Community world model "object" of a shrub contains the coordinates of the shrub, and a URL that points to a geometry file that fully describes how to render the shrub. This geometry file is not necessarily in a format that Open Community itself understands; because all that is necessary is that the visual renderer used by a user program can understand the file format. Open Community itself will not read the file, instead, Open Community just makes URL available to all members of the Open Community session. If a particular user's application program wants to draw the shrub, then the user's program can read the URL independently of Open Community.
The "location" of the shrub is another interesting issue. In Open Community, an object's location can be given by the classical 4x4 homogeneous coordinate matrix used widely in computer graphics, or by the 17-element transform popular in the VRML community (this is X, Y, Z, object "center" X, Y, Z, a unit vector and rotation angle corresponding to the amount of rotation around that unit vector, plus a unit vector, rotation, and three orthogonal scalings. This gives a 17-element positioning/scaling capability that is fully compatible with VRML 2.0).
Open Community adds two interesting features to this concept of "location":
Because Open Community objects can have subobjects, many operations on the Open Community world model have parallels in the field of databases. Most databases use a locking protocol, but in Open Community, that would be unreasonably high in overhead. Instead, Open Community uses an cooperative protocol:
Each Open Community object in the Open Community cosmos has three different references.
The first such reference is the "parent" reference. The parent of a Open Community object is another Open Community object that is immediately "above" the object in the world model graph. If I change the Z-position of the parent object, the child object moves with the parent. The top-level objects in a particular locale are thus the immediate children of the locale. This leaves the interesting question of "what is the parent object of a locale?". In the case of Open Community 3.0, a locale has a NULL parent (and is therefore free-floating*). Note that this parent-child relationship is not the superclass-subclass relationship of derived classes.
[* Yes, but donât try and create a locale by setting the parent of an object to NULL. Locales have a lot of other magic as well that needs to be taken care of. ]
The second such reference is the ãownerä reference. The owner of a Open Community object is not a Open Community object, it is a process on a computer somewhere on the network.
The third such reference is the ãclassä. The class of a Open Community object is described by a Open Community class descriptor object (of class spClass). This descriptor object contains useful information about the class of the object in question. Open Community objects are self-identifying because each Open Community object contains a reference to its class descriptor object*.
[* Yes, but donât try to change the class of a Open Community object by changing the class reference. It Just Doesnât Work That Way. ]
So, one could build a tree of what a Open Community object gets from each of its three references; the tree looks like this:
1) Parent
2) Owner
3) Class
An Open Community application typically has an architecture that looks this- a classic "layer cake" system.
The Open Community library takes care of the whole middle layer

The Open Community library takes care of everything in the green space- the user application code sees the in-memory database and access methods, and the Open Community method library makes calls onto the standard UDP Multicast Internet protocol.
A little more explicitly, hereâs the typical dataflow, as seen
by a single application program:

Important points to remember:
Viewed as a time-wise flowchart, a typical Open Community application
looks like this

The most important issue in this diagram is that Open Community application programs almost inevitably have a loop containing a call to spWMUpdate. The call to spWMUpdate is where Open Community does all of it's processing, network data exchange, time synchronization, etc. It's important to call spWMUpdate regularly. Typical applications should call spWMUpdate every fifty to one hundred milliseconds, but you should be OK if you call .
spWMUpdate contains an internal timer, so that it can be used to set the update frame rate as desired. It is not necessary to synchronize update frame rates between multiple Open Community processes. Open Community will automatically buffer data so that two Open Community processes with different update frame rates will still cooperate successfully. Instead, the frame rate should be adjusted to be compatible with the local hardware.
Lastly, notice that any Callback routines that are specified are actually called at the end of spWMUpdate, so such routines must be written with that taken into account. Each object in the world model will be consistent with itself, but there is no way to assure that an object will not contain a pointer to another object that has been deleted (or, not even created yet!).
This looks like a lot of code to write, eh? Have no fear. The OPEN COMMUNITY kit contains several ready-to-use programs that implement the above interaction loop already. All you need to do is supply a user-application subroutine to initialize your application's data structures, and another routine that you want to have called every time through the interaction loop. Everything else (including rendering) will be taken care of for you.
Here's yet another way to view a Open Community application as
a set of cooperating processes:

Here, the application in cooperation with other applications creates the Open Community World Model, which is then read by the spVisual process and turned into a scene graph.. The scene graph is read by the renderer and turned into a visual image on the screen. Note that this architecture makes the Open Community library completely independent of the renderer- and also implies that the Open Community library is independent of the visual representation language used to describe how objects actually look on-screen.
Some Handy Open Community Classes
Open Community 3.0 is based on a Java description* of a set of classes that implement automagical sharing of information and updates across a multicast network, with many powerful options and capabilities to make the sharing both computationally tractable and efficient.
[* Comforting Lie: The actual definition of the objects is in a language that looks a lot like Java but isnât- it needs to be run through the SPOT preprocessor to make pure Java out of it. SPOT does a number of useful things like auto-generating accessor methods and faking multiple inheritance- things that Java doesn't do but that are needed for Open Community. ]
The toplevel object class in the Open Community hierarchy is the class named:
sp
Yes, just class sp*. All of the shared Open Community objects are descendants in one way or another of sp. Every object in class sp (or a subclass of sp) has a cosmically-unique name, an owner process, a parent object, a class object, and a number of internal fields that are used to facilitate efficient sharing of this object across the network.
[* Comforting Lie: Class sp is actually an abstract interface, not a class- you cannot make an instance of class sp.]
A very handy Open Community class is class spThing. An spThing is an object that is shared and has a location and (usually) a visual representation. The location of an spThing is represented freely as either a 4x4 homogeneous transform matrix (which is what rendering engines typically use), or as a 17-element VRML transform. Changing one of these location representations automagically changes the other for any spThing. The appearance of an spThing is held by an spLink.
Another handy Open Community class is class spLink. An spLink is an object that is shared and contains a URL pointer to a piece of arbitrarily large (disk) data. Different subclasses of class spLink can point to VRML or OpenInventor-formatted files containing visual representations, or to audio files, or to any other kind of representation. Important Feature: Open Community does not examine the URL data pointed to by the spLink; the application is free to use that as it wishes!
The class spBeacon is a class of Open Community objects that are shared and has the ability to be efficiently found, no matter where it is in the Internet, just by knowing the name of the beacon. Beyond finding your keys, this is extremely useful for entering and navigating around in the virtual world. For example, the name of an spBeacon could be advertised as the entry point to a virtual theme park, a virtual bank lobby, or a virtual workplace; the user could just type the spBeacon's name in and 'be there'. Beacons can also be used to request a service. For example, an application can be always looking for a beacon named "istp://ThisWorld/HelpMe". Whenever this beacon is created, the application will find it and provide some desired service. This method is how visual and audio positioning information is directed to the renderers.
The class spLocale is a class of Open Community objects represent a "place". In order to assure an infinite amount of space in the virtual world and allow many developers to produce their own "pieces of world" of arbitrary size for later interconnection, the Open Community cosmos is composed of a large number of spLocales organized in a self-described graph structure. Each "place" in the graph, like each "room" in a building complex, is a locale*.
[* Comforting Lie: Actually, Locales do a lot more than this- see the section on Locales later in this document.]
The class spObserver is a marker that the application uses to tell Open Community that it is interested in a particular locale. Whenever the Open Community library sees an spObserver object, it listens to the multicast address associated with that locale, and every immediately adjacent locale. Indeed, the definition of the ãcurrent set of localesä for a Open Community process is that set of locales in which the process has spObserver objects. If a process doesnât have an spObserver object in a locale or any of the immediate neighboring locales, then the process has absolutely NO knowledge of that locale or anything in it* (because the process just doesnât listen on those multicast addresses!) .
[* Comforting Lie: Except for beacons. You can see beacons in any locale- but you have to ask for the beacons by name. ]
The class spAvatar is a class of Open Community objects that nominally represents a person. An spAvatar is functionally no different from an spThing except our applications can be written with the assumption that an spAvatar will act with ãvolitionä, and may be inherently more "interesting" than the typical shrub or fire hydrant. Open Community provides a convenient way to do special things according to each class or subclass, hence the additional information of "I am probably a real person somewhere" can be used to advantage. An avatar both has a position and a visual representation, among other things.
The class spCallback is a class of Open Community objects that represent application code to be called in the event of various conditions. For instance, an application may want to have a robot perform some particular action (i.e. checking position) against all spAvatars in the area.
Overall, there are about 40 classes in Open Community 3.0 It's possible to add more relatively easily to implement new functionality in an application.
As an aside- if you've been reading the footnotes, you have noticed
that some of this sounds like multiple inheritance, which Java
doesn't do. The comforting lie here is that Open Community 3.0
includes a preprocessor for Java which implements multiple inheritance
of methods (which is all that's necessary). The base "flavors"
that implement the functionality of Open Community 3.0 are:
sp - sharing across the network
linking - to point to URL data
acting - to change another object
beaconing - to be found
observing - to look at other objects
displaying - to be sent to the renderer
positioning - to have a location
Of course, you don't need to worry about any of this unless you want to create your own additional classes.
Locales are the system Open Community uses to partition the universe and make computation, communication, and rendering computationally tractable. Every object exists in a locale, and there may be any number of locales. Since most locales cannot be seen from most other locales, the information about the objects in those unseeable locales does not need to be processed in any way. This is the primary way that Open Community achieves scaleability. Adding a locale does not increase the computational load on computers that cannot see into that locale.
A Locale has a boundary. This boundary is an object of class spBoundary. The spBoundary can be a simple axis-aligned rectangular prism (which is easy to understand and program) or it can be a complex triangulated surface of the subclass type spTerrain. SpTerrains are described below; for now consider spTerrains to be a Nifty Way to describe an irregular volume of space and just leave it at that.
Each Locale has its own coordinate system. This facilitates scaleability, because different parts of the virtual world can be designed independently, each with their own coordinate system, and then connected together as desired. Because the coordinate system is on a per-locale basis, it is even possible to have some locales in the virtual world with different coordinate axes, such as some rooms where Z = "up", and other rooms where Y = "up", and have these two coordinate systems coexist with each other in reasonable ways.
An easy way to think of Locales is by analogy to rooms and hallways
in a building. When you're in a particular room, you use the coordinate
system defined by that room. When you step through the doorway
into another room, you change coordinate systems to the coordinate
system of the new room. Consider this motion, from Room A to Room
B. Room A is a locale, and Room B is a second, different locale.

We want to move from Room A to Room B. However, Room Aâs coordinate system has a different origin than Room B's coordinate system. This means we cannot simply move from Room A to Room B. Instead, we must transform our coordinates when we move between the locales. Open Community takes care of this change of coordinates.
This change of coordinates includes not just the translation between A and B, but also a rotation and a scaling. In Open Community, the actual transformation is a 4x4 homogeneous transform.
Each locale has a list of every locale that is considered to be "adjacent" to itself (more precisely, the list contains every locale that a Open Community object can move directly to from the current locale). This list also contains the appropriate transformation to map a position in one coordinate system to a position in the other coordinate system, so that motion is smooth as objects transit from one locale to another. The list also contains the reverse transformations, so that when one looks into other locales from the current locale, objects in the distant locale also appear correctly sized and oriented.
Because the transformation defines the transform from one locale to another locale, it is possible to have non-Euclidean motion through a Open Community world. For example, it is possible to have two doorways in a four-meter square room. If you go out through one of the doorways, you would be in downtown Tokyo, and if you went out through the other portal, you would be in downtown London.
Furthermore, locales may overlap, be disjoint, be completely enclosed in one another, or may contain void areas (i.e. contain donut holes, elevator shafts, or "mystery closets" that are inside the locale in an Euclidean sense but that aren't "inside" the locale in an inside-outside sense.)
An interesting point is just how this change of coordinate space is triggered. First of all, it is not automatic. An object may move as far as desired, in any direction desired, and remain in the same locale. However, the object will only be seen by those other users who are looking in that particular locale.
If an object is to be moved between locales, there are two choices:
1) Move the object directly into the chosen locale (assuming you know what locale you want it to be in)
2) Let Open Community figure out where the object best belongs.
In the first case, you can simply set the parent of the object to the Locale desired. This moves the object into the specified locale (and thereby makes the object location relative to the coordinate origin of that Locale). The motion is instantaneous and unambiguous.
In the second case, the object has to be in a locale already for Open Community to be able to reasonably figure out where the object best belongs. To let Open Community figure out the best positioning, call the routine spThingLocalize on the object. SpThingLocalize examines the object, the locale the object is in, and an additional flag argument called PickSmallest.
If PickSmallest is False, then if the object is inside the locale (according to the Locale's boundary object), spLocalize then just returns, because the object doesn't need to change locales. This is useful if it is expected that the object will seldom change locales, because it's very fast to check.
If either PickSmallest is True or if the object is outside the locale, then spLocalize examines all of the locales that the old locale listed as being "adjacent", as well as the current locale. There are, of course, two possible results of this examination:
1) the object is not in the current locale or in an adjacent locale2) the object is in the current locale or at least one adjacent locale
In the first case, there is no locale "better" for this object than the current locale (which we were outside of), so the object stays in the current locale even though it's "outside" the nominal Boundary of the locale.
In the second case, there is at least one locale that the object is in. If the object is in more than one locale, the locales are sorted in increasing volume and the object is then moved to the smallest enclosing locale.
Visibility, Scalability, and Multicasting
If the only thing that locales provided was movement and modularity, they would be useful but they would not be as central to Open Community as they are. The greatest impact that locales have is scaleability, because they partition the world model and thus allow us to use the network switching fabric as a prefilter for all network traffic.
To minimize the computation for rendering, Open Community uses the built-in hardware of Ethernet controller cards and multicast-aware network switches. Each locale is assigned a unique multicast address. Information concerning a particular locale is multicast only on that locale's multicast address. By listening only on the multicast addresses corresponding to the current locale and locales adjacent to the current locale, the Ethernet hardware and network switch fabric itself keep the CPU from ever seeing messages that are guaranteed to never affect the rendering*.
[* Comforting Lie: this overlooks the problem that if youâre network is not multicast-capable (large portions of the Internet are not at this writing) then you canât share your Open Community cosmos with anyone not on your local piece of Internet, without resorting to IP tunneling or other black arts.]
Of course, this is a grand oversimplification. In the next section on network communications, more of the details of Open Community's communication design will be explained.
Each Open Community locale is assigned an IP multicast address*. A user program that wants to render the visual image from a particular viewpoint needs listen only to the multicast addresses that might affect the visual rendering for the viewpoint in question.
[* Comforting Lie: actually, two addresses are assigned for each locale; one address for generally-static objects such as visual things, and one address for streaming objects such as realtime audio. ]
In Open Community, there is a system-wide convention that states:
All things that can be observed from a point of view within locale L must either be in locale L, or in a locale directly adjoining locale L.
By taking maximum advantage of this convention (and good architectural design of the virtual world), Open Community 3.0 can greatly decrease the CPU and network bandwidth required to render a viewpoint. For example, the Diamond Park demonstration application uses separate locales for the outside park grounds, the inside of the outer-space building, the inside of the velodrome, the inside of the teleportation booths, and for several other transition areas.
By only listening for network messages in adjacent locales, the IP network protocol overhead, world model memory size, and rendering overhead are greatly decreased.. Humanistically, it also "feels right". As an example, consider the case of a large convention hall. Clearly, there must be bathrooms co-located in such a facility. However, in a well-designed facility the bathrooms do not directly open out onto the main convention hall floor. Instead, there is a small anteroom or access hallway, to allow the mind of a visitor to accept the change in the surroundings easily. By accepting this human need for smooth change in surroundings, Open Community allows us to use a very simplistic rule such as "current locale plus adjacent locales" to limit the amount of information the rendering computer must process.
Here's a flattened-to-2D-example- with the following Venn diagram
loosely based on a popular board game:

Here, we have five Locales (Atrium, Bedroom, Conservatory, Den, and Eastwing). The different rooms (er, locales) overlap. For the sake of discussion, assume that our Locales are on each otherâs adjacency list if they overlap in the above Venn diagram.
Now, if I am in the Bedroom, (i.e. my application has an spObserver object in the bedroom locale) then I would see everyone in the Atrium, everyone in the Bedroom, everyone in the Conservatory, and everyone in Eastwing (areas A, C, D, E, F, G, H, I, J, and K. ) The only area I would NOT see is area B. This is a lot of objects and a lot of network traffic. Of course, this can be improved
If we "improved" the above game to be more similar to the real
board game (by adding a hall and vestibule/doorways, each of which
is it's own locale), and continuing the assumption that if two
locales are on each other's adjacency lists then we draw them
as overlapping) we might get the following Venn diagram:

Now, we need monitor and render only a few areas for any user in a peripheral room. For example, someone in Eastwing need only monitor two multicast addresses and render only those objects in areas L, P, R, and T.
For locales to be truly effective in reducing CPU requirements and rendering time, the architecture of the virtual world must be planned to gracefully include anterooms, joining corridors, approach ramps, passages, or elevators such that complex locales do not directly adjoin, but are separated by small, computationally simple locales. In this way each renderer is only required to render one complex locale (tens to hundreds of thousands of polygons) plus a small number of very simple locales (each with a few dozen polygons), rather than a large number of complex locales.
Network Communications and Initializations
Here's a more complete and accurate picture of Open Community
(operating over a local area network) in operation: Have no fear-
Open Community takes care of most of this automatically; you never
need to worry about it.

When a Open Community session is started, the first thing that starts is the Session Server. The session server is in charge of controlling certain "scarce" resources. These scarce resources are things like multicast address allocation, etc. In general, the session server is only accessed when one of these scarce resources is needed. The Session Server is never accessed by typical user applications.
Various Open Community programs may then be launched. Some of these programs may be programs like Beacon Servers, which are used as central resources of arbitrary beacon knowledge, much as web servers are used in the current world-wide web. Other servers such as Locale Servers may be launched to provide initialization services for users entering a particular locale. Restricted Bandwidth servers provide advanced filtering for users not connected to the part of the Internet that directly supports multicast and high-speed data.
In our example, the first program launched is the Session Server S. S is in charge of allocating multicast addresses to locales on an as-needed basis. Note that you need at most one Session Server per multicast area of your network; you can have more than one Session Server by dividing the multicast address space up. Also note that the Session Server is only queried when a new locale is being created, and then only to get a multicast address (it is possible for multiple session servers to be started independently but enter into a cooperative configuration, but that's beyond the scope of this document It's also possible to "pre-allocate" multicast addresses and so not need any session server anywhere.).
After Session Server S is up and running, an information provider decides to host a new locale in the session. The information provider creates a locale L. This causes the session server to be asked for a multicast address for L. Then, the information provider starts the Locale Server L.. L's purpose is to keep an inventory of all Open Community objects created in locale L so that as users enter L, they can get a rapid download of all interesting objects in L directly from the locale server L via TCP, rather than having to ask each process with objects in L to describe those objects.
The information provider then must populate the world; one of the things that is very useful is to have "beacon service" in the populated world. The beacons are URL-like objects that can be found by anyone with access to the multicast space. Therefore, the information provider starts the Beacon Server Q. The tag of some beacons that will be created later will contain a URL that contains the Internet name of the beacon server, e.g. istp://visitme.Open Community.com/starthere . The beacon server catches these Internet-wide requests for beacon service and returns the information on the beacon, including what locale the beacon is in and what the multicast address for that locale is.
Now, one point of convention: Although it is possible to use any
locale, beacon and suchlike servers anywhere on the accessible
Internet....
It Is Recommended that each content provider should also provide their own Locale and Beacon servers for all locales and beacons that they serve to the Internet.
This is both a matter of courtesy as well as a matter of good architecture. If the locale and beacon servers are "piggybacked" onto another information provider's system, it might be construed as "theft of services", much as the current brouhaha over bouncing mailspam through innocent mail servers is currently perceived. Secondarily, by keeping the Locale and Beacon service "in-house", a measure of control can be maintained over access to the virtual worlds.
Up until this point, the locale L is empty; a visitor entering
it would see nothing. Now the information provider starts the
"decorator" process I. The decorator's task is to initially create
and then own all of the objects that a visitor should see when
they enter locale L. For example, if we wanted to give the look
of an auditorium, then process I would create a stage, stage lights,
a podium, and row upon row of seats. In addition, the "decorator"
must create a beacon so that visitors can actually find the locale
L from the Internet. In our example, the beacon is istp://visitme.Open
Community.com/starthere, so initial decorator I creates a beacon
by that name and places it into locale L. The Open Community library
automagically makes sure that the beacon server Q (which in our
example just happens to be the Internet host visitme.Open Community.com
) gets full information on the locale of istp://visitme.Open Community.com/starthere,
including the multicast address of the locale the beacon resides
in, in this case locale L.
In many applications, process I would then continue to own the scenery and would run for as long as it was desired to maintain the "look" of locale L. In other applications, the information provider would start a persistence server P, and then I would turn ownership of the scenery over to P, which would then take over ownership of the scenery. The initial decorator I could then be free to animate various additional "inhabitants" of locale L, while letting P do authentication and control for allowing visitors to anin ownership and alter the scenery of the locale L.
All through this process, Locale server L has silently monitored the creation of objects in the locale. It merely inventories them; it takes no further action untilÉ [drum roll please]
Real User A logs in, and tries to visit istp://visitme.Open Community.com/starthere . Process A opens a connection to visitme.Open Community.com, and asks for the beacon information on beacon "starthere". Beacon server Q then replies with the multicast address for the locale L.
Process A then joins the multicast address and asks "Is there anyone here who can give me an update on what's in this locale?" Locale server L responds and downloads the current contents of locale L into user process A.
At this point, user process A is now fully up to date on the contents of locale L and so it can operate as one would expect.
User B and process B join similarly; the only difference is that process A will see the creation of process B's objects directly on the locales's multicast channel rather than being told about it indirectly from the locale server L.
Now all is well and good- but users C and D want to join the fun. Since they aren't on a fast connection, the information provider or their ISP must launch a Restricted Bandwidth Server R to prefilter information, to pre-render what can be pre-rendered, and to pass along what must be passed. Processes C and D then connect to the restricted-bandwidth server R directly and let R act as their proxy onto the Internet.
B has now created some objects and wants to log out and go home. If B just exits, then objects owned by process B will be deleted from the world model eventually. However, B wants to have these objects remain in the world model. Therefore, B transfers ownership of the objects to the persistence server P. Once the ownership is transferred, then B can exit the session and the objects will remain.
Lastly, say A wants to alter the way the local scenery looks. So, A requests ownership transfer of that part of the scenery from persistent object server P . If P authorizes A to make changes, P transfers ownership of those scene objects to A. A can then alter the scenery objects as appropriate and then return ownership of the objects to P. The changes made by A are now durable until the persistence server is terminated.
Of course, the persistence server P could also write out a disk-based version of objects that it was maintaining on a regular basis. Then, if P had to be terminated and restarted, the disk file could be used to regenerate the original set of objects.
Open Community Visual Rendering
The usual use for Open Community is to create a 3-D multi-user virtual world. Although Open Community's goal is to make the sharing of world-model information easy, Open Community also provides a renderer to create quality* visual renderings.
[* Comforting Lie: the visual renderers included with Open Community may or may not meet your needs. Please check carefully into this. ]
The standard visual renderer uses the Open Community API to examine each object in the current locale and in every locale adjacent to the current locale. If the object has a graphical model URL associated with it, Open Community fetches the URL caches the model, and uses the position information in the data object to properly place and render the graphical model into the world view.
This, of course, begs the question of just what the point of view
for the rendering is. Open Community has a particular kind of
geometric object that does not render directly, but instead specifies
a camera viewpoint. This object class is called an spVisualObserver.

These spVisualObserver objects exist in the shared world model, and although they donât have a graphical model associated with them, they still have attributes such as position, subobject parenting, etc. This is quite useful, because the POV of a user can be attached as a subobject to the forehead of the userâs avatar. As the avatar moves in the virtual world, the POV object moves with the avatar and the renderer continues to use the POV's coordinates to render the world. This procedure results in a first-person view of the virtual world.
Now, you might ask, "What good is an spVisualObserver? Why can't
I just render the view from the coordinates of the avatar?" The
answer is most easily expressed as another question:
"What makes you think that the process doing the visual rendering knows which avatar is yours?"
The visual renderer process might not know which avatar is yours because there might be many avatars all being controlled by one "user program" or there might be multiple processes running on a particular machine, all cooperating to appear as a single "application" but each with its own private agenda.
By splitting up the concept of "Avatar- that which others see us as" and "VisualObserver- that from which we see the world" we can easily coordinate the multiple processes of an application. By the way- it's quite possible to have the visual renderer running on a different machine than the "user application" is running. We've done this in some show demos, to get the absolute best performance out of whatever hardware was available.
Attaching the spVisualObserver to a point several meters behind and above the avatar gives a third-person, over-the-shoulder-camera effect, with the camera dollying behind the avatar. "Smart Camera Agents" can shift the camera viewpoint like a good cinematographer, to show off the best parts of the world while retaining the "I am here" illusion. Finally, POVs can be moved about entirely separately, which gives a "birds-eye-view" flying view of the virtual world.
The sample visual renderer supplied with Open Community is by no means the only visual renderer that can be used. Any renderer that can read the data format stored in the geometry model URLs of a particular world will work. For some applications it will be worthwhile to write the small amount of code necessary to use an aftermarket renderer.
It is also possible to write a renderer that renders not in the classical "3-D textured polygon" sense but in some other sense. For example, a renderer might gather statistics on where in the virtual world people tended to congregate over time. Since the entire world model can be seen by a renderer viewing the proper set of locales, any sort of session-wide information can be generated, including a session-wide "paging service" or 'View from the Goodyear Blimp'.
The actual mechanism of attaching the renderer's POV to something
controlled by an Avatar goes roughly like this:
Open Community Audio Rendering
As you move around in a typical Open Community session, you will notice that you can both see and hear what is happening near you. Visual objects are 3D models and typically last for minutes to years, but audio is much more dynamic (or so it would seem at first glance) a sound happens, then the sound is gone.
Like visual POV's, Open Community audio POVs exist; the audio is "rendered" according to the location of the spHearing beacon object created by the user avatar application, and the companion spAudioObserver object, created by the audio renderer and attached to the same parent as the spHearing beacon.
Audio in Open Community comes from three distinct sources:
Ambient sounds are "part of the scenery". For example, the birds chirping in the trees in Diamond Park are ambient sounds. They are created in the same way as the terrain and buildings are created; by placing an object at a particular XYZ location, and providing a URL which contains a 16 KHz digitized audio clip. The audio renderer process fetches the URL and mixes the audio clip appropriately. Ambient sounds are long-lived sounds. Each ambient sound clip loops automatically, so a single ambient sound object creates a sound that continues for as long as the object exists.
Foley sounds are "sound effects". The sound of a door opening or a vehicle shifting gears are foley sounds. They are created like the continuously looping sounds, by making a database object pointing to a URL, but they do not play continuously. Instead, they are single-shot sounds, triggered as desired by a Open Community program.
Real-time sounds are produced by people or things in a Open Community session that choose to make noises. These noises are digitized much more slowly (typically at 8 kHz or so), and sent via multicast to everyone listening on the particular multicast channel corresponding to the noisy object's locale. At the receive end, the real-time sound packets are appropriately mixed, which produces the illusion of full stereo sound.
The mixing of multiple looping, foley, and real-time sounds is done "on the fly", and "in place". As various sounds are encountered during audio rendering's scan of the world model, the sound samples are mixed "in place" into a sample buffer (this may require altering the sample rate for various sample types). The mix-in-place also does fading (for distance) and panning (to locate the stereo image) for ambient sounds, foley sounds, and real-time sounds. The resulting audio buffer is then sent to the D/A sound system for rendering.
Object Motion in Open Community
In the Open Community multi-user system, objects can be moved only by their owners. Usually, the owner of the object is the creator of the object, but object ownership can be transferred. (Ownership transfer is covered later in this document.)
An object can be moved in different ways.
Open Community API allows a user program to directly set the transformation of any Open Community object, which allows instantaneous motion as a useful side effect. When the transformation is changed, the object (accompanied by all it's subobjects) moves instantaneously to the new position and orientation. The object "jumps" to the new location as soon as the world model is updated.
To implement smooth motion, the Open Community API allows the user program to create an Actor object. This actor object has the power to directly alter the position and orientation of its parent object (which is the object we originally wanted to move). Open Community automatically triggers the Actor object to update the parent object's position at every display refresh time. This has the side effect that a user program can't just remember the location of an object being moved by an Actor, because the object's location will be changed by the Actor.
The Actor object usually does not move the object instantaneously (although it can come very close to doing so). Instead, the Actor object is controlled by supplying the Actor with a set of positions, orientations, and times that it is desired to have the Actor's parent occupy. These positions, orientations, and times can be either generated on the fly by the user's application, or they can be read from a data file. Once the Actor is supplied with these positions, the Actor will take care of all the details of making the object move smoothly through all of the supplied positions, orientations, and times.
The Actor object changes the coordinates of the object with respect to its parent object. In this way, one achieves the expected results even if the object being moved by the Actor is a subobject of another object which is also being moved by a second Actor.

Another benefit of actors is that frame rate heterodyning is prevented- this causes jumpy motion in distributed VR systems that use repeated instantaneous motion across multiple systems. If the motion desired is ãpredictableä, then a smooth motion actor can also do data rate compression. Actors have the capability of providing smooth motion if enough sample points of position and orientation are supplied. The Actor implementation will drop back to simple linear interpolation if the positioning data rate is insufficient for more powerful smoothing algorithms. If the positioning data rate becomes less than real-time, the Actor implementation will perform extrapolation in the motion. This extrapolation includes a rough approximation of Newtonian physics, so objects continue to move as though they were rigid bodies floating freely in a zero-gravity vacuum with translational and rotational velocities equal to that of a linear interpolation between their last two positional datapoints.
Objects being moved smoothly in Open Community can be told to follow "paths". A path is a linked list of spPath objects, which are time/position coordinate sets. SpPaths can be read and written to files, for easy long-term storage.
For details on spPaths, see the Open Community API document.
In Open Community, each object in the shared world model must have an owning process. Objects without an owner are removed "with extreme prejudice".
However, at times there is a need to transfer ownership of an object from one process to another. For example, if I create an object and then want the object to remain in the universe even though I've logged out and gone home, I need to transfer ownership of the object to a process that will stay around and continue to own the object.
To request an object ownership transfer, an application calls spRequestOwnershipTransfer (???). The owner of the object then will get a callback indicating who wants ownership of the object. If the owner process decides to allow the transfer, it calls spTransferOwnership (???) and ownership transfers on the next call to spWorldModelUpdate.
To transfer ownership of an object unilaterally,. Just call spTransferOwnership and the object ownership will be transferred. You must be the current owner of this object to transfer it, however. Nonowners can only request to be given ownership, at which point they may can unilaterally transfer the object to a third party.
Note that there is no "second handshake" on ownership transfer; there is no way for the recipient to refuse an object being offered for transfer. However, it is possible to set up a callback such that newly transferred objects are subjected to a checking procedure and any not desired are simply deleted immediately.
Terrains and Terrain Following
Terrains provide a way to describe a complex surface or volume in such a way that it can be treated as a floor, lawn, or ceiling. Open Community provides a set of operators to efficiently do terrain following. These terrains are expressed as a number of triangles. Each triangle can carry a tag that says that the particular triangle is to be treated as "floor", or as "ceiling" or as "to be ignored for the moment". Floor triangles have a nonzero positive tag, ceiling triangles have a nonzero negative tag, and triangles with a zero tag are ignored.
Once the terrain has been read in, the application can use spTerrainBelow to "follow the floor" as an avatar walks around undulating surfaces, ramps, etc. SpTerrainAbove can be used to provide the maximum height that a camera can view the important action without "punching through" the ceiling.
Beyond this positive/negative/zero distinction, an application is free to use the tag value in any way it desires, such as for doing "warp zones", triggering advanced preload of URLs that will be needed soon, etc.
SpTerrainInside is used by spLocalize to determine whether a given point is inside or outside a locale [a point is considered to be "inside" only if there is both a floor directly below the point in question (in the -Y direction), AND a ceiling directly above the point in question, above being the +Y direction*. If either direction contains no terrain triangles or the first triangle encountered is of the ãwrong typeä - e.g. ceiling in the floor, floor in the ceiling, then the given point is determined to be "outside" the locale.
[* Comforting Lie: this is the one place in Open Community where the coordinate system and handedness are somewhat hardwired. In order to get the extremely high speed for terrain following, the directions of ãUpä and ãdownä are fixed. If you need other directions, you must pre-rotate the terrain file yourself. ]
Terrain following operations in Open Community 3.0 are highly optimized; depending on cache coherency and cache-line contention the CPU time required on a P-180 to do a single terrain-following operation may be anywhere from 30 microseconds down to 5 microseconds per point. Because of the L1 cache effects, if you have more than one point to terrain-follow at once (i.e. for shadowcasting) then it is highly advised to do them en masse; you may well achieve terrain following in under 4 microseconds per point in such situations.
A Open Community terrain file is in the following format:
VOLUME=nnnn
npoints
x1 y1 z1
x2 y2 z2
...
ntriangles
p1 p2 p3 t1
p4 p5 p6 t2
...
The first line tells Open Community how big the Terrain is claimed to be; this is used in spLocalize to choose the "smallest" locale. Open Community does NOT do an actual volumetric calculation of the terrain volume; no problems will ensue if you use "volume" as a prioritization method.
The second line tells how many individual points are in the terrain. Successive lines after that describe the points in XYZ space.
The next line says how many triangles there are in the terrain. The next lines define triangles in the terrain by their corner vertices, plus the associated tag number. If there is no tag number given, the default is +1.
Here's a simple Terrain - a bump on a triangulated plane (all
with tag +1), with a simple two-triangle ceiling, with the two
ceiling triangles tagged -1. We don't show the actual tag values
here- it would make the diagram too crowded. Also note- we have
drawn the triangles with gaps to make it clear how they were arranged.
In a real terrain, there are no gaps between triangles sharing
the same vertices and edges.

The area inside the dotted lines is the ãinsideä of the terrain - that is, where spTerrainAbove finds a valid ceiling, and spTerrainBelow finds a valid floor. Thus, point P is inside the terrain, while points Q and R are "outside" the terrain.
In Open Community, it's possible to set up an application method or function to be automatically called by the Open Community library during spWMUpdate. This is called a callback.
For each callback, the programmer specifies two function pointers, one for a predicate function to be evaluated and one for an action function to be executed whenever the predicate function returns TRUE. The actual mechanism is that all predicates are evaluated first and the results stored; then and only then are the action functions called for the corresponding predicates that returned TRUE. The justification for this two-pass paradigm is that each predicate can see the data undamaged by the action functions of other callbacks and thereby prevent cascade effects within a single invocation of spWMUpdate. The downside of this is that you can't have cascade effects within a single invocation of spWMUpdate; you get one step of the cascade per invocation and that's it. To make this work, predicate functions are required to be "stateless functions" and not change any data, in either the World Model or the application*.
[* Comforting lie: yes, this is stateless- but thereâs no way for Open Community to actually know if you cheat. But if you cheat, you might break the cascade prevention and be very sorry afterwards. ]
Safety tip: Callbacks are not executed in any particular sequence- donât write your application to depend on a serendipitous ordering of callbacks in a particular release of Open Community.
Callbacks can be triggered on a number of different circumstances:
For more details on how to create and use spCallbacks, see the Open Community API documentation set.
Open Community Extensibility via Java
Open Community can be extended to allow real-time sharing of new kinds of objects (e.g. new user-defined classes). These new classes are derived from the base Open Community classes, and are defined in a Java-esque language, which is automatically translated into both ANSI C and genuine Java. The new C file can be compiled and linked into the native ANSI C Open Community library, and the Java file byte-code compiled and downloaded into a running Java. The new classes are then available for applications to use.
Although this may seem to imply that Open Community is written in Java or requires Java, that is emphatically not the case. It is quite simple to write, compile, link, and run an ANSI C Open Community application that contains no Java whatsoever. It is also quite simple to write, byte-compile, load, and run a Open Community application purely in Java, with no C coding whatsoever. The only differences between the two applications are that the pure Java application will not use any native methods other than the ones supplied in Open Community directly, and the pure C application will not be able to extend the object class structure at runtime (it can extend it at compile time, by creating new classes in the Java-esque object definition language).
Because the class methods (like creation, deletion, data member access, etc.) are automatically generated from the object definition language, the ANSI C and the Java APIs contain exactly the same functionality. Their calling sequences may be slightly different, but they will perform precisely the same action (in part because they are both interfaces to the same underlying native Open Community function)
For example:
Java:
myobject.PerformSomeAction ( action, how_long_to_take);
and
ANSI C:
spPerformSomeAction ( myobject, action, how_long_to_take);
actually execute precisely the same routine inside Open Community.
In this way, Open Community addresses both the needs of the Java community and the needs of the ANSI C community, without favoring either and without causing version skew between APIs*.
[* Comforting Lie: This is only true for the versions of Open Community that add native methods to Java. The 100% Pure Java (TM Sunsoft Inc.) version of Open Community is inherently implemented in Java, and hence may not be bug-for-bug equivalent to the native-method implementation.]
Return to Open Community main page