Immediate-Mode Rendering

The Java 3D API Specification |

C H A P T E R 14

Immediate-Mode Rendering

> JAVA 3D is fundamentally a scene graph-based API. Most of the constructs in the API are biased toward retained mode and compiled-retained mode rendering. However, there are some applications that want both the control and the flexibility that immediate-mode rendering offers.

> Immediate-mode applications can either use or ignore Java 3D's scene graph structure. By using immediate mode, end-user applications have more freedom, but this freedom comes at the expense of performance. In immediate mode, Java 3D has no high-level information concerning graphical objects or their composition. Because it has minimal global knowledge, Java 3D can perform only localized optimizations on behalf of the application programmer.

> ## 14.1 Two Styles of Immediate-Mode Rendering

> Use of Java 3D's immediate mode falls into one of two categories: pure immediate-mode rendering and mixed-mode rendering in which immediate mode and retained or compiled-retained mode interoperate and render to the same canvas. The Java 3D renderer is idle in pure immediate mode, distinguishing it from mixed-mode rendering.

> ### 14.1.1 Pure Immediate-Mode Rendering

> Pure immediate-mode rendering provides for those applications and applets that do not want Java 3D to do any automatic rendering of the scene graph. Such applications may not even wish to build a scene graph to represent their graphical data. However, they use Java 3D's attribute objects to set graphics state and Java 3D's geometric objects to render geometry.

> A pure immediate mode application must create a minimal set of Java 3D objects before rendering. In addition to a Canvas3D object, the application must create a View object, with its associated PhysicalBody and PhysicalEnvironment objects, and the following scene graph elements: a VirtualUniverse object, a high-resolution Locale object, a BranchGroup node object, a TransformGroup node object with associated transform, and, finally, a ViewPlatform leaf node object that defines the position and orientation within the virtual universe that generates the view (see Figure 14-1).

> Figure 14-1 Minimal Immediate-Mode Structure

> Java 3D provides utility functions that create much of this structure on behalf of a pure immediate-mode application, making it less noticeable from the application's perspective-but the structure must exist.

> All rendering is done completely under user control. It is necessary for the user to clear the 3D canvas, render all geometry, and swap the buffers. Additionally, rendering the right and left eye for stereo viewing becomes the sole responsibility of the application.

> In pure immediate mode, the user must stop the Java 3D renderer, via the Canvas3D object `stopRenderer()` method, prior to adding the Canvas3D object to an active View object (that is, one that is attached to a live ViewPlatform object).

> ### 14.1.2 Mixed-Mode Rendering

> Mixing immediate mode and retained or compiled-retained mode requires more structure than pure immediate mode. In mixed mode, the Java 3D renderer is running continuously, rendering the scene graph into the canvas. The basic Java 3D stereo rendering loop, executed for each Canvas3D, is as follows:

>     clear canvas (both eyes)
>     call preRender()                           // user-supplied method
>     set left eye view
>     render opaque scene graph objects
>     call renderField(FIELD_LEFT)               // user-supplied method
>     render transparent scene graph objects
>     set right eye view
>     render opaque scene graph objects again
>     call renderField(FIELD_RIGHT)              // user-supplied method
>     render transparent scene graph objects again
>     call postRender()                          // user-supplied method
>     synchronize and swap buffers
>     call postSwap()                            // user-supplied method

> The basic Java 3D monoscopic rendering loop is as follows:

>     clear canvas
>     call preRender()                            // user-supplied method
>     set view
>     render opaque scene graph objects
>     call renderField(FIELD_ALL)                 // user-supplied method
>     render transparent scene graph objects
>     call postRender()                           // user-supplied method
>     synchronize and swap buffers
>     call postSwap()                             // user-supplied method

> In both cases, the entire loop, beginning with clearing the canvas and ending with swapping the buffers, defines a frame. The application is given the opportunity to render immediate-mode geometry at any of the clearly identified spots in the rendering loop. A user specifies his or her own rendering methods by extending the Canvas3D class and overriding the `preRender`, `postRender`, `postSwap`, and/or `renderField` methods.

> ## 14.2 Canvas3D Methods

> The Canvas3D methods that directly affect immediate-mode rendering are described here.

> When a Canvas3D object is created, it is initially marked as being started. This means that as soon as the Canvas3D is added to an active View object, the rendering loop will render the scene graph to the canvas. In pure immediate mode, the renderer must be stopped (via a call to `stopRenderer`) prior to adding the canvas to an active View object.

