Welcome to the 3D Worldby Pierre Raynaud-Richard
The 3D Problem
3D is an amazingly hard problem. We can easily identify the reasons:
For these reasons, 3D is mostly used for creating games, synthesizing pictures or frames of animation, and in expensive CAD programs. The needs of each of these three application domains are significantly different:
To provide a solution to the problem, most of the available 3D libraries (OpenGL, Renderman, QuickDraw 3D) are huge and complex. Consequently, the users of these products need to have a non-trivial level of 3D knowledge.
Choosing a 3D Solution for Be
At the latest MacHack event in Ann Arbor, an anonymous hacker, discovering the BeBox for the first time, complained that it would take six months to learn the API for a new machine. But after playing with the Box for just a few hours, he had windows, views, dialogs--he'd built a real application. His comment: "My god, it's so simple." He got the point.
Efficiency and Simplicity
The two main goals of the BeOS have always been--will always be--efficiency and simplicity. But is it possible to present a 3D solution that's both general and simple? Frankly, no. So, if we can't have general simplicity, we'll choose "specific" simplicity: The 3D Kit, our "from scratch" 3D API, is simple and efficient, but it won't satisfy the farthest-out of the 3D innovators and synthesizers. Of course, we don't want to abandon the experts; for them, we've chosen to support the most common 3D standard, OpenGL.
OpenGL
The implementation of OpenGL that we will initially support is based on the latest version provided by Silicon Graphics Inc. The implementation will include the standard tool kit. Our port of OpenGL is just beginning, so it won't be available in DR8. Until we get further into development, we won't know exactly what we'll do to fine-tune the implementation. But we can tell you what our priorities are (in roughly this order):
In addition, we'll look at what it will take to merge OpenGL and the 3D Kit.
The 3D Kit
The main goal of the 3D Kit is to make 3D accessible to all programmers, particularly those that have never used 3D before. That gives us three main problems to solve:
Solving these problems asks for much more that just a 3D rendering engine. Sticking with the BeOS philosophy of efficiency and simplicity, we've chosen to provide "medium-end" native rendering that the programmer can efficiently enliven and that the user can easily manipulate, rather than a "high-end" engine that's difficult and sluggish.
3D Kit Classes
The 3D Kit is written in C++, and is highly modular and expandable. Looked at generally, the classes in the 3D Kit fall into four categories:
Be aware that the divisions between these categories isn't exact: For example, a B3dCamera, in addition to being part of the rendering engine, is a "thing" in that it can be placed somewhere in a 3D world. In the following sections, we'll look at the design of these groups of classes. We start with the "thing" classes (because they're the most interesting), and then describe the milieu classes, rendering engine, and, finally, the interface classes.
Things
The things that you place in a 3D world inherit, perhaps at some distance, from the B3dThing class. The main properties of a B3dThing are its location, orientation, and area:
B3dBarrier and 3dBody objects are typical B3dThings as they describe "voluminous" physical objects that are placed at a location and orientation within a 3dWorld. But the B3dThing class isn't limited to only describing physical objects. Other subclasses include B3dLight (the geometrical and optical description of a light source) and B3dCamera. Instances of these classes don't have a volume, and so don't need the steric description, but they do have locations and orientations. Another interesting and useful subclass is 3dFakeBody. A fake body is visible artifact that doesn't actually live in the 3D world. For example, you can use a fake body to float a label near some other "real" body. You can also use a fake body to impose a special effect, such as blurring. Typically, fake bodies are much simpler than real bodies; they usually don't have a complex geometric architecture and very often don't respect the "zoom" property (they can remain the same size even when moving away from the camera). It's easy to imagine other "non-material" things. For example, you could use the B3dThing architecture to describe the location and orientation of a sound source, or you could use a B3dThing to move a "black hole" around a room, and so on.
Body Architecture
The three main properties of a B3dBody are its geometrical description (encapsulated in the B3dModel class), its appearance (the B3dLook class), and the way its parts are connected to each other and to other objects (the B3dLink class). Other properties can be added to a B3dBody, but these three will be specially optimized. The two types of real objects, B3dBodies and B3dBarriers, are based on the same architecture. The B3dBarrier class is actually a simplified version of B3dBody, so we concentrate, here, on the latter. Consider a simple, real-world body such as a red ball. In the 3D Kit, this description of a B3dBody would be broken into a B3dModel and B3dLook. The B3dModel would represent the shape of the ball (a sphere), and the B3dLook would represent its color (red). The tasks that these objects perform are similarly divided:
Assembling Models
Smaller models (B3dModel objects) can be put together in a hierarchical structure (an "n-ary" tree) to create more complex models. For example, let's say you're modelling a human arm; first you would model the basic elements: arm segment ("branch"), palm, and finger segment ("phalanx"). From these parts you would link three phalanxes (one with a finger nail attached) to create a finger. Create four more fingers (each defined to be a different size), link them to a palm, and you've got a complete hand. You then link the hand to a lower branch, and the lower branch to an upper branch, to create a complete arm:
The connection between models (or model parts) is called a "link". For example, the internal description of a finger, with the links exposed, looks like this:
A link is encapsulated as a B3dLink object. A B3dLink expresses some geometrical relationship between the linked models; for example, the link between a MiddlePhalanx and an UpperPhalanx would express the attributes of the "hinge" that connects the two models. Notice that even though the ForePhalanx is linked to the MiddlePhalanx, the two are described at the same hierarchical level. You can navigate the structure of a complex model through the hierarchy. For example, the path that leads from the Arm to the ForePhalanx on the second finger would look like this:
Arm/Hand/Finger2/ForePhalanx
The 3D Kit lets you build hierarchical models dynamically: Each instance of B3dModel (or, more accurately, each instance of one of the "modelling technique" subclasses) can be manipulated to describe a distinct portion of a complex model.
Level of Detail
The B3dBody class incorporates "Level Of Detail" (LOD) management. By the tenets of LOD, you can "tie" a detailed body to a simplified version of the same object. The choice of simple or "full blown" rendering is determined by the object's "apparent size" as compared to the object's "LOD threshold": When the apparent size falls below the LOD threshold, the simple version is used. LOD management, as applied by the 3D Kit, is recursive: A simplified 3dBody can have its own simplified version, and so on. Both the complex and the simple versions of a body can be as simple as a static description (a list of pre-defined faces), or as complex as a C++ object will allow you to describe. To accommodate the most common body types, every B3dBody (through association with a B3dModel) contains a list of points, a list of vectors, and list of "normalized vectors" (or "norms"--a norm is a vector that defines the orientation of a plane). This assumption allows significant optimization and simplification for models whose description can be based on standard elements; this includes all face-based models, and most of the standard geometrical shapes and 3D curves. (The small overhead of including the lists for bodies that don't use them is insignificant.) The LOD management can be used at any level of the hierarchy. For example, you can have a simplified version of a hand (a single object) that has the approximate form and size of the palm+fingers model. The simple hand would be used when the overall size of the entire arm becomes too small (because of zooming, typically) to sensibly render the full hand. In the case of such a LOD substitution, the rendered arm model becomes:
Zoom out some more and the arm can even become:
Shifting to a simplified version doesn't cause the model to "lose precision." For example, as you zoom in on the simplified arm, the model's complex depiction is restored.
Links
The B3dLink class does more than simply connect two parts of a model: It also describes how the parts are connected. This is an important feature that extends the utility of the B3dLink class beyond model building. You can link any two models together, even if they aren't part of the same body. By creating links between "arbitrary" objects, you can define the relationships between objects. For example: Let's say you want to create a 3D scene that depicts planetary motion. You wouldn't want the moon to be part of the Earth's model--but the two are obviously related. So you create a 3dMoon model and a 3dEarth model and link them; the B3dLink would describe the distance between the two objects, and the rate at which the moon rotates around the Earth. The expression of the relationship is unlimited--you have an entire C++ object to encapsulate the expression. You can even use a B3dLink to connect a body (or, more generally, a thing) to some point or combination of points in the world. For example, through the use of a B3dLink you could tell your moon to rotate around some static point (expressed as hard-coded coordinates), or you could tell it to rotate around the point that lies midway between the Earth and Mars (or at the center of the Earth, Mars, and Venus, and so on). To control the timing of your moon's rotation (or, more generally, any "evolutionary" relationship expressed in a B3dLink), the B3dWorld class provides an internal clock. Because the clock is common to the world, all links within that world can by synchronized.
Worlds and the Universe
The B3dWorld architecture is based on two simple assumptions:
The advantages of such an architecture are numerous:
The main disadvantage of the architecture is that you have to choose a world and stick with it. Unfortunately, the world you imagine may be more complex than can be described in a single B3dWorld object. For example, what world do you choose if you want to place a little house (a closed world) on the prairie (a ground world)? Fortunately, while you can't change the nature of a world after it's been created (you can't convert a B3dClosedWorld to a B3dGroundWorld, for example), you can create more than one of them. Because the world isn't the biggest thing in the... world. The universe is.
The Universe
The B3dUniverse class provides, primarily, the ability to have co-existing B3dWorld objects. For example, you could build a house by defining a different B3dClosedWorld for each room. You could even set the multi-world house onto a B3dGroundWorld. But, you may wonder, "What's the point? Why not just define a single 3dGroundWorld and construct the house out of B3dBarrier objects? Wouldn't that create a more unified model?" Maybe. But creating a B3dUniverse that's composed of different interconnected B3dWorlds presents many serious advantages. Returning to our house, it's much easier to re-design the house by moving (and possibly scaling) the world/rooms around, than to reconstruct the B3dBarriers. Also, modular worlds are much easier to re-use in different parts of an application than are structural definitions of a space. But most important, worlds are connected by B3dDoor objects. And the B3dDoor class is extremely clever.
Doors
All the advantages of the B3dWorld architecture disappear if there's no way to connect the different B3dWorld instances. The key to connecting one world to another is the B3dDoor. A B3dDoor is an object that has a geometry (it's a planar section closed by a polygonal shape, typically a single triangular or rectangular face), but it doesn't do any drawing--B3dDoor objects aren't visible. If you want to see your door, you have to create a B3dThing that will graphically represent it. The geometry of the door is used to define the interface between two worlds. For example, let's say you want to put a connecting door between two rooms, where the two rooms are defined as separate B3dClosedWorld object. In the first room you define and "hang" a rectangular 1x2 door (a B3dDoor object). In addition to the door's size, you give it an orientation. In the other room, you create another B3dDoor object that has the same proportions as the first, but with the "opposite" orientation. You connect the two B3dDoor objects and--voila--a B3dBody can automatically pass between the two worlds by walking through the door that connects the two rooms. One of the more fanciful aspects of the B3dDoor class is that you connect any door to any other (similarly-proportioned) door, even if the connection doesn't make (real-world) sense. Imagine a meadow (B3dGroundWorld), that has a brick wall (a B3dBarrier) running through it, and a door (a B3dDoor with a B3dBody attached to it so it's visible) in the middle of the wall. The door opens, and through it you see and enter into a room (a B3dClosedWorld). But if you leave the room and hop over the brick wall, you only see the back of the wall--there's no room there (nor room for a room). The two worlds seem to take up the same "real-world" space. Used in this manner, a B3dDoor looks like science-fiction teleporter, as it can move an object instantly from one world to another. In any other aspect, the B3dDoor is just a transparent interface for almost any information. For example, it can take the light that hits it from one world and spill it into the world of its "partner" door. A B3dDoor can also have filtering properties. For example, you can create a B3dDoor that represents a transparent glass window. The window connects the room of a house to the outside. Light that passes from the outside into the room can be filtered by the properties of the window's glass (or window shade, etc.); you can even define the window to reflect the outdoor scene if the light outside is greater than the light inside, and so on. Another feature of the B3dDoor class is that it clips the objects that pass through it. Every B3dBody going through a B3dDoor is clipped so that a world only processes the part of the body that lies on that world's side of the door.
Rendering a Scene
At the rendering level the 3D Kit is (mostly) independent of the OS and the hardware, such that a port to another OS or platform should be easy. Nonetheless, we've given a high priority to the integration of the 3D Kit into the BeOS environment, so that you can, for instance, easily create a 3d-capable view that's rendered into an otherwise "normal" window. The B3dWorld class provides the highest-level of rendering control. The world has to "sort" its (visible) things: It has to determine whether and how the objects overlap or intersect. On the basis of this determination, the world then decides if it needs to use the "z buffer" (or "depth buffer"). In general, if objects overlap, then the z buffer is needed. This is an important decision because z buffering takes a pretty large amount of computation if it's done in software--3D graphics cards provide a z buffer that makes z buffering much faster. In any case, the scene that's ultimately rendered should look the same regardless of whether or not the z buffer was used. A note regarding z buffering: It's tempting to think that 3D cards will make the fuss over "to z or not to z" moot. However, there's also precision to think about: A hardware z buffer isn't as flexible as software. In some cases, such as rendering interconnected objects that start far away and then move toward the camera, the results can look better when the rendering is done by software (because hardware rendering could introduce rounding error).
The Rendering Engine
The foreman of the rendering engine is the B3dCamera. When it's time to render all or part of a B3dWorld, the camera starts things going by telling the world that it needs to render itself. The world accedes by asking all the renderable things that are in the camera's view (all the B3dBody, B3dFakeBody, and B3dBarrier objects) to render themselves. At this level, rendering is handled by the B3dLook objects that are associated with the various bodies and barriers (one look per body/barrier, as described earlier). The B3dLook class describes the rendering for its body (or barrier) by applying a "lens" to its body's model. A lens (a B3dLens object) provides a formula for calculating the projection of three-dimensional geometry onto a two-dimensional plane; every camera has one lens (this is the B3dLens object that the B3dLook consults). The most natural lens describes a "radial" perspective: All straight lines appear straight, and lines that are parallel in the z plane converge at a single vanishing point. Other possible lenses include "fish-eye" (in which straight lines appear bowed), or "flat" (lines are straight, but there's no vanishing point). The lens also clips its projection onto a rectangular frame, and provides interpolation for objects that spill out of the clipping region. The B3dLook class also calls on the B3dLighter class. A B3dLighter is the "lighting engine" for the collection of B3dLight's that illuminate the view that's scene by a B3dCamera: It's responsible for calculating the amount and color of the light that hits any particular point in the world as viewed from a particular angle. The B3dLens and the B3dLighter classes can both perform body-by-body optimization as they send their computation back to the B3dLook. (This optimization is provided by the 3dLensImage and 3dLighterProc classes.) For example, the 3dLighter can decide to ignore faint light, or use simplified models for barely illuminated bodies. At the lowest-level of rendering is the B3dRenderer class. This class provides basic rendering functions (for now, it can only do triangular drawing). It's at the B3dRenderer level that the implementation can more easily start to spill over to hardware.
Rendering and OpenGL
The rendering engine is intentionally modular such that it would be possible to use the 3D Kit to architect a scene, but then use OpenGL (for example) to render it. To do this, we would provide a hook out of the Kit somewhere in the rendering engine (probably in the B3dLook class) such that OpenGL could process the lighting, geometry, and rendering. Perhaps we'll provide this feature in the future--but, honestly, it doesn't look like a practically useful solution. Why? Because the developers who really need OpenGL probably won't be satisfied with the simplicity of the 3D Kit--more to the point, they probably already have an OpenGL front-end. At the other end, folks who haven't had much 3D experience, or programmers that are using the 3D Kit simply to create a couple of quick three-dimensional interface controls will probably prefer to use the Kit's rendering engine rather than drag in another huge library.
The Interface Classes
The 3D Kit provides four main interface classes, B3dOffscreen, B3dScreen, B3dView, and B3dControl. The first two of these are low-level "image buffer" classes; you would use them if you really want to fine-tune or customize the rendering mechanism:
Both the B3dOffscreen and the B3dScreen are rendered directly in the display buffer they describe, so you're responsible for providing your own multi-buffer management (such management will come for free with the Game Kit). The other two classes are useful to all programmers
The interface classes also support advanced interaction. For example, in addition to the ability to select, move, and turn objects, the user will also be able to move, turn, and zoom the camera. This interaction will be provided through an optional, modular, and extensible API. The design goals of the interface classes are these:
Of all the parts of the 3D Kit, we think that the interface classes are potentially the most important. A solid, intuitive, yet imaginative interface is an indispensable condition to advancing 3D applications beyond standard CAD, game, and picture synthesis programs. With the right interface, 3D controls and views can be used in applications that aren't graphical by nature. For example, an application that needs to set a two dimensional matrix of values can use an interactive 3D mesh: You can image the user turning the mesh to get a better perspective, or clicking on a point in the mesh to move it. We're pretty confident that our developers will find new ways to use interactive 3D controls.
Design Perspectives
At the beginning of this paper, we opined that the 3D world presents three fundamental problems:
Of these, the descriptions in this paper have addressed the final two point, but not much has been said about how to craft your models in the first place--hierarchical model design and LOD management are nice tools, but how do you form the basic models that these tools use? Some sort of CAD program would be nice, but that's a huge task. This problem is too complex for an easy solution. Clearly, it's too soon to define what type of CAD application our programmers will need, since we don't know what they want to do. Nevertheless, here are a few remarks on the direction that we think the 3D Kit will take in future releases, and what we need to do to support these expectations; with luck, we'll find the right combination of internal and external (third party) effort to provide the tools that we need.
What We Need
About B3dBodies:
About 3dWorld:
After all that's done, we need to extend this sort of management to the B3dUniverse. Looking at the wish list, a certain pattern emerges--modeler, looker, archiving...The best way to provide all these services will be to integrate them into a single 3D modeler/looker/editor application (a "3D Maker" app). Perhaps the application could be extended to the different 3D layers (bodies, barriers, worlds) through the use of add-ons. Since we're wishing, let's hope for more: Once our hypothetical 3D Maker app is in place, it would be a simple matter of programming to also create a 3D Browser that would allow the user to cut and paste three-dimensional objects between applications (for example). The demands that this will make upon the UI controls will be...interesting. Again, the controls need to be as intuitive as today's two-dimensional objects; otherwise, the user will give up in frustration.
The 3D Kit in DR8
The 3D Kit is brand new in DR8, and so development hasn't advanced far. Very few of the advanced features are implemented (no B3dDoors yet, for example), and there will certainly be plenty of bugs. To help get you started, we'll publish the source to a simple 3D demo application. So, please, take the DR8 3D Kit for what it is, enjoy it if you can, but don't expect the world (okay, you'll get the world, but don't expect the universe). We hope you understand better now why were not just porting one or two standard 3D APIs. Here's a list of the notable features presented in the DR8 3D Kit:
How to Use the Kit
In closing, let's look at the ways you can approach the 3D Kit as a programmer. We can identify five entry levels:
As a corollary to this, it's also possible to use the 3D Kit simply for its rendering engine. The Kit is designed to allow programmers to use only the parts they need, and to learn only as much about 3D as they are comfortable with. Welcome to the 3D world!
Appendix A: The Game Kit
The Game Kit is new in DR8. Its main feature--currently, its only feature--is the BWindowScreen class. Through the use of a BWindowScreen object, your application can take over the entire screen; no dock, no Browser windows, just the images that you want to display spread across the entire canvas. In addition, BWindowScreen knows about multiple workspaces, so you can set up a different BWindowScreen object in each workspace. Other features of the BWindowScreen class include:
Best of all, everything is completely transparent to the BeOS, so the machine is still completely alive (unlike the deadly lock_screen() function that BWindowScreen replaces). Note that most of the Game Kit's advanced features use the new API for graphic add-ons (described below). Not all of these features will be available for every card; a list of cards that work with the Game Kit will be published with DR8. In a future release (we'll try for DR9), BWindowScreen will be extended to support standard VGA mode (the application will be responsible for setting specific modes using the standard VGA registers). The class will then be useful for much more than just displaying game animation. Other future release features include:
Appendix B: Graphic Driver API
In DR7, we introduced a very simple and limited API for graphic drivers in which drivers are loaded as add-ons. For DR8 we've extended (slightly) the graphics driver API, mostly to provide support for the Game Kit. Drivers that are using the DR7 version of the add-on API are still supported in DR8. The graphics card add-on scheme isn't perfect yet. There are still a couple of important features missing:
The changes that we have planned for DR9 are much more significant than those presented in DR8. For example, we'll probably re-work the API for clarity and stability; because of this, existing graphic add-ons won't be compatible in DR9. We will, of course, provide new drivers for all the graphics cards that are on the official support list, so the incompatibility shouldn't be too painful for most developers. If you're developing a graphics driver and are worried about these change, please contact: Welcom to the 3D World, HTML Edition.
| |||
Copyright ©1997 Be, Inc. Be is a registered trademark, and BeOS, BeBox, BeWare, GeekPort, the Be logo and the BeOS logo are trademarks of Be, Inc. All other trademarks mentioned are the property of their respective owners. Comments about this site? Please write us at webmaster@be.com. Icons used herein are the property of Be Inc. All rights reserved. |