Open Source Platform
for interconnected virtual worlds

NG Design Document/Viewer Architecture/Graphics

From Rex community wiki

Contents

Introduction

Because the new viewer will be plugin-based, it is natural that the graphics renderer, responsible for drawing the virtual world on the screen, is also another plugin.

The new viewer will be initially developed to display 3D graphics on desktop and laptop PC's, and the default renderer plugin we develop will reflect this. But because of the plugin nature, it will be possible to also create 2D or even text renderer plugins for more limited hardware in the future.

The default 3D renderer plugin will provide a platform- and rendering API-independent way of drawing objects on the screen. In addition to just displaying the 3D objects in the virtual world view, it should also provide facilities to draw arbitrary 2D and 3D elements on top of the world view, for head-up-displays (HUDs), tools and debug information for instance.

The default 3D renderer will use the LGPL-licensed open source 3D rendering engine OGRE [1], which has a clean, extensible object-oriented design, is relatively easy to learn to program to, and is actively developed. OGRE is multiplatform and has support for both Direct3D and OpenGL rendering APIs. It supports features expected of modern rendering engines such as programmable shaders, materials defined through a declaration language, particle effects, skeletal animation, post processing effects, and level-of-detail.

Other alternatives to OGRE are for example Irrlicht [2] and OpenSceneGraph [3]: both are also open source multiplatform rendering engines. However, Irrlicht does not have as clean design as OGRE, and also for example its material capabilities are not nearly as powerful as in OGRE. OpenSceneGraph on the other hand is a complex and extensible OpenGL-based rendering engine, which has a significantly steeper learning curve compared to OGRE while not providing superior features. On Windows machines it is preferable to use Direct3D if possible due performance and compatibility: especially low-end graphics cards usually support Direct3D better in their drivers.


Features

The default 3D renderer will expose OGRE features and capabilities through its interface, these include but are not limited to:

High-level:

  • 3D mesh-based objects
  • Terrain geometry
  • Animations (both vertex and skeletal)
  • Lights - point light, spot light and directional light
  • Particle emitters
  • Billboards
  • Materials
  • Textures
  • Shaders

Low-level:

  • Arbitrarily definable 3D geometry (for example manually created shapes such as boxes / spheres)
  • Performing arbitrary rendering operations


Assets

The renderer plugin must be able to dynamically receive and take into use assets that come through the viewer's asset cache system, or alternatively are manually (programmatically) created: these assets include meshes and their skeletons, textures, materials and shaders. It should be noted that OGRE usually works best with assets that are pre-loaded at program start, so in some cases modification of the OGRE library may be necessary. In this case, patches should be submitted upstream: making Ogre more dynamic will benefit all of its users.


On interface and abstraction

Because of the complexity of all the renderer features, it is to be expected that some OGRE abstractions will leak outside of the default renderer to the other modules using the renderer. However, the abstractions should not leak to the core framework itself. It would be a large and time-wasting job to create an abstract interface for all the renderer features and parameters just in an attempt to hide OGRE. This interface would still probably become very OGRE-like, and for other possible future renderers a different kind of interface might be needed in any case.

In any case, the kind of a renderer plugin used affects heavily how it will be used by the other modules. This is not limited to just the function interface, but also the asset data fed to the renderer: a 2D renderer plugin could not naturally use 3D mesh data in a sensible way.


Operation

When initializing, the renderer plugin must possibly interact with the graphical user interface to create its rendering window, if the world view is embedded into the GUI. But in case of no GUI embedding, the renderer plugin should create and manage the rendering window by itself.

To actually display objects inside the virtual world, world entities will have renderer-related components exposed by the renderer plugin, such as a mesh component or a light component. When the set/get functions of these components are used, for example setting the material of a mesh or the intensity of a light, the values will be set/queried from the underlying rendering engine.

The renderer plugin offers a service method to render the scene. This will be called by the viewer framework for each frame of processing. When finished with the world rendering, the renderer will send a "post-render" event, into which other modules can subscribe to perform custom drawing on top of the world view as desired: heads-up-displays, 2D/3D tools and debug drawing.

Use cases

Renderer initialization without embedding into user interface

  • The renderer plugin is initialized.
  • The renderer queries for a user interface module that supports embedding (Qt/GTK+ for example) and finds none.
  • The renderer creates its own rendering window, that may be fullscreen or not.

Renderer initialization with embedding into user interface

  • The renderer plugin is initialized.
  • The renderer queries and finds an user interface module that supports embedding.
  • The renderer requests the window handle to be used for the rendering window from the user interface.
  • The renderer creates the rendering window using the received window handle.

Rendering a frame, including custom rendering

  • As a part of the frame update process, the core framework calls the renderer's render() service function.
  • The renderer redraws the 3D world view to its rendering window.
  • The renderer sends a post-render event, which is to be reacted into immediately.
  • A heads-up-display module receives the post-render event and draws its own elements into the rendering window, using the renderer's rendering operation API.
  • The renderer swaps buffers, making the just rendered frame visible.

Adding a 3D mesh into the world

  • A mesh component is added into a world entity.
  • Appropriate parameters (mesh asset to use, material etc.) are set using the mesh component's API.
  • The mesh will appear in the 3D world on subsequent frames.

Performing a ray cast query

  • A module wants to know what object is in a certain direction (for example in the direction pointed by the mouse cursor).
  • To get this information, it asks the renderer, via a function call, to perform a ray cast query.
  • The renderer performs the ray cast, using OGRE scene manager facilities, and going into per-poly checking as necessary.
  • A list of objects, sorted in nearest-first fashion, is returned.

Showing an activity icon on top of an avatar

  • A user is typing into a chat window and an activity/busy icon should be displayed above her avatar.
  • A billboard component, that will display the busy icon, is added to the avatar entity with an appropriate position offset, by the World Logic module.
  • After the user has finished typing, the billboard component is removed by the World Logic module.


UML diagram

Image:RendererPlugin.png


Citations

  1. OGRE
    (http://www.ogre3d.org/)
  2. Irrlicht
    (http://irrlicht.sourceforge.net/)
  3. OpenSceneGraph
    (http://www.openscenegraph.org/projects/osg)