> ##### Constants

>     public static final int FIELD_LEFT
>     public static final int FIELD_RIGHT
>     public static final int FIELD_ALL

> These constants specify the field that the rendering loop for this Canvas3D is rendering. The `FIELD_LEFT` and `FIELD_RIGHT` values indicate the left and right fields of a field-sequential stereo rendering loop, respectively. The `FIELD_ALL` value indicates a monoscopic or single-pass stereo rendering loop.

> ##### Methods

>     public GraphicsContext3D getGraphicsContext3D()

> This method retrieves the immediate-mode 3D graphics context associated with this Canvas3D. It creates a new graphics context if one does not already exist. It returns a GraphicsContext3D object that can be used for immediate mode rendering to this Canvas3D.

>     public J3DGraphics2D getGraphics2D()

> This method returns the 2D graphics object associated with this Canvas3D. A new 2D graphics object is created if one does not already exist. See Section 14.3.2, "J3DGraphics2D."

>     public void preRender()

> Applications that wish to perform operations in the rendering loop prior to any actual rendering must override this method. The Java 3D rendering loop invokes this method after clearing the canvas and before any rendering has been done for this frame. Applications should not call this method.

>     public void postRender()

> Applications that wish to perform operations in the rendering loop following any actual rendering must override this method. The Java 3D rendering loop invokes this method after completing all rendering to the canvas for this frame and before the buffer swap. Applications should not call this method.

>     public void postSwap()

> Applications that wish to perform operations at the very end of the rendering loop must override this method. The Java 3D rendering loop invokes this method after completing all rendering to this canvas, and all other canvases associated with the current view, for this frame following the buffer swap. Applications that wish to perform operations at the very end of the rendering loop may override this function. In off-screen mode, all rendering is copied to the off-screen buffer before this method is called. Applications should not call this method.

>     public void renderField(int fieldDesc)

> Applications that wish to perform operations during the rendering loop must override this function. The Java 3D rendering loop invokes this method, possibly twice, during the loop. It is called once for each field (once per frame on a monoscopic system or once each for the right eye and left eye on a field-sequential stereo system). This method is called after all opaque objects are rendered and before any transparent objects are rendered (subject to restrictions imposed by OrderedGroup nodes). This is intended for use by applications that want to mix retained/compiled-retained mode rendering with some immediate-mode rendering. The `fieldDesc` parameter is the field description: `FIELD_LEFT`, `FIELD_RIGHT`, or `FIELD_ALL`. Applications that wish to work correctly in stereo mode should render the same image for both `FIELD_LEFT` and `FIELD_RIGHT` calls. If Java 3D calls the renderer with `FIELD_ALL`, the immediate-mode rendering needs to be done only once. Applications should not call this method.

>     public final void startRenderer()
>     public final void stopRenderer()

> These methods start or stop the Java 3D renderer for this Canvas3D object. If the Java 3D renderer is currently running when `stopRenderer` is called, the rendering will be synchronized before being stopped. No further rendering will be done to this canvas by Java 3D until the renderer is started again. If the Java 3D renderer is not currently running when `startRenderer` is called, any rendering to other Canvas3D objects sharing the same View will be synchronized before this Canvas3D's renderer is (re)started.

>     public final boolean isRendererRunning()

> This method retrieves the state of the renderer for this Canvas3D object.

>     public void swap()

> This method synchronizes and swaps buffers on a double-buffered canvas for this Canvas3D object. This method should be called only if the Java 3D renderer has been stopped. In the normal case, the renderer automatically swaps the buffer. This method calls the `flush(true)` methods of the associated 2D and 3D graphics contexts, if they have been allocated. If the application invokes this method and the canvas has a running Java 3D renderer, a `RestrictedAccessException` exception is thrown. An `IllegalStateException` is thrown if this Canvas3D is in off-screen mode.

> ## 14.3 API for Immediate Mode

> The Java 3D immediate mode allows an application to set attributes directly and draw three-dimensional geometry using the same objects as in Java 3D scene graphs. An immediate-mode application renders by passing these objects to the `set` and `draw` methods of a GraphicsContext3D object.

> ### 14.3.1 GraphicsContext3D

> The GraphicsContext3D object is used for immediate-mode rendering into a 3D canvas. It is created by, and associated with, a specific Canvas3D object. A GraphicsContext3D class defines methods that manipulate 3D graphics state attributes and draw 3D geometric primitives.

