EnvironmentHandler
EnvironmentInterface
Availability LightWave 6.0 | Component Layout | Header lwenviron.h
Environment handlers render the backdrop, the points at infinity that aren't covered by anything in the scene. This is the natural place to draw the sky, the distant horizon, or a procedural nebula in space.
Handler Activation Function
XCALL_( int ) MyEnvironment( long version, GlobalFunc *global, LWEnvironmentHandler *local, void *serverData );
The local
argument to an environment handler's activation function is an
LWEnvironmentHandler.
typedef struct st_LWEnvironmentHandler { LWInstanceFuncs *inst; LWItemFuncs *item; LWRenderFuncs *rend; LWError (*evaluate) (LWInstance, LWEnvironmentAccess *); unsigned int (*flags) (LWInstance); } LWEnvironmentHandler;
The first three members of this structure point to the standard handler functions. In addition to these, an environment handler provides an evaluation function and a flags function.
errmsg = evaluate( instance, access )
- This is where the environment handler does its work. At each time step in the animation, the evaluation function is called for each affected pixel in the image. The access argument, described below, contains information about the environment to be colored.
f = flags( instance )
- Returns flag bits combined using bitwise-or.
Interface Activation Function
XCALL_( int ) MyInterface( long version, GlobalFunc *global, LWInterface *local, void *serverData );
This is the standard interface activation for handlers. An environment's non-modal xpanel interface is drawn on the Backdrop tab of the Effects panel.
Environment Access
This is the structure passed to the handler's evaluation function.
typedef struct st_LWEnvironmentAccess { LWEnvironmentMode mode; double h[2], p[2]; LWDVector dir; double colRect[4][3]; double color[3]; } LWEnvironmentAccess;
mode
- The context of the evaluation. Currently this distinguishes between rendering (
EHMODE_REAL
) and lower quality previewing (EHMODE_PREVIEW
). h, p
- The heading and pitch extents of a rectangular area of the backdrop. They're both expressed in radians. In preview mode, these form a bounding box in spherical coordinates of an area to be colored. They should be ignored in real mode.
dir
- A vector pointing toward a point on the backdrop to be colored. Use this when evaluating in real mode.
colRect
- In preview mode, this is where the evaluation function returns the color at the corners
of the rectangular area defined by
h
andp
. The preview display interpolates between these at points inside the rectangle.colRect[0]
gets the color of(h[0], p[0])
gets the color of
colRect[1](h[0], p[1])
gets the color of
colRect[2](h[1], p[0])
gets the color of
colRect[3](h[1], p[1])
color
- In real mode, this is where the evaluation function returns the color of the point
defined by the direction vector
dir
.
Example
The horizon sample duplicates Layout's gradient
backdrop settings. It can also produce a grid backdrop. Be sure to look for the haiku in
the newTime
function.
The following code can be used to draw a simple representation of the sky and ground that includes a disk for the sun.
Drawing the sun requires knowing whether a point on the backdrop is inside the sun's disk. The point's angular separation from the center of the sun must be less than the sun's angular radius. So we need a function for calculating the angular separation between two spherical coordinates.
static double angsep( double h1, double p1, double h2, double p2 ) { double cd; if ( h1 == h2 && p1 == p2 ) return 0.0; cd = cos( p1 ) * cos( p2 ) * cos( fabs( h2 - h1 )) + sin( p1 ) * sin( p2 ); /* catch small roundoff errors */ if ( cd > 1.0 ) cd = 1.0; if ( cd < -1.0 ) cd = -1.0; return acos( cd ); }
We'd also like to write a sampling function that uses the same representation for the point being sampled, regardless of whether it's called in preview or real mode, so we need to be able to convert the direction vector into spherical (heading and pitch) coordinates. If the vector points straight up or down, the heading is undefined, so we set it arbitrarily to 0. To avoid problems with roundoff, we say that the vector is straight up or down if the magnitude of the y component is within some epsilon of 1.0.
static void vec2hp( LWDVector n, double *h, double *p ) { *p = asin( -n[ 1 ] ); if ( 1.0 - fabs( n[ 1 ] ) > 1e-5 ) { /* not straight up or down */ *h = acos( n[ 2 ] / cos( *p )); if ( n[ 0 ] < 0.0 ) *h = 2 * PI - *h; } else *h = 0; }
The sampling function decides whether the point is in the sky, the ground, or the sun,
and colors the point accordingly. If the backdrop point is below the horizon, the ground
color is used. If both the point and the sun are above the horizon, the point is compared
to the sun's position to decide whether the sun or the sky color is used. hsun
and psun
are the heading and pitch of the sun's position. In preview mode, the
Manhattan distance between the point and the sun's center is sufficient, while in real
mode we do the more expensive angular separation calculation.
static void sample( MyInstance *inst, double h, double p, double *color, int mode ) { int insun; if ( p >= 0.0 ) { color[ 0 ] = inst->gndcolor[ 0 ]; color[ 1 ] = inst->gndcolor[ 1 ]; color[ 2 ] = inst->gndcolor[ 2 ]; return; } insun = inst->psun - inst->sunrad < 0.0; if ( insun ) { if ( mode == EHMODE_PREVIEW ) insun = ( fabs( h - inst->hsun ) < inst->sunrad ) && ( fabs( p - inst->psun ) < inst->sunrad ); else insun = angsep( h, p, inst->hsun, inst->psun ) < inst->sunrad; } if ( insun ) { color[ 0 ] = inst->suncolor[ 0 ]; color[ 1 ] = inst->suncolor[ 1 ]; color[ 2 ] = inst->suncolor[ 2 ]; } else { color[ 0 ] = inst->skycolor[ 0 ]; color[ 1 ] = inst->skycolor[ 1 ]; color[ 2 ] = inst->skycolor[ 2 ]; } }
The evaluation function uses the sampling function to find the right color and returns the color to the renderer.
XCALL_( static LWError ) Evaluate( MyInstance *inst, LWEnvironmentAccess *access ) { double h, p; switch ( access->mode ) { case EHMODE_PREVIEW: sample( inst, access->h[ 0 ], access->p[ 0 ], access->colRect[ 0 ], access->mode ); sample( inst, access->h[ 0 ], access->p[ 1 ], access->colRect[ 1 ], access->mode ); sample( inst, access->h[ 1 ], access->p[ 0 ], access->colRect[ 2 ], access->mode ); sample( inst, access->h[ 1 ], access->p[ 1 ], access->colRect[ 3 ], access->mode ); break; case EHMODE_REAL: vec2hp( access->dir, &h, &p ); sample( inst, h, p, access->color, access->mode ); break; default: break; } return NULL; }