How to create 2D image and 3D procedural texture definitions
How to layer two or more textures on a single surface
How to use spherical environment mapping
How to use cubical environment mapping
How to tile a bitmap image across the background
How to add texture coordinates to polygonal data
In this tutorial we will demonstrate various ways to apply 2d bitmap
images and 3d procedural textures to objects. It is recommended that you first read the
previous overviews and tutorials before continuing with this tutorial.
For this example we will create a scene with 16 spheres in it, each
linked to 16 different surface definitions. These are illustrated in the following image:
Each sphere in the previous image demonstrates different texturing
methods. The following table describes each sphere, starting from the lower-left sphere
and proceeding to the right then upwards:
Sphere # 1
shows the simplest form of 2d texture mapping. A checkerboard texture
is mapped around a sphere using the sphere's built-in u/v texture coordinates.
Sphere # 2
demonstrates bump mapping. The same checkerboard texture bitmap is
used to add bumps to the sphere where the texture changes between black and white (the
bumps may not be obvious in the image).
Sphere # 3
combines the texture mapping of Sphere # 1 and the bump mapping of
Sphere # 2 (the bump mapping may not be obvious in the image).
Sphere # 4
demonstrates opacity mapping. The same checkerboard texture bitmap is
used to modulate the opacity of the surface. The sphere is transparent where the texture
image is black and opaque where the texture image is white.
Sphere # 5
demonstrates spherical environment mapping. A bitmap image of a
fireplace is used to simulate a gold surface.
Sphere # 6
demonstrates cubical environment mapping. The sphere reflects 6
images that are mapped to the faces of a cube (the sphere shows the fireplace image, the
checkerboard image, and the image used for the background).
Sphere # 7
demonstrates how to use the orthographic texture parameterization
method to add new texture coordinates to an object. In this case the sphere's built-in u/v
texture coordinates have been overridden with new front-on projected coordinates. Note how
the texture appears to be projected square-on.
Sphere # 8
demonstrates how to use the cylindrical texture parameterization
method to add new texture coordinates to an object. In this case the sphere's built-in u/v
texture coordinates have been overridden with new cylindrically projected coordinates.
Compare this sphere to the lower-left hand corner sphere (the checker pattern does not get
compressed in the vertical direction for sphere # 8).
Spheres # 9 through # 15
demonstrate 7 different 3D procedural texture functions. These
textures are computed on-the-fly rather than texture mapped from a bitmap image.
Sphere # 16
demonstrates how two (or more) textures can be layered on top of each
other. The first layer is the checkerboard bitmap image and the second layer is the 3d
procedural marble shown in sphere # 9.
Adding texture to an object is a three step process. First, a texture
definition is created which specifies the arguments to a 2D image texture or a 3D
procedural texture. Second, the texture definition is linked to a surface definition. And
third, the surface definition is linked to an object or instance.
The first of these two steps is illustrated in the following simple
C code example which is used for Sphere # 1. The command is used to create a new 2d image
texture definition called 'checker bitmap texture' which references the TIFF
image file 'check256.tif'; MIPmap filtering is also enabled to produce good
filtering results (this is the default).
A surface definition is then created and the texture definition is
linked to it via the Nt_TEXTURELINK sub-option. One or more texture definitions can
be layered upon a single surface, but for this example we only have one layer called
"layer 1''. The sub-options of the Nt_TEXTURE option specify the u/v
offset and u/v scaling of the texture; these allow the referenced bitmap image to be
scaled and moved about in u/v texture-space. For this example we have set the scaling
values to be 0.25 which will cause the bitmap image to repeat 4 times in the u and v
directions on the sphere.
When Sphere # 1 is rendered the checkerboard bitmap image will wrap
around the sphere 4 times in the horizontal direction (the u direction) and 4 times
in the vertical direction (the v direction). If the Nt_WRAPU and/or Nt_WRAPV
options of the command shown in the previous C code were to be set to Nt_OFF then
the texture would not repeat in the u and/or v directions.
Note that this code assumes that the object(s) being texture mapped
already have u/v texture coordinates assigned to them. This is always true for the
built-in primitives provided with NuGraf (such as the sphere primitive), but it may not be
the case for user-supplied raw polygonal data. In such cases you will have to add u/v
texture coordinates to the data (see examples described later in this tutorial).
Sphere # 2, is similar to Sphere # 1 except that the checkerboard
bitmap image is used to bump map the sphere rather than change its color. NuGraf allows a
2d bitmap image to modulate the color of a surface, its bumpiness and/or its
opacity (any combination of these can be enabled in each texture layer). The modulation
source is set with the Nt_MODULATE sub-option, as shown in the following C code
snippet which disables color modulation and enables bump mapping modulation. The Nt_MULTIPLIER
keyword is used to set the amount of bump mapping in the u and v directions; good values
range between -1.0 and 1.0 (flipping the sign between positive and negative will make the
bumps either protrude up or down on the surface). NOTE: there are several other
sub-options to the Nt_TEXTURE option which are not described in this tutorial.
Sphere # 3 combines both color modulation and bump mapping
modulation. We will not duplicate the C code here since only the 'Nt_MODULATE,Nt_COLOR'
sub-option changed from the last snippet above.
Sphere # 4 makes interesting use of opacity mapping. This form of
texture mapping uses the intensity from a bitmap image to change the opacity (or,
inversely the transparency) of a surface. The surface will be opaque where the image is
bright and transparent where the image is dark. A bitmap image can be made to modulate a
surface's face opacity and/or its reflected opacity (for highlights and reflections). The
following C code shows how to enable face and reflected opacity mapping.
Sphere # 5 demonstrates how to use spherical environment mapping.
This is a cheap version of ray tracing in which an imaginary sphere covered with a 2d
bitmap image is placed about an object which is to be mapped. Rays from the camera's
look-from location are bounced off the object and intersected with the imaginary sphere;
the bitmap image is sampled where the ray hits the sphere and the resulting color is used
as the object's surface color.
The following C code illustrates how to simulate highly reflective
gold with the use of a 2d bitmap image of a fireplace. The Nt_TEXTUREIMAGE command
is used to define the texture image, and the Nt_CROPWINDOW sub-option is used to
define a sub-region of the texture image which is to be used (some of the black parts of
the fireplace image are cropped out).
The Nt_SPHENVMAP option of the command is given to add a
spherical environment map to the surface. The Nt_REFLECTCOEFF sub-option is a
multiplier which controls the intensity of the spherical environment map added to the
final pixel color; it ranges from 0.0 to 1.0. In order to simulate chrome or highly
reflective gold we set the ambient & diffuse shading coefficients to 0.0 since chrome
is like a mirror surface and hence has no ambient or diffuse shading. We also set the Nt_REFLECTCOEFF
value to 1.0 so that all of the surface color comes from the spherical environment map.
This example also illustrates how to rotate the imaginary sphere relative to world-space
with the 'Nt_ROTATE,Nt_YAXIS' sub-option; this sub-option allows the
spherical environment map to be rotated so that the texture seam can be moved behind the
object being textured.
Sphere # 6 demonstrates how to use cubical environment mapping. This
is another cheap version of ray tracing in which an imaginary box covered with 6 bitmap
images is placed about an object which is to be mapped. Rays from the camera's look-from
location are bounced off the object and intersected with the imaginary box; one of the 6
bitmap images is sampled where the ray hits the box and the resulting color is used as the
object's surface color.
Cubical environment mapping is enabled with the Nt_CUBICALENVMAP
option of the Ni_Surface command. NOTE: No texture definitions are
required to use cubical environment mapping. The bitmap images to be assigned to the six
cube faces are specified with the Nt_FRONT, Nt_BACK, Nt_LEFT, Nt_RIGHT,
Nt_TOP and Nt_BOTTOM sub-options; at least one bitmap image must be
specified. Any arbitrary image can be assigned to the different faces but in general you
will probably assign six prerendered images of the scene surrounding the object to the six
faces (this will simulate fairly accurate ray tracing).
This example also sets the ambient and diffuse shading coefficients
to 0.0, and the Nt_REFLECTCOEFF to 1.0; this will simulate a highly reflective
surface.
Sphere # 7 demonstrates the concept of texture parameterization.
Texture parameterization provides a mechanism by which new u/v texture coordinates can be
added to an object or instance in a fairly simple manner. Normally this mechanism would be
used to add u/v texture coordinates to raw polygonal data which doesn't have any existing
u/v texture coordinates, but it can also be used to override the predefined u/v texture
coordinates of NuGraf's built-in primitives; we will demonstrate the latter by overriding
the sphere primitive's built-in u/v texture coordinates with new ones which have a
different mapping behaviour.
For the following example we will use the orthographic
texture parameterization method in which an imaginary texture-mapped two-dimensional plane
is oriented in front of the sphere and the texture projected front-on towards the sphere.
The projected u/v coordinates become the new u/v coordinates for the sphere. The
two-dimensional plane is specified using 3 points in the sphere's primitive-space
coordinate system; the plane is sized to be the same width and height as the sphere, and
oriented so that it encompasses the entire sphere.
The final result in shown as Sphere # 7 in the large image at the
start of this tutorial. Note how the checkerboard image appears to be projected front-on
in a direction perpendicular to the page.
{
/* Orthographic texture parameterization variables */
Nd_Vector txtrparam_ortho_origin = { -1.0, -1.0, 0.0 };
Nd_Vector txtrparam_ortho_upoint = { 1.0, -1.0, 0.0 };
Nd_Vector txtrparam_ortho_vpoint = { -1.0, 1.0, 0.0 };
/* This statement creates new texture coordinates for the */
/* seventh sphere by overriding the sphere's built-in u/v */
/* texture coordinates with new coordinates created by a */
/* front-on orthographic projection method. */
Ni_TxtrParam(Nt_INSTANCE, "sphere instance 7",
Nt_MODEL, Nt_ORTHOGRAPHIC, Nt_CMDSEP,
Nt_ENABLED, Nt_ON, Nt_CMDSEP,
Nt_COORDSYSTEM, Nt_PRIMITIVE, Nt_CMDSEP,
Nt_ORIGIN, (Nd_Vector *) txtrparam_ortho_origin, Nt_CMDSEP,
Nt_UPOINT, (Nd_Vector *) txtrparam_ortho_upoint, Nt_CMDSEP,
Nt_VPOINT, (Nd_Vector *) txtrparam_ortho_vpoint, Nt_CMDSEP,
Nt_CMDEND);
}
Likewise, Sphere # 8 demonstrates the cylindrical texture
parameterization. For this example an imaginary cylinder has been oriented around the
sphere such that their vertical axes are coincident and the height of the cylinder has
been set equal to the height of the sphere.
Note the differences between the checkerboard mapping for Sphere # 1
and Sphere # 8 on the large image at the start of this tutorial. The main difference with
Sphere # 8 is that the checkerboard squares have equal heights in the vertical direction;
this is due to the cylindrical texture parameterization.
We will not demonstrate the spherical texture parameterization
method since the mapping produced will be the same as the sphere primitive's built-in u/v
texture coordinate mapping.
{
/* Cylindrical texture parameterization variables */
Nd_Vector txtrparam_cyl_origin = { 0.0, -1.0, 0.0 };
Nd_Vector txtrparam_cyl_upoint = { 1.0, -1.0, 0.0 };
Nd_Vector txtrparam_cyl_vpoint = { 0.0, 1.0, 0.0 };
/* This statement creates new texture coordinates for the */
/* eighth sphere by overriding the sphere's built-in u/v */
/* texture coordinates with new coordinates created by a */
/* cylindrical projection method (aligned with Y axis). */
Ni_TxtrParam(Nt_INSTANCE, "sphere instance 8",
Nt_MODEL, Nt_CYLINDRICAL, Nt_CMDSEP,
Nt_ENABLED, Nt_ON, Nt_CMDSEP,
Nt_COORDSYSTEM, Nt_PRIMITIVE, Nt_CMDSEP,
Nt_ORIGIN, (Nd_Vector *) txtrparam_cyl_origin, Nt_CMDSEP,
Nt_UPOINT, (Nd_Vector *) txtrparam_cyl_upoint, Nt_CMDSEP,
Nt_VPOINT, (Nd_Vector *) txtrparam_cyl_vpoint, Nt_CMDSEP,
Nt_CMDEND);
}
The last two rows demonstrate 3D procedural texture mapping
in which the texture color is computed as a function of (x,y,z) location on an object
using a small C program built-in to NuGraf. 3D procedural texture mapping is easier to use
than 2d image texture mapping since no u/v texture coordinates are required to apply the
texture.
Creating a 3D procedural texture definition uses the same process as
described above except that the Nt_PROCEDURAL option is specified to the command
rather than the Nt_IMAGE option. There are 42 separate procedural texture functions
that can be selected, each of which generates a different type of texture such as wood,
clouds, bumpy surfaces and other interesting effects. The texture function is selected for
a texture definition with the Nt_NAME sub-option.
Each texture function also takes zero of more sub-options such as Nt_FREQUENCY
which sets the starting noise frequency, Nt_NUMOCTAVES which sets the number of
octaves of Perlin noise to use, Nt_PARAM1 through Nt_PARAM6 which set the
local parameters used by each function, and Nt_COLOR1 through Nt_COLOR3
which set the colors used by each function. All of these parameters are optional and are
specific to each procedural function chosen.
The following example creates a texture definition which uses the 'marble2'
procedural texture function. The Nt_FREQUENCY and Nt_NUMOCTAVES sub-options
are also specified but these usually don't have to be given. The texture is assigned to
Sphere # 9.
Sphere # 10 uses a 3d procedural bump map function. Rather
than modify the surface color this procedural function perturbs the surface normal with
the end result that the rendered surface appears to be bumpy.
The following C code uses the 'bump' procedural texture
function. The Nt_PARAM1 parameter is used to scale the intensity of the resulting
bumps; values of 2.0 or smaller produce acceptable results. The C code also shows how to
scale a procedural texture globally so that its features appear larger or smaller on the
textured surface; since procedural textures are computed using absolute (x,y,z)
coordinates in texture-space, linear transformation can easily be applied to the texture
definition. In this example the bump function is scaled smaller so that more bumps appear
on the surface. NOTE: linear transformations can also be applied to 3d procedural textures
on a per-surface basis (see ).
We will not bother to describe the remaining 5 procedural texture
functions shown in the image since they are just variations of those applied to Spheres #
9 and # 10. Please refer to the C program listing at the end of this tutorial for an
explanation of these remaining functions.
The last sphere, Sphere # 16, demonstrates how to layer two or more
textures on a single surface. This is achieved by specifying two Nt_TEXTURE
options, each with a different unique identifier label ("layer 1'' and
"layer 2''). Each layer references its respective texture definition. The
only difference between the two texture layers is that layer 2 specifies the Nt_COLORBLEND
sub-option; this sets the amount of color mixing that will occur between the computed
texture color of layer 1 and the computed texture color of layer 2.
To mix face or reflected opacities, use the 'Nt_MIX,Nt_FACEOPACITY'
or 'Nt_MIX,Nt_REFLECTOPACITY' sub-options.
And lastly, we will demonstrate how to tile a bitmap image across
the background. This is achieved by defining a 2d image texture definition which
references the desired bitmap image, then assigning the texture definition to a new
surface definition, and finally referencing the new surface definition with the 'Nt_COLORSCHEME,Nt_SURFACELINK'
option of the command.
This will produce the same results as if a polygon were placed flush
with the far clipping plane and textured. Texture coordinates (0,0) are the lower-left
corner of the screen and (1,1) are the upper-right. All 2D texturing commands apply
(scaling, cropping, offsetting, etc). Note that the image to be mapped onto the background
does not have to be the same size as the output image.
The Nt_FILTER option of the command determines which form of
filtering is to be used when magnifying or compressing the bitmap image on the background.
Selecting Nt_POINTSAMPLE will use no filtering and will produce the fastest results
with acceptable quality if the bitmap image is relatively the same size as the background
area. Selecting Nt_MIPMAP will use MIPmap filtering which is good when the bitmap
image is much larger or much smaller than the background area.
The Nt_WRAPU and Nt_WRAPV wrap-around sub-options
specify whether the bitmap image is to repeat in the u and v directions when the Nt_USCALE
and Nt_VSCALE parameters are less than 1.0. They are set to Nt_ON by
default. For example, if the Nt_USCALE and Nt_VSCALE parameters are set to
(0.5,0.5) and these wrap-around sub-options are set to Nt_OFF then the bitmap image
will only fill the lower-left quarter of the display. If these sub-options are set to Nt_ON
then the bitmap image will tile the background 4 times.
The bitmap image can be scaled by changing the values specified to
the Nt_USCALE and Nt_VSCALE parameters. If you want the bitmap to tile the
background several times then set the Nt_WRAPU and Nt_WRAPV enables to Nt_ON
and set the scaling parameters less than 1.0 (set them to 1.0 divided by the repeat
count). If they are set greater than 1.0 then only a portion of the bitmap image will
appear.
The Nt_UOFFSET and Nt_VOFFSET parameters can be used
to move the origin of the bitmap around on the background. For example, setting them to
(0.5, 0.5) will move the bitmap so that its lower-left corner is in the middle of the
display.