> Note that the drawing methods in this class are not necessarily executed immediately. They may be buffered up for future execution. Applications must call the `flush(boolean)` method to ensure that the rendering actually happens. The `flush` method is implicitly called in the following cases:

> - The `readRaster` method calls `flush(true).`

> - The `Canvas3D.swap` method calls `flush(true).`

> - The Java 3D renderer calls `flush(true)` prior to swapping the buffer for a double-buffered on-screen Canvas3D.

> - The Java 3D renderer calls `flush(true)` prior to copying into the off-screen buffer of an off-screen Canvas3D.

> - The Java 3D renderer calls `flush(false)` after calling the `preRender`, `renderField`, `postRender`, and `postSwap` Canvas3D callback methods.

> A single-buffered, pure-immediate mode application must explicitly call `flush` to ensure that the graphics will be rendered to the Canvas3D.

> ##### Constants

>     public static final int STEREO_LEFT
>     public static final int STEREO_RIGHT
>     public static final int STEREO_BOTH

> These constants specify whether rendering is done to the left eye, to the right eye, or to both eyes.

> ##### Constructors

> There are no publicly accessible constructors of GraphicsContext3D. An application obtains a 3D graphics context object from the Canvas3D object into which the application wishes to render by using the `getGraphicsContext3D` method.

> The Canvas3D object creates a new GraphicsContext3D the first time an application invokes `getGraphicsContext3D`. A new GraphicsContext3D initializes its state variables to the following defaults:

> Parameters | Default Values
> --- | ---
> Background object | null
> Fog object | null
> ModelClip object | null
> Appearance object | null
> List of Light objects | empty
> High-Res coordinates | (0, 0, 0,)
> modelTransform | identity
> AuralAttributes object | null
> List of Sound objects | empty
> buffer override | false
> front buffer rendering | false
> stereo mode | STEREO_BOTH

> ##### Methods

>     public Canvas3D getCanvas3D()

> This method gets the Canvas3D that created this GraphicsContext3D.

>     public void setAppearance(Appearance appearance)
>     public Appearance getAppearance()

> These methods access or modify the current Appearance component object used by this 3D graphics context. The graphics context stores a reference to the specified Appearance object. This means that the application may modify individual appearance attributes by using the appropriate methods on the Appearance object (see Section 8.1.2, "Appearance Object"). The Appearance component object must not be part of a live scene graph, nor may it subsequently be made part of a live scene graph-an `IllegalSharingException` is thrown in such cases. If the Appearance object is `null`, default values will be used for all appearance attributes-it is as if an Appearance node were created using the default constructor.

>     public void setBackground(Background background)
>     public Background getBackground()

> These methods access or modify the current Background leaf node object used by this 3D graphics context. The graphics context stores a reference to the specified Background node. This means that the application may modify the background color or image by using the appropriate methods on the Background node object (see Section 6.4, "Background Node"). The Background node must not be part of a live scene graph, nor may it subsequently be made part of a live scene graph-an `IllegalSharingException` is thrown in such cases. If the Background object is `null`, the default background color of black (0,0,0) is used to clear the canvas prior to rendering a new frame. The Background node's application region is ignored for immediate-mode rendering.

>     public void setFog(Fog fog)
>     public Fog getFog()

> These methods access or modify the current Fog leaf node object used by this 3D graphics context. The graphics context stores a reference to the specified Fog node. This means that the application may modify the fog attributes using the appropriate methods on the Fog node object (see Section 6.7, "Fog Node"). The Fog node must not be part of a live scene graph, nor may it subsequently be made part of a live scene graph-an `IllegalSharingException` is thrown in such cases. If the Fog object is `null`, fog is disabled. Both the region of influence and the hierarchical scope of the Fog node are ignored for immediate-mode rendering.

>     public void addLight(Light light)
>     public void insertLight(Light light, int index)
>     public void setLight(Light light, int index)
>     public Light getLight(int index)
>     public void removeLight(int index)
>     public int numLights()
>     public Enumeration getAllLights()

> These methods access or modify the list of lights used by this 3D graphics context. The `addLight` method adds a new light to the end of the list of lights. The `insertLight` method inserts a new light before the light at the specified index. The `setLight` method replaces the light at the specified index with the light provided. The `removeLight` method removes the light at the specified index. The `numLights` method returns a count of the number of lights in the list. The `getLight` method returns the light at the specified index. The `getAllLights` method retrieves the Enumeration object of all lights.

