lightfog.txt 14.5 KB
DEVELOPER DOCUMENTATION ON LIGHTING, FOG, and REFLECTION MAPPING
----------------------------------------------------------------
Started 2/23/95 by Acorn (Nathan Pooley) (415)390-2503 acorn@sgi.com

FOG
==============================================================================
Fog works with gspFast3D and gspFastLight3D microcode.

WHAT FOG IS
-----------
Fog makes objects farther from the viewer look different than objects close
to the viewer.  Objects are blended with a "fog color".  The farther the object
is from the viewer, the more it is blended with the "fog color".  Objects close to the far clipping plane will be completely "fog colored" and objects close
to the near clipping plane will be completely normal (as if fog was turned off).
If the fog color is the same as the background color in the scene (eg the sky
color) then objects will appear to fade into the distance as they get farther
away.  This is advantageous because objects which are very far away are often
not drawn (either because they were clipped by the far clipping plane or because
they were culled by the application to save rendering time) and when they get
closer they appear to "pop" into view when they cross the far clipping plane.  
When fog is on (with the "fog color" close to the background color) then 
instead of "popping" into the scene as they approach, objects will "fade" into 
the scene more smoothly.

HOW TO TURN FOG ON
------------------
To use fog do the following things:
  1) Turn 2 cycle mode on because FOG requires 2 cycle mode.
  2) Use a color combiner mode which works in 2 cycle mode.
  2) Set the "fog color" with gsDPSetFogColor.
  3) Turn fog on in the RSP with gsSPSetGeometryMode.
  4) Turn fog on in the RDP with gsDPSetRenderMode.

Here is a sample display list which turns fog on:

    Gfx turn_fog_on[] = {
	gsDPSetCycleType(G_CYC_2CYCLE),			/* 2 cycle mode */
	gsDPSetCombineMode (G_CC_SHADE, G_CC_SHADE),	/* color combiner mode*/
	gsDPSetFogColor(0x00,0xc8,0xc8,0xff),		/* fog color cyan */
	gsSPSetGeometryMode(G_FOG),			/* fog on in RSP */
	gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_AA_ZB_OPA_SURF2),
							/* fog on in RDP */
    };

NOTES:
  The color combiner mode can be any 2 cycle color combiner mode.
  The fog color is up to you.
  The 2nd half of the rendering mode can be any 2nd cycle rendering mode.

HOW TO TURN FOG OFF
-------------------
To turn fog off:
  1) Turn fog off in the RSP with gsSPClearGeometryMode.
  2) Turn fog off in the RDP with gsDPSetRenderMode.

Example:
	gsSPClearGeometryMode(G_FOG),
	gsDPSetRenderMode(G_RM_PASS, G_RM_AA_ZB_OPA_SURF2),

TROUBLESHOOTING NOTE:
  Fog is very sensitive to where the near and far clipping planes are.  If you
are having trouble getting fog to look the way you think it should, try moving
the near plane away from the viewer and the far plane closer to the viewer.
For example, in the call:
	guPerspective(&matrix,fovy,aspect,near,far,scale);
try making "near" larger and "far smaller.
(this same tip applies to troubles with z buffer precision).

ANOTHER NOTE:
  Per vertex alphas cannot be used with fog because the RSP replaces the alpha
with a number used for fog.  You can still use an alpha from a texture map if
you want.


LIGHTING
==============================================================================
Lighting works with gspFastLight3D microcode.

WHAT LIGHTING IS
----------------
Lighting makes 3D objects look more 3D by altering the way they look as they 
change their orientation.  The developer can define up to 7 lights at a time.
Each light has a direction and a color.  Regardless of the orientation of
the object and the viewer, each light will continue to shine in the same
direction (relative to the "world") until the light direction is changed.
There is also an ambient light which shines in all directions uniformly.
Shadows are not explicitly supported.

HOW TO USE LIGHTING
-------------------
  1) To use lighting you must be running the gspFastLight microcode.  If you
	want some objects in a scene to be lit and others to be colored 
	statically they you will have to draw the statically shaded objects
	with the gspFast3D microcode, then load the gspFastLight3D microcode
	and then draw the lighted objects (the order doesn't matter; the 
	lighted objects could be done first).

  2) In order to light an object, the vertices which make up the object must
	have normals instead of colors.  The normal consists of 3 signed 8 
	bit numbers: the x, y, and z comnponants of the normal (each ranging
	from -128 to +127).  The x componant goes in the vertex' red color,
	the y into the green, and the z into the blue.  Alpha is still alpha.
	It is important that the normal be normalized.  This means that
	square_root(x*x + y*y + z*z) <= 127.  To normalize the normal (x,y,z)
	find d=127/square_root(x*x + y*y + z*z).  Then find XN=x*d; YN=y*d;
	ZN=z*d.  The normalized normal is (XN,YN,ZN).

  3) Define some lights (see DEFINING LIGHTS).

  4) Turn the lights on (See TURNING LIGHTS ON).

  5) Draw an object.  All objects drawn will use have lighted colors instead 
	of vertex colors.  In other words any color combiner mode which 
	normally uses vertex colors will now be using lighted colors.

