Image Filter (ls-if.p)
Object Replacement (ls-or.p)
Displacement Map (ls-dm.p)
Procedural Texture (ls-pt.p)
Item Animation (ls-ia.p)
Layout Generic (ls-gn.p)
With the notable exception of Layout Generic scripts, Layout scripting, on the other hand, presents a new method of script execution that causes an LScript to be activated only once, while it remains active until it is specifically stopped by either the termination of LightWave Layout, or the explicit deactivation of the Layout LScript plug-in from the plug-in panel. The script remains active even while you perform other functions within LightWave Layout. LightWave Layout scripts are designed to partake in this type of cooperative execution.
To facilitate this cooperative execution, Layout LScript scripting is centered completely around the concept of "call-back" functions. A call-back function is one designed to be called at any time, usually to respond to some specific event or situation. Until these call-back functions are activated, they remain "asleep," taking up no CPU time and having no influence on the processing of LightWave Layout.
Figure #1 illustrates the flow of execution in Modeler LScript.
Figure #1 Modeler LScript Execution Flow
Figure #2, however, illustrates the dramatic difference in execution flow for a Layout LScript.
Figure #2 Layout LScript Execution Flow
As mentioned previously, Layout Generic scripts are the exeception to this mechanism. The reason for this exception is that Layout Generic plug-ins are not associated with any Layout component (Camera, Mesh object, Light, etc.), and as such, are not involved in the generation of frames of animation. In fact, Layout Generic scripts behave almost identically to Modeler scripts in that they have a single point of entry, and their execution begins and ends with this function. Layout Generic scripts, however, have full access to all non-architecture-specific Layout components that all other Layout scripts enjoy. The section documenting Layout Generic LScripts later on this page provides more detail.
Having a clear understanding of these mechanisms is essential to the discussions that follow. Please take this time to examine the available example scripts for additional clarification, if necessary.
process()
this call-back function is used to perform the main
processing of the script, if any (similar to main() in
Modeler scripting). it can be (and usually is) invoked
more than once.
create()
called once when the script is loaded, immediately upon
successful processsing of the script by the LScript core
engine. it is used to perform "startup" processing for a
script.
destroy()
called once when the script is deactivated from the plug-in
panel or removed from memory. used to perform "cleanup"
processing for a script.
save()
called when a scene file is saved to disk by the user. at
this time, the script can store any script-related values
to be restored when the scene is reloaded into LightWave
Layout. in either a scene (ASCII) or object (binary) file.
this function will be called each time the scene is saved
to disk.
load()
used to restore any previously-saved script-related values
from either a scene or object file
options()
invoked when the the "Options" button of the script is
selected. standard requester functions, identical to those
available in Modeler LScript, can be used to generate a
user-interface and to allow the user to modify operational
parameters. the LightWave Panel Services Global-Class
plug-in must be available for successful requester dialog
creation to occur. The LW Panel Services plug-in enables
Layout LScript to offer several "extended" control types,
discussed in Appendix C.
A Layout script can define any of these "common" functions that it
wishes to have activated. Once again, if one of these functions is not
present in your script, Layout LScript will default its behavior (which is to
say, an empty internal function is invoked instead). This is true even for
the process() function.
Again, Layout Generic is the exception to these standards. Layout Generic
scripts have a single required function, generic(), where processing
takes place when the script is activated. Refer to the
Layout Generic LScripts section later on this
page for more information.
The current globals available to Layout scripts are:
INSTANCE a read-only character string that represents an identifier
that is guaranteed to be unique for each instance of a
script, regardless of plug-in architecture.
Getfirstitem() returns a value that represents the first object of the type you desire. You select from the available object types by providing getfirstitem() with a parameter value (pre-defined by Layout LScript for convenience) that indicates the object list from which to pull. These pre-defined values are:
MESH select from among the available Layout mesh objects
LIGHT select from among the defined Layout light sources
CAMERA get a value that represents the Layout camera
SCENE get a value that contains information about scene settings
Getfirstitem() will also accept a character string that should represent the
name of an object that currently exist in Layout. This name should be identical
to that displayed to the user in any object-selection panel within Layout.Named objects can include Lights, Mesh data, or Bones.
filllight = getfirstitem("FillLight");
You might have noticed that an access identifier for Bones is missing. The
reason for this is that Bone objects are considered children of Mesh objects;
Bones cannot exist by themselves. As such, access to Bone information must
take place through the parent Mesh object. Bone objects essentially become
data members of the LScript Mesh object.As the name implies, getfirstitem() will return the first object (according to LightWave Layout) that resides in the list of the objects of the specified type. However, if no items of the specified type exist in the current scene, then getfirstitem() will return 'nil'. The following code snippet illustrates how you might use getfirstitem() to begin a sequential scan of the lights currently defined in the scene:
...
light = getfirstitem(LIGHT);
if light != nil then
begin
// scan through all lights
...
end
else
// we're animating by Braille...
...
The data type returned by getfirstitem() are "instances" of an internal LScript
object type designed to provide an interface to, or "wrapper" around, the
Layout object returned. Unlike normal LScript data types (string, integer, etc.),
this data type is "alive." Not only does it provide access to data that is
associated with the Layout object, but in most cases these object "instances"
provide functions that you can invoke to perform some operation on the Layout
object or its data. In the language of C++, these functions are referred to
as "methods," and the object variables containing data are referred to as
"data members." These "wrappers" for the Layout objects are known as Layout
Object Agents in LScript parlance, but we will refer to them simply as Object
Agents.The LScript data type known as a "FileObject" is also a type of Object Agent, used as agents for disk files.
Getfirstitem() returns an Object Agent for the first Layout object, but it provides no capability for randomly accessing Layout objects, nor is there a companion function to getfirstitem() that will return the next Layout object in the list. How, then, do you access other objects of the same type?
Once you have the first Object Agent off the list, you have in your possession the ability to access all other Layout objects of that class in sequential order. Each Object Agent returned by a call to getfirstitem() provides (or "exports") some common functions (or "methods") that allow each Object Agent to perform the same functions--even though they my do so in different ways. In a purely object-oriented language like Smalltalk, these common methods are known as "messages" that an object recognizes and to which it can respond. When instances of different "classes" (definition of objects) respond to the same message, they are considered to be "polymorphic."
One such method that each Object Agent exports is called "next." The next() method will return the next Layout object (as a LScript Object Agent instance) in the list of the same object category. By way of example, let's see how we might accomplish a traversal of Layout Light objects in a Layout LScript script.
light = getfirstitem(LIGHT);
while(light != nil)
{
...code to process this light instance...
light = light.next();
}
Each Object Agent returned by getfirstitem() (or, for that matter, those
returned by any Object Agent method that returns another Object Agent) will
respond to the following common methods and contains the following common data
members:
parent
points to an Object Agent that represents the Layout
object that is considered the parent of this Layout
object (or 'nil' if there is none)
target
points to an Object Agent that represents the Layout
object that is designated as the target for this Layout
object (or 'nil' if there is none)
type
holds a constant (i.e., read-only) value that identifies
the type of this Layout object (one of MESH, BONE, LIGHT,
CAMERA, or SCENE)
goal
points to an Object Agent that represents the Layout
object that is designated as the goal for this Layout
object (or 'nil' if there is none)
name
holds a character string that represents the name of this
Layout object (as it appears to the user in an Layout
object list)
getPosition(time) -> vector
getRight(time) -> vector
getUp(time) -> vector
getForward(time) -> vector
getRotation(time) -> vector
getScaling(time) -> vector
getPivot(time) -> vector
getWorldPosition(time) -> vector
getWorldRight(time) -> vector
getWorldUp(time) -> vector
getWorldForward(time) -> vector
each of these methods returns a vector containing the
three numeric values corresponding to the parameter
at the specified time index.
limits(state) -> array[6]
returns an array of six (6) numbers that represent the
minimum [elements 1-3] and maximum [elements 4-6] limits
that have been established on a particular Layout object
state (POSITION, RIGHT, UP, FOWARD, ROTATION, SCALING,
PIVOT or WPOSITION)
filename
holds a character string that represents the filename
(including path, if any) that contains this Layout object
pointcount
when appropriate, contains an integer value that
represents the number of points in the Layout object, or
'nil' when not appropriate (i.e., CAMERA)
polycount
when appropriate, contains an integer value that
represents the number of polygons in the Layout object,
or 'nil' when not appropriate (i.e., CAMERA)
shadows[]
holds an array of three (3) boolean values that represent
the Layout object's current shadow options:
[1] == true if Self Shadow is on, or false if off
[2] == true if Casts Shadow is on, or false if off
[3] == true if Receive Shadow is on, or false if off
dissolve(time) -> number
returns the percentage (where 1.0 equals 100%) that this
Layout object is dissolved at the specified 'time' index
next() -> Object Agent
returns the next Layout object (as a LScript Object Agent) in
the list of the same category, or 'nil' if there is none
firstChild() -> Object Agent
returns a Object Agent that represents the Layout object
that is designated as the first child belonging to this
Layout object (or 'nil' if there is none)
nextChild() -> Object Agent
returns the next Object Agent that represents the Layout
object that is designated as a child of this Layout
object (or 'nil' if there is none)
bone() -> Object Agent
returns the first Object Agent that represents the Layout
object that is designated as the first bone assigned to
this Layout object (using the Object Agent method next(),
you can traverse all Layout bones that are assigned to
this Layout object)
Because not all Layout objects contain the same types of data, some Object
Agents will only offer a subset of these data members and respond to a subset
of these exported methods. For instance, Object Agents of type SCENE will
return 'nil' for most of these methods, and the CAMERA Object Agent contains
no points or polygons.A number of exported Object Agent methods listed previously accept a parameter that needs to be provided as a "time index." This index value represents the offset (expressed as time) from the beginning of the specific span of animation frames contained in the scene. To calculate the time index in which you have interest, simply divide the frame number by the frames-per-second setting for the scene. For instance, frame number 163 of a 30-frames-per-second animation would be the (163 / 30) second time index, or 5.43 seconds into the animation.
At the time of this writing, LightWave 3D is currently in its fifth major release, and as of LightWave 3D version 5.0, all data members discussed in this section are strictly read-only. Modifying them will have no effect on the Layout objects themselves, and will likely generate a run-time error when the script is executed.
flags[]
holds an array of two (2) boolean values that represent
the Bone's current options:
[1] == true if Bone is active, or false if not
[2] == true if Bone is limited, or false if unlimited
restparam(state) -> array[3]
returns an array of three (3) numbers that represent the
value of a particular Bone state. The state value can be
one of POSITION, RIGHT, UP, FORWARD, ROTATION, SCALING,
PIVOT or WPOSITION ("world" position)
restlength
contains a floating-point number that represents the rest
length of the Bone in meters
innerlimit
contains a floating-point number that represents the
inner limit radius of the Bone (only valid if flags[2] is
'true')
outerlimit
contains a floating-point number that represents the
outer limit radius of the Bone (only valid if flags[2] is
'true')
ambient(time) -> vector
rgbambient(time) -> array[3]
returns a vector or array of three (3) values that
represent the global ambient Light's color values
at the specified 'time' index. ambient() returns
the channel value as a percentage between 0.0 and 1.0,
while rgbambient() returns the channel value as an
integer between 0 and 255.
type
holds a constant (read-only) integer value that
identifies the type of this Light (one of DISTANTLIGHT,
POINTLIGHT, or SPOTLIGHT)
color(time) -> vector
rgbcolor(time) -> array[3]
returns a vector or array of three (3) values that
represent the Light's color values at the specified
'time' index. color() returns the channel value as
a percentage between 0.0 and 1.0, while rgbcolor()
returns the channel value as an integer between 0
and 255.
shadowtype
holds a constant (read-only) integer value that
identifies the shadow type of this Light (one of
SHADOWRAYTRACE, SHADOWMAP or SHADOWOFF)
coneangles[]
holds an array of two (2) floating-point numbers that
represent the cone angles for this Light if it is of type
SPOTLIGHT. The first element [1] represents the radius
as half the total Spotlight cone angle, and element [2]
indicates the angular width of the Spotlight's soft edge.
zoomfactor(time) -> number
returns a floating-point number that represents the
Camera's zoom factor at the specified 'time' index
focallength(time) -> number
returns a floating-point number that represents the
Camera's focal length at the specified 'time' index
focaldistance(time) -> number
returns a floating-point number that represents (in
meters) the Camera's focal distance at the specified
'time' index
fstop(time) -> number
returns a floating-point number that represents the
Camera's f-stop setting at the specified 'time' index
blurlength(time) -> number
returns a floating-point number that represents (in
meters) the Camera's blur length at the specified 'time'
index
fovangles(time) -> array[2]
returns an array of two (2) floating-point numbers that
represent the Camera's field-of-view angles at the
specified 'time' index. the first element [1] represents
the horizontal angle, the second element [2] represents
the vertical angle. these angles (measured in radians)
are centered around the Camera's direction
name
holds a character string that represents the name of this
Scene
filename
holds a character string that represents the filename of
this Scene
totalpoints
contains an integer value that represents the total
number of Mesh points in the Scene
totalpolygons
contains an integer value that represents the total
number of Mesh polygons in the Scene
rendertype
holds a constant (read-only) integer value that
identifies the type of rendering that will take place in
the Scene (one of WIRERENDER, QUICKRENDER, or
REALISTICRENDER)
renderopts[]
holds an array of eight (8) boolean values that represent
the Scene's current options:
[1] == true if Shadow Tracing is active
[2] == true if Reflection Tracing is active
[3] == true if Refraction Tracing is active
[4] == true if Field Rendering is active
[5] == true if Reverse Field Rendering is active
[6] == true if Motion Blur is active
[7] == true if Depth-Of-Field is active
[8] == true if Limited Region is active
framestart
contains an integer value that represents the beginning
frame number to render
frameend
contains an integer value that represents the ending
frame number to render
framestep
contains an integer value that represents the frame step
value
fps
contains an integer value that represents the
frames-per-second setting for the Scene (default is 30)
framewidth
contains an integer value that represents the width of
the frames to be rendered
frameheight
contains an integer value that represents the height of
the frames to be rendered
pixelaspect
contains a floating-point number that represents the
pixel aspect ratio of the Scene (as pixel-width /
pixel-height).
minsamplesperpixel
contains an integer value that represents the minimum
number of samples per pixel in the final image based on
the current rendering options.
maxsamplesperpixel
contains an integer value that represents the maximum
number of samples per pixel in the final image based on
the current rendering options.
limitedregion[]
holds an array of four (4) floating-point numbers that
represent the location of the Scene's limited region
area:
[1] == x0
[2] == y0
[3] == x1
[4] == y1
options() function, a Layout script can use requester code that
is virtually identical to that used by Modeler LScript. In fact, requester code can
actually be transferred between scripts without modification. However,
unlike Modeler, LightWave Layout does not contain integral interface code
that is made available to user-written plug-ins. Instead, Layout employs the
Panel Services plug-in to provide interface features to user-written plug-ins.
LScript takes advantage of the Panel Services plug-in to facilitate its own
requester functionality.Because Panel Services makes available controls that add more functionality than those found in LightWave 3D Modeler, Layout LScript passes this ability on to the Layout script writer in the form of new functions. Even though these new controls could be considered "non-standard", they have been designed within Layout LScript to function in a fashion similar to other controls.
Because Panel Services is a plug-in, the possibility exists that the plug-in may
not be available at the time your LScript attempts to post a requester panel.
To allow the script writer the ability to detect the absence of this critical
plug-in, the reqbegin() command has been extended in Layout LScript
to return a logical 'true' or 'false' value to indicate the presence of the
Panel Services plug-in. A logical 'true' indicates its presence. You can use
this indicator to decide whether or not you have the required facilities to post
requesters from your script.
...
if(!reqbegin("My Requester"))
{
error("Requester support unavailable");
return;
}
...
In support of Panel Services, five new control creation commands have been
added to the Layout LScript command set. These functions are only available
in Layout scripts; Modeler LScript does not support Panel
Services-equivalents of these control commands.
ctlfilename(title,filename) -> string
creates a control that contains an text edit field and
a push button that will post a file-requester dialog
box. the selection returned from the file requester will
be placed into the text edit field.
'title' is a string value representing the label of the
control
'filename' is a string value representing the initial
value of the filename edit field of the control
ctlrgb(title,rgb) -> vector
creates a control that contains three numeric entry fields
for typing in color components and a preview area where the
entered values are combined and displayed.
'title' is a string value representing the label of the
control
'rgb' is a vector value representing the Red, Green and Blue
color components in the 'x', 'y', and 'z' positions. each of
these values is an integer number between 0 and 255. This
parameter can also be a single integer value that will be used
with all channels, or it can be three individual integer
values corresponding to each of the color channels.
ctlhsv(title,hsv) -> vector
creates a control that contains three numeric entry fields
for typing in color components and a preview area where the
entered values are combined and displayed.
'title' is a string value representing the label of the
control
'hsv' is a vector value representing the Red, Green and Blue
color components in the 'x', 'y', and 'z' positions. each of
these values is an integer number between 0 and 255. This
parameter can also be a single integer value that will be used
with all channels, or it can be three individual integer
values corresponding to each of the color channels.
ctlcheckbox(title,state) -> boolean
'title' is a string value representing the label of the
control
'state' is a boolean value that indicates the appearance
of the checkbox. a logical 'true' will initially check
the control, while a logical 'false' will leave it
unchecked
ctlallitems(title) -> Object Agent
ctlmeshitems(title) -> Object Agent
ctlcameraitems(title) -> Object Agent
ctllightitems(title) -> Object Agent
ctlboneitems(title) -> Object Agent
ctlimageitems(title) -> Object Agent
these functions create controls that provide a drop-down
list of the specified types of Layout objects currently
available in the scene. the return value from each of these
controls is an Object Agent that represents the LightWave
object that was selected, or 'nil' if no object was selected.
'title' is a string value representing the label of the
control
Because we will be dealing with and discussing internal data structures that LightWave 3D makes publicly available to plug-ins, it is assumed that you have some level of familiarity with the data structures and mechanisms that are employed by 3D rendering systems and some of the more common computer graphics file formats being used in the industry today (i.e., Targa).
There are a number of different data buffers that Layout uses or creates as a result of its rendering activity, and your LS/IF script can request access to any or all of these buffers. Regardless of which buffers you request, however, all LS/IF scripts have implicit access to the Red, Green, Blue and Alpha-Channel buffers maintained by Layout. You do not have to explicitly request these buffers.
With the exception of the implicit buffers (Red, Green, etc.), all Layout-maintained buffers are strictly read-only. Their contents are intended to be used to influence your modifications of those buffers whose data are meant to be altered.
The buffers to which a LS/IF script can request access are:
RED, GREEN, BLUE, ALPHA
these buffers are available to every script, and represent the
individual RGB and Alpha values of the rendered frame. off all
buffers available, only these may be modified. all others are
strictly read-only
SPECIAL
this value is assigned by the user on a surface by surface basis
which is used only for this filter. this is designed to be used
to activate the post-processing effect for specific surfaces,
and user-assigned percentages show up here as 0-255 values in
the buffer
LUMINOUS, DIFFUSE, MIRROR, TRANS, RAWRED, RAWGREEN, RAWBLUE
these eight buffers are the raw values of the surface parameters
before shading
SHADING
this buffer is a picture of the diffuse shading applied to the
raw shapes in the image
SHADOW
this buffer indicates where shadows are falling in the final
image. it may also be thought of as an illuminations map,
showing what parts of the image are visible to the lights in the
scene
GEOMETRY
the values in this buffer are computed from the dot-product of
the surface normal with the eye vector. it reveals something
about the underlying shape of the objects in the image. where
this buffer is 255 (or 1.0) the surface is facing directly
toward the camera, and where this buffer is 0, the surface is
edge-on to the camera
DEPTH
this buffer is a map of the distance of each pixel from the
camera plane. this buffer differs from all the others in that
it is floating point, and because it is not anti-aliased or
motion-blurred
You can communicate to Layout the buffers it should make available to your
script by returning one or more of these pre-defined values from your
flags() function. In fact, the sole purpose of the flags() function is to
do nothing but return one or more of these values. For example, the following
code snippet illustrates a sample flags() function used to merely consume
CPU time by requesting the implicit buffers:
flags
{
return(RED, // select the defaults just for fun
GREEN,
BLUE,
ALPHA);
}
Processing Image Buffers
As with most Layout scripts, the central point of processing in a
LS/IF script takes place in the process() function. The process() function
is invoked only once for every frame of animation that LightWave 3D Layout
generates, and any manipulations the script is designed to apply to the image
pixels should be rendered to the entire image at that time.
LS/IF passes five parameters to the process() function when it is invoked.
These parameters are designed to assist the process() function in accessing
data in the Layout buffers by providing such information as the image width
and height, as well as the current frame number being rendered. The five
parameters passed to a LS/IF process() function are listed below.
width
an integer value that indicates the width (number of horizontal
lines) of the generated image. this value will be equal to the
value that the user has set under the Layout Camera information
panel.
height
an integer value that indicates the height (number of vertical
lines) of the generated image. this value will be equal to the
value that the user has set under the Layout Camera information
panel.
frame
an integer value that indicates the frame number of the
generated image
start
a floating-point number that represents the start time of this
frame as a time index value.
end
a floating-point number that represents the end time of this
frame expressed as a time index value.
this index value will be the same as the start time unless the
frame has had motion-blur apply by Layout. In this case, the
difference between the starting and ending time index is the
"exposure time" for the frame
LS/IF scripts can call upon specialized, internal functions for accessing and
updating the Red, Green, Blue and Alpha-Channel image buffer data. These
functions are only available to a LS/IF function, and are not shared among
other Layout scripts.
bufferline(bufferid,line) -> array[]
used to retrieve the values in the buffer identified by
'bufferid' for the indicated vertical image 'line'. 'bufferid'
is one of the buffer indicators discussed previously (SPECIAL,
DIFFUSE, RED, etc.). if a buffer is requested that was not
selected in the flags() function, a run-time error will occur.
returns an array of buffer values whose count of elements
matches the 'width' parameter passed to the process() function
floatline(bufferid,line) -> array[]
this function is identical to bufferline(), except that it is
used to access buffers that contain floating-point data
(currently only the DEPTH buffer qualifies)
setrgb(col,row,buf)
used to set the Red, Green and Blue value for a particular image
pixel at the specified row/column of the image. 'buf' is an
array of three color values that represent Red ([1]), Green
([2]) and Blue ([3])
setalpha(col,row,bufval)
used to set the Alpha value for a particular image pixel at the
specified row/column of the image
processrgb(row,red,green,blue,alpha)
this function is a replacement for both the setrgb() and
setalpha() functions, and will process all four buffers at once
for the specified image row. because individual buffer elements
are processed all at once--instead of one at a time, as is the
case with setrgb() and setalpha()--this function tends to be
much faster
Please note that, as in all cases concerning LScript arrays, the values that you
use as image row/column indicators should always be "1-based", meaning that
the first element in each buffer is always [1]. If you attempt to access the
first element as [0], a run-time error will be generated, and the LS/IF
script will disable itself from further activation.
Caching Image Data
As the name implies, Image Filter plug-ins are quite literally filters.
Data comes in one end from Layout, and passes out the other end directly back to
Layout. When you call bufferline() to retrieve a copy of the
data in Layout's render buffer, you must process that line, and pass it back
to Layout using any one of the available processing commands. In a typical
processing situtation, however, once you pass this modified data back to
Layout, you cannot access it again. Further calls to bufferline()
requesting the same scan-line will simply return to you the original,
unmodified scan-line data. The image data you modified is now safely
tucked away into a separate buffer, forever beyond your reach.
LS/IF provides an internal mechanism to script writers that will take
the rendered image data provided by Layout and cache it locally. This
allows for such procedures as processing image data in multiple passes, or
processing only portions of the image without having to cycle through all
of the data. This mechanism does not necessarily provide speed improvements
to LS/IF scripts; rather it provides convenience to the script writer.
To enable this caching feature, place a call to the following function at
the head of your LS/IF script's process() function:
cache()
this function causes the LS/IF script instance to acquire all
rendered image data into the local memory space of the script to
facilitate multiple accesses to the same data.
Once you have enabled caching, all other LS/IF commands and functions are used
just as though you were performing true filtering. However, these function calls
will be redirected to retrieve and update the local data within the script
instance instead of the data being buffered by Layout.
When caching is enabled, two new functions become available that allow direct
row/column access to pixel data. These functions are only active when and after
the cache() call is made in your Image Filter script.
getpixel(row,col) -> array[4]
this function accepts row and column integer values, specifying
an exact location in the pixel data buffer. it returns
the Red, Green, Blue, and Alpha values at that location.
putpixel(row,col,red,green,blue,alpha)
pixel data can be directly modified using this value. the pixel
values at the specified row and column offset in the pixel
buffer will be altered to reflect the values provided for
the Red, Green, Blue, and Alpha channels.
There is no need to explicitly "flush" the new internal image data once caching is
enabled. The LS/IF plug-in will automatically perform a complete update to Layout
of the modified data when your script's process() function terminates.
LS/IF Logic Flow
Here we will examine the flow of control that passes through a LS/IF script
as it is invoked by LightWave Layout.
The sequence of processing within a LS/IF script will typically begin with
the flags() function. Remember that this function is optional, and if you do
provide a flags() function in your script, then only the Red, Green, Blue and
Alpha-Channel buffers will be available for access later in your process()
function. For the sake of illustration, we call once again upon our space-
consuming flags() function that selects the implicit buffers:
flags
{
return(RED,GREEN,BLUE,ALPHA);
}
If your script is active, Layout attempts to add your processing to the
rendered image by invoking your process() function. This will typically occur
immediately after the image has been rendered, but before it is displayed to
the user or saved to disk. Here is an incomplete process() function that
shows the typical flow of processing that a script will want to duplicate for
each image:
process: width, height, frame, starttime, endtime
{
out[3] = nil; // holds new values passed back to Layout
for(i = 1;i <= height;++i)
{
red = bufferline(RED,i);
green = bufferline(GREEN,i);
blue = bufferline(BLUE,i);
alpha = bufferline(ALPHA,i);
for(j = 1;j <= width;++j)
{
// perform some manipulation on the buffer values
...
setrgb(j,i,out);
setalpha(j,i,alpha[j]);
}
}
}
It should be noted that, whether or not you perform any modifications to a
particular image pixel or Alpha-Channel value, unless you have enabled caching
with a call to cache(), a call to setrgb() and setalpha() (or,
alternately, processrgb()) must be made. As the name implies,
LS/IF is an image filter, and like all filters, things are expected to enter,
while something useful passes through to eventually emerge in the output.
LightWave Layout expects every pixel of the Red, Green, Blue and Alpha-Channel
buffers to pass through this filter in order to generate a complete image. If
you fail to process a pixel into Layout's output--whether or not you altered
its value--then the resulting location in the final image will have an
undefined value RGB (typically, each channel is assigned zeros (0), which
equates to black in the output).
Using The Monitor
Unique among Layout LScript plug-ins, LS/IF provides access to a progress
monitor, quite similar to that offered by Modeler LScript. Because a great
deal of processing can take place inside an Image Filter plug-in (imagine
having to perform some function on each pixel of a 640x480 image for each
frame of animation!), a visual indicator is used to provide feedback to the
viewer concerning the progress of processing.
The following functions are used to manage Layout-provided monitor access.
As you will see, usage of these functions is almost identical to those
provided within Modeler LScript.
moninit(steps)
initializes the monitor system, indicating the anticipated
number of steps required to complete the processing task
monstep([advance])
advances the monitor indicator by the optional integer value
provided. if no argument is provided, then the advance value
is 1
monend()
terminates the monitor system
//// //// //// //// //// //// //// //// //// ////
/// ///
// S T A R T C O N S T R U C T I O N //
/ /
//// //// //// //// //// //// //// //// ////
LS/PT (Procedural Texture)
Procedural textures (or Shaders, as they are commonly referred to) are surface
appearances that are calculated at render-time based upon specific values.
LS/PT is a shader scripting plug-in, and can be used to give a surface a
desired texture or color.
The included example script, Blotch, creates a colored spot on a surface.
Shader Functions
LS/PT contains two of its own specific support functions.
init()
invoked at the start of a sequence of frames. use to
initialize script values that are needed to properly
generate a texture
cleanup()
invoked when a render sequence is complete
newtime(frame,time)
invoked at the start of each new time within the current
render sequence. an integer value 'frame' indicates the
current frame number, while the number 'time' specifies
the current time index
flags()
a LS/PT script needs to indicate to Layout which
attributes of a surface's texture it will modify. one or
more of the following values may be returned from the
flags() function:
NORMAL
COLOR
LUMINOUS
DIFFUSE
SPECULAR
MIRROR
TRANSPARENT
ETA
ROUGHNESS
RAYTRACE
if a LS/PT script intends to utilize the raytrace()
method (discussed presently), then it should include
in the flags() return value the RAYTRACE flag.
Processing Textures
As with all Layout scripts, the processing point of your LS/PT script
is the process() function. The process() function is called on a per-pixel
basis.
LS/PT provides a single argument to your script's process() function.
This argument is an instance of a Object Agent, known as a ShaderObject. This
object contains data members and methods that can be accessed (and in some
cases, modified).
A LS/PT ShaderObject has the following members/methods:
sx (READ-ONLY)
number representing the spot X location in the final
image in pixel coordinates where (0,0) is at the
upper-left corner
sy (READ-ONLY)
number representing the spot Y location in the final
image in pixel coordinates where (0,0) is at the
upper-left corner
oPos[3] (READ-ONLY)
numbers that represent the coordinates of the
spot position in object coordinates
wPos[3] (READ-ONLY)
numbers that represent the coordinates of the
spot position in world coordinates
gNorm[3] (READ-ONLY)
numbers representing the geometric normal of the spot in
world coordinates. this is the raw polygonal normal at
the spot, unperturbed by smoothing or bump mapping
spotSize (READ-ONLY)
number representing the approximate spot diameter. this
is a very approximate value since spots on a surface
viewed on edge are long and thin. this can be used to
compute texture anti-aliasing
raySource[3] (READ-ONLY)
numbers representing the origin of the incoming viewing
ray in world coordinates. often this will be the camera
but it does not have to be
rayLength (READ-ONLY)
a number representing the distance the viewing ray
travelled in free space to reach this spot
cosine (READ-ONLY)
a number representing the cosine of the angle between the
viewing ray and the surface normal at this spot. it
indicates how glancing the view is and gives a measure of
how approximate the spot size is
oXfrm[9] (READ-ONLY)
object-to-world transformation matrix. this can be
computed other ways, but are included here for speed and
are intended to be used primarily for directional
vectors.
wXfrm[9] (READ-ONLY)
world-to-object transformation matrix. This can be
computed other ways, but are included here for speed and
are intended to be used primarily for directional
vectors.
objID (READ-ONLY)
a pointer to an Object Agent that represents the object being
shaded
polNum (READ-ONLY)
an integer that represents the polygon number of the
object being shaded. While this will be the polygon
number for normal mesh objects, it may represent other
sub-object information in non-mesh objects.
wNorm[3]
new geometric normal of the spot in world coordinates.
Modifying this makes the surface look bumpy without altering
the geometry (bump mapping). The shader needs to re-normalize
the vector after perturbation.
color[3]
numbers representing the percentage of the Red [1], Green
[2], and Blue [3] values of the surface color, where 1.0
equals 100%
luminous
a number representing the percentage of luminousity of the
surface (1.0 == 100%)
diffuse
a number representing the percentage of diffusion of the
surface (1.0 == 100%)
specular
a number representing the percentage of specularity of the
surface (1.0 == 100%)
mirror
a number representing the percentage of mirroring of the
surface (1.0 == 100%)
transparency
a number representing the percentage of transparency of the
surface (1.0 == 100%)
eta
a number representing the percentage of the index of
refraction of the surface (1.0 == 100%)
roughness
a number representing the percentage of roughness of the
surface (1.0 == 100%)
To set the perceived color directly, a shader script can set all the
parameters to zero except for luminous which is 1.0 and color which is the
output color of the spot.
ShaderObject Methods
ShaderObject's provide two methods can be used in generating a surface
texture.
illuminate(light,position) -> array[6]
this function returns an array of six (6) numbers that
represent the light ray (color[1-3] and direction[4-6])
hitting the given position from the given light at the
current instant. the return value is zero if the light does
not illuminate the given world coordinate position at all.
the color includes effects from shadows (if any), falloff,
spotlight cones and transparent objects between the light and
the point
raytrace(position,direction) -> array[4]
this function may be called to trace a ray from the a given
location in a given direction (in world coordinates). the
function returns an array of four (4) elements that represent
the length of the ray [1] and the color coming from that
direction [2-4]. the ray length will be -1.0 if it is
infinite. the direction used is the outgoing direction and
must be normalized to be a unit vector
LS/DM (Displacement Map)
The LS/DM plug-in is used to calculate the location of an object's point based
on a given frame and/or time. Unlike LS/IF, whose processing can be
accomplished in a single invocation, a LS/DM script is called on a per-point
basis.
Displacement Functions
LS/DM offers the following displacement-specific functions:
newtime(object,frame,time)
as with LS/PT, this function is invoked at the start of
each new time within the current sequence. the parameters
provided to newtime() are: an Object Agent that represents the
object containing the point to be processed; an integer
representing the frame number; and a number representing the
current time index.
flags()
this function returns (only) one of two possible values, that
indicate whether displacements will take place in world
coordinates (WORLD) or in the object's local coordinates
(LOCAL)
Processing Displacement
The LS/DM process() function is provided with a single argument. This
argument is an instance of a DisplacementObject.
A LS/DM DisplacementObject contains the following data members:
oPos[3] (READ-ONLY)
numbers representing the position of the point
being processed at its origin. these values do not
change, and should be used to calculate offsets based
upon the passage of time
source[3]
numbers representing the new position of the point
being processed for the current frame/time
No methods are provided by the DisplacementObject.
LS/IA (Item Animation)
LS/IA, an Item Animation plug-in, allows you to influence an object's
translations during an animation sequence. You can modify an object's
position, rotation, and scaling, overriding that calculated by Layout.
Processing Motion
LS/IA provides three arguments to the process() function. The second and
third parameters are the integer frame number and numeric time index of the
current invocation. The first argument is an instance of a MotionObject.
The LS/IA MotionObject provides the following object methods:
get(attribute,time) -> vector
this function will return a vector that represents the value
of the specified 'attribute' at the given 'time'. 'attribute'
can be one of POSITION, ROTATION, or SCALING. 'time' is the
time index in which you are interested. in the case of
ROTATION, the values are in degrees. SCALING values
are multipliers, where 1.0 indicates no change.
set(attribute,value)
this function allows you to set the specified 'attribute'
(POSITION, ROTATION, SCALING) to the provided vector 'value'
A LS/IA MotionObject contains the following data members:
objID (READ-ONLY)
a pointer to the Object Agent to which this particular plug-in
has been assigned
LS/OR (Object Replacement)
LS/OR allows you to arbitrarily replace an object in Layout on a
frame-by-frame basis.
Processing Replacements
The process() function of a LS/OR plug-in receives a single argument. This
argument is an instance of a ReplacementObject. The LS/OR ReplacementObject
provides the following data members:
objID (READ-ONLY)
an Object Agent that represents the object whose geometry you
are replacing
curFrame (READ-ONLY)
an integer that represents the frame number for the currently
loaded geometry.
curTime (READ-ONLY)
a number that represents the time index for the currently
loaded geometry.
newFrame (READ-ONLY)
an integer value that represents the frame number for the
next step. new geometry should be loaded if the object needs
to look different at this new frame
newTime (READ-ONLY)
a number that represents the time index for the next step.
new geometry should be loaded if the object needs to look
different at this new time index. 'curTime' and 'newTime'
may not be sequential, since network rendering can cause the
renderer to jump around between non-sequential times
curType (READ-ONLY)
a constant value that indicates the current type of rendering
to be done. the script can provide different geometry for
interactive previewing and actual rendering by examining this
value. this value can be one of NONE, PREVIEW, or RENDER.
NONE is present if no geometry is loaded for the current time
index. PREVIEW indicates that a Layout preview is being
generated, where RENDER is used when a complete render is
being done
newType (READ-ONLY)
a constant that indicates the type of rendering that will
be done at the next frame/time index. this member can be
one of NONE, PREVIEW, or RENDER
curFilename (READ-ONLY)
a string value that represents the object geometry file
currently loaded, and may be 'nil' if there is no geometry
loaded.
newFilename
a string value that represents the filename of a new object
file to be loaded as the geometry for this item at the new
time index, and is the only data member set by the script. it
should only be set if the new geometry differs from that
currently loaded, since loading new geometry incurs
significant overhead
//// //// //// //// //// //// //// //// //// ////
/// ///
// E N D C O N S T R U C T I O N //
/ /
//// //// //// //// //// //// //// //// ////
LS/GN (Layout Generic)
Finally, we come to Layout Generic scripting. LS/GN allows you to access
Layout internal objects and data without the need to be associated with any
scene or scene component. Layout Generic scripts can access all scene
components and settings, as well as all functions and data belonging to
the LScript engine (preprocessor, Requester support, IPC queues, etc.).
Generic Script Construction
Layout Generic scripts are very similar to the format used by Modeler
scripts. There is a single, required function in all Layout Generic scripts,
and this function is called generic(). When a Layout Generic
script is invoked, execution will begin with this function, and when this
function terminates, execution of the script will be complete.
Here is a simple Layout Generic script to report on the number of vertices
in an object currently loaded into Layout:
generic
{
if(!reqbegin("Point Count"))
return; // no Panel Services plug-in
c1 = ctlallitems("Reference object");
if(reqpost())
{
if((item = getvalue(c1)) == nil)
return;
}
else
return;
reqend();
info("Object ",item.name," has ",item.pointcount," points.");
}
Generic Functions
The Layout Generic architecture makes available two functions for managing
Layout scenes:
loadscene(filename[,title])
this function loads the indicated 'filename' as a Layout
scene file. the optional 'title' parameter will be used
to name the scene file internally once it is loaded. this
optional name will then become the scene's new filename.
if this parameter is not provided, the 'filename' parameter
will be used in it's place.
savescene(filename)
this function saves the scene that is currently loaded into
Layout as the provided path and 'filename'.
Next Section
Previous Section
Table of Contents
Index
Errata
© 1996 Virtual Visions, Inc.
© 1997 NewTek, Inc.