> The graphics context stores a reference to each light object in the list of lights. This means that the application may modify the light attributes for any of the lights using the appropriate methods on that Light node object (see Section 6.8, "Light Node"). None of the Light nodes in the list of lights may be part of a live scene graph, nor may they subsequently be made part of a live scene graph-an `IllegalSharingException` is thrown in such cases. Adding a `null` Light object to the list will result in a `NullPointerException`. Both the region of influence and the hierarchical scope of all lights in the list are ignored for immediate-mode rendering.

>     public void setHiRes(int x[], int y[], int z[])
>     public void setHiRes(HiResCoord hiRes)
>     public void getHiRes(HiResCoord hiRes)

> These methods access or modify the high-resolution coordinates of this graphics context to the location specified by the parameters provided. In the first method, the parameters `x`, `y`, and `z` are arrays of eight 32-bit integers that specify the high-resolution coordinates point.

>     public void setModelTransform(Transform3D t)
>     public void multiplyModelTransform(Transform3D t)
>     public void getModelTransform(Transform3D t)

> These methods access or modify the current model transform. The `multiplyModelTransform` method multiplies the current model transform by the specified transform and stores the result back into the current model transform. The specified transformation must be affine. A `BadTransformException` is thrown (see Section D.1, "BadTransformException") if an attempt is made to specify an illegal Transform3D.

>     public void setBufferOverride(boolean bufferOverride)
>     public boolean getBufferOverride()

> These methods set and retrieve a flag that specifies whether the double buffering and stereo mode from the Canvas3D are overridden. When set to true, this attribute enables the `frontBufferRendering` and `stereoMode` attributes.

>     public void setFrontBufferRendering(boolean frontBufferRendering)
>     public boolean getFrontBufferRendering()

> These methods set and retrieve a flag that enables or disables immediate mode rendering into the front buffer of a double buffered Canvas3D. This attribute is used only when the `bufferOverride` flag is enabled. Note that this attribute has no effect if double buffering is disabled or is not available on the Canvas3D.

>     public void setStereoMode(int stereoMode)
>     public int getStereoMode()

> These methods set and retrieve the current stereo mode for immediate mode rendering. The parameter specifies which stereo buffer or buffers are rendered into. This attribute is used only when the `bufferOverride` flag is enabled. The stereo mode is one of the following: `STEREO_LEFT`, `STEREO_RIGHT`, or `STEREO_BOTH`. Note that this attribute has no effect if stereo is disabled or is not available on the Canvas3D.

>     public void setModelClip(ModelClip modelClip)
>     public ModelClip getModelClip()

> These methods set and retrieve the current ModelClip leaf node. The set method sets the ModelClip to the specified object. The graphics context stores a reference to the specified ModelClip node. This means that the application may modify the model clipping attributes using the appropriate methods on the ModelClip node object. The ModelClip node must not be part of a live scene graph, nor may it subsequently be made part of a live scene graph-an IllegalSharingException is thrown in such cases. If the ModelClip object is null, model clipping is disabled. Both the region of influence and the hierarchical scope of the ModelClip node are ignored for immediate-mode rendering.

>     public void setAuralAttributes(AuralAttributes attributes)
>     public AuralAttributes getAuralAttributes()

> These methods access or modify the current AuralAttributes component object used by this 3D graphics context. The graphics context stores a reference to the specified AuralAttributes object. This means that the application may modify individual audio attributes by using the appropriate methods in the Aural-Attributes object (see Section 8.1.17, "AuralAttributes Object"). The Aural-Attributes component object must not be part of a live scene graph, nor may it subsequently be made part of a live scene graph-an `IllegalSharingException` is thrown in such cases. If the AuralAttributes object is `null`, default values will be used for all audio attributes-it is as if an AuralAttributes object were created using the default constructor.

>     public void addSound(Sound sound)
>     public void insertSound(Sound sound, int index)
>     public void setSound(Sound sound, int index)
>     public Sound getSound(int index)
>     public void removeSound(int index)
>     public int numSounds()
>     public boolean isSoundPlaying(int index)
>     public Enumeration getAllSounds()