DEFINING LIGHTS
---------------
Lights are defined in structures.  There are 8 macros used to define lights:
gdSPDefLights0, gdSPDefLights1, gdSPDefLights2, ..., gdSPDefLights8.  The one
you use will depend on how many lights you want to turn on.

To define a light structure use gdSPDefLights# where # is the number of lights
that you want to turn on.  For example, for 3 lights:

Lights3 light_structure1 = gdSPDefLights3(
	ambient_red, ambient_green, ambient_blue,
	light1red, light1green, light1blue,   light1x, light1y, light1z,
	light2red, light2green, light2blue,   light2x, light2y, light2z,
	light3red, light3green, light3blue,   light3x, light3y, light3z)

will define a structure called light_structure1 with an ambient light and
3 directional lights.  The red,green,blue (rangeing from 0 to 255) is the
color of the light.  The x,y,z (ranging from -128 to 127) is the direction
of the light.  The direction indicates where the light is.  For example if
the light is coming from the upper left of the world, the direction might be
x=-141, y=-141, z=0. (IMPORTANT NOTE: The light direction indicates the 
direction TO the light and NOT the direction that the light is SHINING.  If 
you know the direction the light is SHINING, supply the negative of that
direction).  If this light is green, and the ambient ligt is red, this structure
could look like this:

Lights1 my_light = gdSPDefLights1(
	255, 0, 0,			/* ambient color green */
	0, 255, 0,   -141, -141, 0)	/* red light from the upper left */

If you don't want any ambient light, make the ambient light black (0,0,0).
If you only want ambient light (no directional light) use gdSPDefLights0:

Lights0 my_ambient_only_light = gdSPDefLights0(
	0, 0, 255)			/* blue ambient light */	

TURNING LIGHTS ON
-----------------
To activate a set lights in a display list use the macros:
gSPSetLights0, gSPSetLights1, gSPSetLights2, ..., gSPSetLights8 or
gsSPSetLights0, gsSPSetLights1, gsSPSetLights2, ..., gsSPSetLights8.

For example, if you want to activate the lights defined in the examples above
you would use:

    gsSPSetLights3(light_structure1),
or
    gsSPSetLights1(my_light),
or
    gsSPSetLights0(my_ambient_only_light),

in a static display list, or to insert into a display list dynamically use 
gSPSetLights#.  Once lights are activated, they will remain on until the
next set of lights is activated.  Whenever you activate a new structure of lights
the old structure of lights is overwritten.

To turn on the lighting computation so that the lights can take effect, the
lighting mode bit needs to be turned on using the macro

gSPSetGeometryMode in a dynamic display list or
gsSPSetGeometryMode in a static display list.

e.g gsSPSetGeometryMode(G_LIGHTING)


LIGHTING NOTES
--------------
1) There can be a maximum of 8 directional lights at a time.  The more lights
	you turn on, the slower the microcode will be.

SPECULAR HIGHLIGHTS
==============================================================================
Specular highlights work with gspFastLight3D microcode.

WHAT SPECULAR HIGHLIGHTS ARE
----------------------------
A specular highlight is the bright spot that you see on a shiny object.  It
is caused by the light from the light source being directly reflected into 
your eye.  Specuar highlights occur on a shiny object wherever the normal, of
the object is halfway between the direction of the light and the direction of 
the eye.  The gspFastLight3D microcode can support zero one or two specular 
highlights on an object.  If you have more than 2 lights in a scene choose the
two most important lights and render the highlights from those two lights.
Specular highlights use texture mapping so specular highlights cannot usually
be used with texture mapped surfaces.  Specular highlighting when combined
with Diffuse lighting (described above) can produce very realistic looking
surfaces.

USING SPECULAR HIGHLIGHTS
-------------------------
A specular highlight is basically a reflection of a light source.  To render it
you need a picture of the light in a texture map.  Most lights' specular
highlights can be represented by a round dot (exponential or gaussian function).
(If you want you can use other shapes of highlight for oddly shaped lights like
flourescent tubes or glowing swords, etc).  The center of the picture of the
light should be in the center of the texture map and the texture map must be a
power of 2 in width and height. For examples I will use a 32x32 bit texture:

#define HIGHLIGHT_TX_WIDTH		32	/* width of texture */
#define HIGHLIGHT_TX_HEIGHT		32	/* height of texture */
#define HIGHLIGHT_TX_WIDTH_POWER2	5	/* 2^5 = texture width (32) */
#define HIGHLIGHT_TX_HEIGHT_POWER2	5	/* 2^5 = texture height (32) */

DESCRIBE THE EYE DIRECTION TO THE RSP
-------------------------------------
The first thing to do is let the RSP know what the eye direction is.  To
accomplish this, replace your call to guLookAt with a call to guLookAtHilite.
The guLookAtHilite call does everything that the guLookAt call does, and it
also sets up 2 structures, Hilite and LookAt, for use in highlighting.  These
two structures must be part of the dynamic segment, declared as:

