The geometry and appearance of a shape are independent of one another. The appearance of a shape is the two-dimensional texture, such as the rind of an orange, that is mapped onto a geometry.
This chapter describes how to specify the appearance of a geometry in the following sections::
A csContext object maintains the OpenGL graphics state for a scene graph and therefore contains all the default appearance values necessary to render a shape.
Appearance values, such as material and texture, can be specified per shape using csAppearance. If csAppearance fields are not set, the shape inherits the default appearance values set in csContext. For optimal performance, set as few csAppearance object fields as possible by setting the global defaults in csContext to values that satisfy the majority of geometries in a scene graph. This practice minimizes state changes while rendering.
There is an inheritance mask in each csAppearance that specifies which appearance values are inherited by csAppearance from csContext. csAppearance values automatically override csContext default values on a per-shape basis, regardless of the bit values in the inheritance mask.
csContext maintains and manages OpenGL graphics state for the purpose of efficient graphics pipeline state control. OpenGL is a state machine: you put it into various states (or modes) that then remain in effect until you change them. For example, the current color is a state variable. The Cosmo 3D context maintains two notions of state:
State that is not explicitly set in a csAppearance via the appropriate csAppearance set() methods is inherited from the default state. An inheritance mask, however, specifies which csContext fields a shape inherits by default.
The effect of a set() method is immediate, as if you made the OpenGL calls directly. The set() methods affect the current state but have no effect on the default state.
Inheritance masks specify which csContext fields are inherited by csAppearance. Each bit in the bitmask corresponds to a specific csAppearance field. All fields are inherited by default.
Figure 3-1 demonstrates how the inheritance mask works as a result of the code in Example 3-1.
csContext *ctx = new cscontext; ctx->setCullFace(BACK); ctx->setLightEnable(TRUE); . . . csAppearance *app = new csAppearance; app->setMaterial(mtl); shape->setAppearance(app); |
All 0 bits indicate that the default value is used.
When you set a csAppearance value, its corresponding bit in the inheritance mask is set.
Applications can access the current state using the various get() methods. The primary use of the get() method is to ask the system about its current state. Cosmo 3D makes this state available so that a user callback can know the current state of the system and make OpenGL calls appropriately.
![]() | Warning: It is critical that such a callback not alter the OpenGL state. |
You can avoid altering the OpenGL state either by using csContext::set() calls or by saving and restoring OpenGL state explicitly upon entry and exit of the callback.
As a csDrawAction traverses the scene graph, the current state is modified when:
Appearances a their draw methods are invoked.
Calls users make to various set() methods in csContext invoke pre- and post-node callbacks.
The actual appearance of a csGeometry being drawn is independent of traversal order. Only that csShape's appearance and the default state affect the actual appearance. At no time does Cosmo 3D depend on the traversal order of the draw action. No guarantees are made about traversal order because the traversal order of the draw is subject to change. Because applications cannot depend on draw traversal order to imply the state of the context, methods to query the context for its current state are available.
csContext can be used in a multi-threaded program. When makeCurrent() is called within a given thread, that context is attached to the thread. Binding a thread to a context allows multi-pipe or multi-window rendering in parallel using a single, shared copy of the scene graph.
For more information about multi-threaded implementation, see Chapter 13, “Multiprocessing.”
In general, csAppearance settings override csContext default values. You can, however, override csAppearance settings using csContext::pushOverrideAppearance(). Only one override appearance per context can be in place at a time.
You can override some properties that are not in csAppearance and are geometry-specific through the use of pushOverrideGeoProp(). Currently, csCullFace, csLineWidth, and csPointSize are the only geometry-specific properties that can be overridden.
To change the screen to a specified color, use one of the following csContext methods:
static void clear(int which); static void clear(int which, float r, float g, float b, float a); |
where which is a bitmask specifying whether to clear the color planes, depth planes, or both.
The first clear() method clears the screen to black. The second version allows you to set a uniform color and transparency.
You can create multiple csContext objects but only one can be active at a time. In this way, in addition to changing field values in a context object, you can change the entire context all at once using makeCurrent(). This method replaces the current context with the csContext object specified in the argument, for example:
csContext* context1 = new csContext; csContext* context2 = new csContext; context1->makeCurrent(display, window); context2->makeCurrent(display, window); |
In this example, the second context replaces the first.
display is a pointer to the X window display.
window is the GLXDrawable in which the scene is displayed.
getCurrent() returns the context object on top of the context stack.
csWindow has a context and calls makeCurrent() automatically.
csAppearance fields define the appearance of a csGeometry object, for example, its texture, material, or color. All of the fields in csAppearance are replicated in csContext.
To specify the appearance of a csGeometry, you can either
Set all of the appearance fields in a csAppearance object.
Use the inherited, global, default values from the current context, csContext.
Use a combination of the first two options.
If you set all of the fields of an appearance object, the appearance object becomes the full graphic context of the csShape. The more appearance fields you set, however, the slower the application's performance because you are triggering lots of state changes.
For maximum performance, set the appearance values in csContext to satisfy the maximum number of shapes so that the fewest number of csAppearance fields are set on a per-shape basis.
The only fields that you should set locally are those that change often, such as the field values for material and texture. Changing a field value locally overrides any value inherited from csContext.
The csAppearance class includes a series of set...() methods to define the appearance characteristics of a geometry. A series of corresponding get...() methods provide access to those values. The following set...() methods are described in greater detail in the rest of this chapter:
void setTexture(csTexture* texture); void setTexEnable(csBool texEnable); void setTexMode(csContext::TexModeEnum texMode); void setTexBlendColor(const csVec4f& texBlendColor); void setTexBlendColor(csFloat v0, csFloat v1, csFloat v2, csFloat v3); void setTexEnv(csContext::TexEnvEnum texEnv); void setTexGen(csTexGen* texGen); void setTexGenEnable(csBool texGenEnable); void setMaterial(csMaterial* material); void setLightEnable(csBool lightEnable); void setShadeModel(csContext::ShadeModelEnum shadeModel); void setTranspEnable(csBool transpEnable); void setTranspMode(csContext::TranspModeEnum transpMode); void setAlphaFunc(csContext::AlphaFuncEnum alphaFunc); void setAlphaRef(csFloat alphaRef); void setBlendColor(const csVec4f& blendColor); void setBlendColor(csFloat v0, csFloat v1, csFloat v2, csFloat v3); void setSrcBlendFunc(csContext::SrcBlendFuncEnum srcBlendFunc); void setDstBlendFunc(csContext::DstBlendFuncEnum dstBlendFunc); void setColorMask(const csVec4ub &colorMask); void setColorMask(csUByte v0, csUByte v1, csUByte v2, csUByte v3); void setDepthFunc(csContext::DepthFuncEnum depthFunc); void setDepthMask(csUInt depthMask); void setFogEnable(csBool fogEnable); void setPolyMode(csContext::PolyModeEnum polyMode); |
These method are separated into two groups:
Methods containing the string “tex” modify textures.
The remaining methods modify the appearance of geometries.
csAppearance values are updated in a lazy way: a value is changed only when it is used. For example, if a ball is currently displayed and you change its color using setColor(), the ball would change color immediately on the screen. If, however, the ball is out of view of the camera, the color of the ball would not be updated until it is seen by the camera.
One way to affect the appearance of a geometry is to apply a texture to it. A texture is a rectangular 2D image, for example, a 2D map of the world. This rectangular texture is scaled or repeated to fit on the surface of a 3D object, such as a sphere. The clamping and repetition of a texture over a surface is programmatically controllable.
To create the image of an orange, for example, you first create the orange, pitted texture of orange rind and then apply it to a sphere. The difference between using and not using a texture, in this example, is the difference between rendering a generic sphere and a realistic-looking orange.
A texture map is always defined by the coordinates s, for the horizontal component, and t, for the vertical component, each of which range in values from 0.0 to 1.0, as shown in Figure 3-3.
Texture coordinates are assigned to each vertex of a geometry either by you or by Cosmo 3D.
To apply a texture to a geometry, set the argument of the csAppearance::setTexEnable() method to ON. If you do not want to apply a texture to a geometry, set the argument of setTexEnable() to OFF.
Texture rendering uses the texture values specified in csContext by default. To set the texture values locally, however, use the following methods in csAppearance:
setTexture() | to specify the image used as the texture. | |
setTexMode() | to specify the speed and quality of the rendered texture. | |
setTexBlendColor() |
| |
setTexEnv() | to specify how texture colors are blended with the colors of a geometry. | |
setTexGen(), setTexGenEnable() |
|
The following sections describe these methods.
To apply a texture to a geometry, supply a csTexture object in the argument of setTexture(). csTexture is a class consisting of the following fields and default values:
csSFString filename “noName” csMFRef imageLevel[] csSFEnum format 0 csSFEnum repeat_S REPEAT csSFEnum repeat_T REPEAT csSFEnum minFilter FAST csSFEnum magFilter FAST csSFEnum source 0 |
imageLevel is an array of MIPmap levels for this texture of type csImages. If this field is not set or has all NULL values, the texture is loaded from csSFString fileName instead.
format is the pixel format of the image. For more information about pixel format, see “Color Components”.
repeat_S and repeat_T specify whether or not the texture is repeated in the s and t directions on the geometry, respectively. If the texture is not repeated, it is clamped.
minFilter specifies what to do with texels that project smaller than a screen pixel. Possible values include NEAREST_MIN, LINEAR_MIN, or MIPMAP.
magFilter specifies what to do with texels that project larger than a screen pixel. Possible values include NEAREST_MAX or LINEAR_MAX.
The texture mode method allows you to specify texture rendering speed, quality, and perspective where speed and quality, and speed and perspective are trade-offs.
You specify the mode of the texture rendering using setTexMode() with one of the following arguments from csContext::TexModeEnum:
When you choose the NON_PERSP_TEX mode, Cosmo 3D applies the texture to a geometry without proper perspective. For example, if you apply a texture to a plane extending into the Z dimension, the pattern should not distort but just appear to recede into the distance. In NON_PERSP_TEX mode, however, the pattern is distorted, as shown in Figure 3-4.
If you enable texture rendering but do not set the texture mode in a csContext or csAppearance object, the texture rendering mode is defined by the csTexture object in the argument of csAppearance::setTexture() or csContext::setTexture(). A csTexture object can specify one of the values in TexModeEnum.
Texture environment variables specify how texture colors are blended with the colors of a geometry; the texture color can replace, blend with, or subtract from the colors already on the geometry.
To specify how texture colors are blended with the colors of a geometry, use the setTexEnv() method with one of the following csContext::TexEnvEnum values as an argument:
![]() | Tip: If you use MODULATE, consider surrounding your texture images with a one-pixel border of white pixels and set csTexture::setRepeatS() and csTexture::setRepeatT() to CLAMP so the geometry's color is used where the texture runs out. |
A texture image can have up to four components per texture element:
A one-component image consists of a luminance value, Lt. One-component textures are often referred to as intensity maps. For example, an image of a statue could use polygons of different intensities to shade and provide detail.
A two-component image consists of luminance, Lt, and transparency, At. For example, you could create an architect's diagram of a house using polygons of different intensities to give detail to the building materials and then vary the transparency of the polygons to see through the building materials.
A three-component image consists of a set of RGB values, referred to as a color triplet, Ct. For example, any color image is at least a three-component image.
A four-component image consists of an RGB (or Ct) set of values, and transparency, At. The “t” subscript denotes the transparency or the color of the texture. For example, you could create an architect's diagram of a house using a variety of colors and transparencies.
The color components work with the texture environments in the following way:
MODULATE works with any texture file.
BLEND works with one- to four-component textures.
REPLACE works with three- or four-component textures.
ADD works with three- or four-component textures.
DECAL works with three- or four-component textures.
![]() | Tip: MODULATE works best with bright materials because the texture intensity is reduced by the factor of the geometry's intensity. |
There are two ways to specify how a texture is applied to a geometry:
Use the default. Cosmo 3D applies textures to geometries according to the geometry.
Use the texture coordinate function, setTexGen().
Cosmo 3D applies textures to geometries according to the geometry. For all geometries subclassed from csGeometry, Cosmo 3D
Computes the bounding box.
Turns the texture so its longest side is in the horizontal (s) direction.
The horizontal (s) value ranges from 0.0 to 1.0 and the vertical component ranges from 0.0 to n, where n equals the ratio of the t dimension to the s dimension; this ratio maintains the texture without distorting it.
The setTexGen() method generates texture coordinates by, in effect, projecting a texture plane onto a geometry, as shown in Figure 3-5.
The setTexGen() method specifies
Whether or not the texture plane is repeated across the geometry.
Whether the texture plane is stationary or moves in concert with the motion of the geometry.
The setTexGen() method takes a csTexGen object for an argument. In a csTexGen object, you set the
Repetition of the texture image in three dimensions, s, t, and r.
Mode of the texture in each of the dimensions.
For example, csTexGen::setPlaneS(2.5, 0, 0, 0) repeats the texture two-and-a-half times in the s dimension.
Figure 3-6 shows how a texture plane is repeated across a geometry.
The default values of both s plane equations are (1,0,0,0), both t plane equations are (0,1,0,0), and all r and q plane equations are (0,0,0,0).
If you think of the texture plane as being projected onto the surface of a geometry rather than being on the surface of a geometry, it is easy to understand how the mode settings in csTexGen work. Either the plane is stationary and the geometry moves “under” it or the plane moves in concert with the geometry. In the second case, the colors of the plane appear to be part of the geometry when it moves; in the first case, the colors of the plane appear to ride over the geometry when it moves.
You set the mode of each plane in csTexGen to one of the following values:
The setTexGen() function is enabled or disabled using setTexGenEnable() with an argument of ON or OFF, respectively. Enabling the generation is, in effect, like turning on the light which shines through the plane and onto a geometry. Disabling the generation turns off the light.
The remaining sections apply to the appearance of the geometry itself.
The material field in csAppearance defines the surface qualities of a geometry, such as how well it reflects light, what color it reflects, and what color it emits. The material field is of type csMaterial, which has the following set...() methods:
void setAmbientIntensity(csFloat ambientintensity); void setAmbientColor (const csVec3f& ambientColor); void setDiffuseColor(const csVec3f& diffuseColor); void setDiffuseColor(float v0, float v1, float v2); void setSpecularColor(const csVec3f& specularColor); void setSpecularColor(float v0, float v1, float v2); void setEmissiveColor(const csVec3f& emissiveColor); void setEmissiveColor(float v0, float v1, float v2); void setAmbientIndex(csShort ambientIndex); void setDiffuseIndex(csShort diffuseIndex); void setSpecularIndex(csShort specularIndex); void setShininess(csFloat shininess); void setTransparency(csFloat transparency); |
csMaterial also has a corresponding set of get...() methods.
Ambient color is the color of the light reflected from an object when lit by another ambient object in the scene. The default value is [0.2, 0.2, 0.2]. Ambient intensity refers to the strength of the reflection—a value between 0.0 and 1.0 where 1.0 is a strong reflection. Ambient index refers to a color lookup table in which each ambient color is paired with an index number for easy look-ups.
Diffuse color is an object's base color. The default value is [0.8, 0.8, 0.8]. Diffuse index refers to a color lookup table in which each diffuse color is paired with an index number for easy look-ups.
Specular color is the reflected color of an object's highlights. Specular intensity refers to the strength of the reflection. The default value is [0.0, 0.0, 0.0]. Specular index refers to a color lookup table in which each specular color is paired with an index number for easy look ups.
Emissive color is the color emitted by an object. A lamp shade for example, might have a base color of yellow. When the lamp is turned on, however, the emissive color might be white. The default value is [0.0, 0.0, 0.0].
Shininess describes how much of the surroundings are reflected by an object, for example, a mirror would have a large shininess value so that surrounding objects would be seen in it. Values range from 0.0, for a very dull surface, to 1.0, for a highly polished surface. The default value is 0.2.
Transparency describes how opaque or clear an object is, for example, water might be more clear than opaque. Values range from 0.0, for opaque, to 1.0, for complete transparency. The default value is 0.0.
The following example shows the material settings for gold:
csMaterial *gold = new csMaterial; gold->setAmbientColor(.3, .1, .1); gold->setDiffuseColor(.8, .7, .2); gold->setSpecularColor(.4, .3, .1); gold->setShininess(.4); |
Since gold is opaque, the default value, 0.0, for transparency suffices.
The setPolyMode() method specifies how to render the elementary polygons that compose a geometry. The following values for the method are valid:
For example, if you use POINT_PMODE, a triangle would appear as three points. LINE_PMODE would render a triangle as a set of three lines; FILL_PMODE would render the triangle as filled.
You set the shading model using the setShadeModel() method with one of the following csContext::ShadeModelEnum values as its argument:
To specify the transparency of a geometry locally, enable the transparency mode by setting setTranspEnable() to ON and then specifying the transparency mode in the argument of setTranspMode(). The possible transparency values include
Commonly, you use the setTranspMode() twice: you specify
FAST_TRANSP or NICE_TRANSP
BLEND_TRANSP or SCREEN_DOOR_TRANSP
The setAlphaFunc() method sets the requirements for whether or not a pixel is rendered. Not rendering some of the pixels in a geometry has the effect of making the geometry partially transparent.
To use the setAlphaFunc() method, you first set the reference value against which you measure the alpha value of the pixel to be drawn using setAlphaRef(), for example
setAlphaRef(10); |
Then you supply, as an argument to setAlphaFunc(), one of the values of csContext::AlphaFuncEnum:
NEVER_AFUNC
LESS_AFUNC
EQUAL_AFUNC
LEQUAL_AFUNC
GREATER_AFUNC
NOTEQUAL_AFUNC
GEQUAL_AFUNC
ALWAYS_AFUNC
For example, the following code
setAlphaRef(0.5); setAlphaFunc(LESS_AFUNC); |
is similar to the following lines of code:
if(Alpha < 0.5) { //draw the pixel }; |
where Alpha is the alpha values of pixels to be drawn in a geometry.
The values have the following effects:
NEVER_AFUNC |
| |
LESS_AFUNC | The incoming pixel is rendered only if its alpha value is less than the reference value. | |
ALWAYS_AFUNC |
|