> These methods access or modify the list of sounds used by this 3D graphics context. The `addSound` method appends the specified sound to this graphics context's list of sounds. The `insertSound` method inserts the specified sound at the specified index location. The `setSound` method replaces the specified sound with the sound provided. The `removeSound` method removes the sound at the specified index location. The `numSounds` method retrieves the current number of sounds in this graphics context. The `getSound` method retrieves the index-selected sound. The `isSoundPlaying` method retrieves the sound-playing flag. The `getAllSounds` method retrieves the Enumeration object of all the sounds.

> The graphics context stores a reference to each sound object in the list of sounds. This means that the application may modify the sound attributes for any of the sounds by using the appropriate methods on that Sound node object (see Section 6.9, "Sound Node"). None of the Sound nodes in the list of sounds may be part of a live scene graph, nor may they subsequently be made part of a live scene graph-an `IllegalSharingException` is thrown in such cases. Adding a `null` Sound object to the list results in a `NullPointerException`. If the list of sounds is empty, sound rendering is disabled.

> Adding or inserting a sound to the list of sounds implicitly starts the sound playing. Once a sound is finished playing, it can be restarted by setting the sound's enable flag to `true`. The scheduling region of all sounds in the list is ignored for immediate-mode rendering.

>     public void readRaster(Raster raster)

> This method reads an image from the frame buffer and copies it into the ImageComponent or DepthComponent objects referenced by the specified Raster object. All parameters of the Raster object and the component ImageComponent or DepthComponent objects must be set to the desired values prior to calling this method. These values determine the location, size, and format of the pixel data that is read. This method calls `flush(true)` prior to reading the frame buffer.

>     public void clear()

> This method clears the canvas to the color or image specified by the current Background leaf node object.

>     public void draw(Geometry geometry)
>     public void draw(Shape3D shape)

> The first `draw` method draws the specified Geometry component object using the current state in the graphics context. The second `draw` method draws the specified Shape3D leaf node object. This is a convenience method that is identical to calling the `setAppearance(Appearance)` and `draw(Geometry)` methods passing the Appearance and Geometry component objects of the specified Shape3D nodes as arguments.

>     public void flush(boolean wait)

> This method flushes all previously executed rendering operations to the drawing buffer for this 3D graphics context. The `wait` parameter indicates whether to wait for the rendering to complete before returning from this call.

> ### 14.3.2 J3DGraphics2D

> The J3DGraphics2D class extends Graphics2D to provide 2D rendering into a Canvas3D. It is an abstract base class that is further extended by a non-public Java 3D implementation class. This class allows Java 2D rendering to be mixed with Java 3D rendering in the same Canvas3D, subject to the same restrictions as imposed for 3D immediate-mode rendering: In mixed-mode rendering, all Java 2D requests must be done from one of the Canvas3D callback methods; in pure-immediate mode, the Java 3D renderer must be stopped for the Canvas3D being rendered into.

> An application obtains a Java 3D 2D graphics context object from the Canvas3D object that the application wishes to render into by using the `getGraphics2D` method. A new J3DGraphics2D object is created if one does not already exist.

> Note that the drawing methods in this class, including those inherited from Graphics2D, are not necessarily executed immediately. They may be buffered up for future execution. Applications must call the `flush(boolean)` method to ensure that the rendering actually happens. The flush method is implicitly called in the following cases:

> - The `Canvas3D.swap` method calls `flush(true).`

> - The Java 3D renderer calls `flush(true)` prior to swapping the buffer for a double-buffered on-screen Canvas3D.

> - The Java 3D renderer calls `flush(true)` prior to copying into the off-screen buffer of an off-screen Canvas3D.

> - The Java 3D renderer calls `flush(false)` after calling the `preRender`, `renderField`, `postRender`, and `postSwap` Canvas3D callback methods.

> A single-buffered, pure-immediate mode application must explicitly call `flush` to ensure that the graphics will be rendered to the Canvas3D.

> ##### Methods

>     public abstract void flush(boolean wait)

> This method flushes all previously executed rendering operations to the drawing buffer for this 2D graphics object.

>     public final Graphics create()
>     public final Graphics create(int x, int y, int width, int height)

> These methods are not supported. The only way to obtain a J3DGraphics2D is from the associated Canvas3D.

>     public final void setBackground(Color color)
>     public final Color getBackground()
>     public final void clearRect(int x, int y, int width, int height)

> These methods are not supported. Clearing a Canvas3D is done implicitly via a Background node in the scene graph or explicitly via the `clear` method in a 3D graphics context.

The Java 3D API Specification |

##### Copyright © 2000, Sun Microsystems, Inc. All rights reserved.