Hilite hilite;
LookAt lookat;

Make the call to guLookAtHilite (this must be done per frame):

guLookAtHilite( &view_matrix, &lookat, &hilite,
		Eyex,    Eyey,    Eyez,
		Atx,     Aty,     Atz,
		Upx,     Upy,     Upz,
		light1x, light1y, light1z,
		light2x, light2y, light2z,
		HIGHLIGHT_TX_WIDTH, HIGHLIGHT_TX_HEIGHT);

where light1x, light1y, light1z is the light direction of the light
corresponding to the first highlight (same as in the gdSPDefLightsr# macro
described above). Now send this information to the RSP with the LookAt macro:

    gsSPLookAt( &lookat ),

The hilite structure will be used later below.

LOAD THE TEXTURE TO USE IN THE HIGHLIGHT
----------------------------------------
The texture for the highlights must be loaded, so use gsDPLoadTextureBlock
(or similar loadblock command) to load the texture before rendering the
highlight.  For example use:

    gsDPLoadTextureBlock_4b(hilight_texture, G_IM_FMT_I, 
			HIGHLIGHT_TX_WIDTH, HIGHLIGHT_TX_HEIGHT, 0,
                        G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR,
                        HIGHLIGHT_TX_WIDTH_POWER2, HIGHLIGHT_TX_WIDTH_POWER2, 
			G_TX_NOLOD, G_TX_NOLOD),

to load a 32x32 texel texture (4 bit intensity texture).  Note that wrapping
must be turned on (this is why texture size must be a power of 2). Next turn
on a 2nd tile for the 2nd highlight.  This can be done by loading another
texture, but generally the same texture can be used for both highlights.  Use
gsDPSetTile to set up the second tile if you are sharing one texture map.  For
example:

    gsDPSetTile(G_IM_FMT_I, G_IM_SIZ_4b, ((HIGHLIGHT_TX_WIDTH/2)+7)>>3,
                        0, G_TX_RENDERTILE+1, 0, 
			G_TX_WRAP | G_TX_NOMIRROR, 
			HIGHLIGHT_TX_WIDTH_POWER2, G_TX_NOLOD, 
			G_TX_WRAP | G_TX_NOMIRROR, 
			HIGHLIGHT_TX_HEIGHT_POWER2, G_TX_NOLOD),

to set up a second tile (using the same 4 bit intensity texture used for the
first highlight).

DESCRIBE THE HIGHLIGHT POSITIONS TO THE RSP
-------------------------------------------
Finally, after the texture is loaded, send the hilite structure to the rsp
with the gsDPSetHilite1Tile and gsDPSetHilite2Tile macros:

    gsDPSetHilite1Tile(G_TX_RENDERTILE,&hilite,
		HIGHLIGHT_TX_WIDTH,HIGHLIGHT_TX_HEIGHT),
    gsDPSetHilite2Tile(G_TX_RENDERTILE+1,&hilite,
		HIGHLIGHT_TX_WIDTH,HIGHLIGHT_TX_HEIGHT),

NOW DRAW SOME PRIMITIVES WITH HIGHLIGHTS
----------------------------------------
After all the setup, you can draw shiny looking primitives with highlights.
Use 2 cycle mode (one cycle for each highlight) and appropriate rendering
and combine modes.  Use Primitive Color for the first highlight's color and
Environment mode for the second highlight's color.  For example:

    gsDPSetCycleType(G_CYC_2CYCLE),
    gsDPSetEnvColor(000, 255, 255, 255),		/* cyan   */
    gsDPSetPrimColor(0, 0, 255, 255, 000, 255),		/* orange */
    gsDPSetRenderMode(G_RM_PASS, G_RM_AA_ZB_OPA_SURF2),
    gsDPSetCombineMode(G_CC_HILITERGBA, G_CC_HILITERGBA2),

to render a cyan and an orange highlight in opaque z buffered antialiased mode.
Note that the highlight color is often the same as the light's color (unlike
diffuse light which is often affected by the color of the object it is 
striking).

REFLECTION MAPPING
==============================================================================
Reflection mapping may be done in the gspFastLight3D microcode.

WHAT IT IS
----------
Reflection mapping allows you to map a texture onto an object using the normals
of the object to specify where on the abject the texture will be mapped.  If 
this texture is a picture of the surroundings of the object, then this
effect will make the object appear to reflect its surroundings.  This allows 
objects to be rendered as if made of chrome or a mirror surface.

COMPATABLILITY WITH SPECULAR HIGHLIGHTS
---------------------------------------
Reflection mapping uses texture mappping so it cannot be used with objects
which are otherwise texture mapped.  However, Reflection mapping can be used
in conjunction with one specular highlight.  Instead of redering in 1 cycle
mode (as described here-below) render in 2 cycle mode and use a specular
highlight texture in the second tile (used in the second cycle).  

Another way to combine specular highlights with reflection mapping is to draw
specular highlights (bright dots) onto your reflection map texture wherever the
lights are located.  This will allow you an unlimited number of specular
highlights.