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( int 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( int 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 modifies the color at the corners
of the rectangular area defined by h and p. The preview display
interpolates between these at points inside the rectangle.
colRect[0] gets the color of (h[0], p[0])
colRect[1] gets the color of (h[0], p[1])
colRect[2] gets the color of (h[1], p[0])
colRect[3] gets the color of (h[1], p[1])
- color
- In real mode, this is where the evaluation function modifies 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;
}
|