
- By Sonya
Roberts
In our previous lesson, we looked at the use of the #declare statement and how that allows you to create re-usable objects, and make their construction more flexible. It's even the first step needed for making #include-able objects.
In this lesson, we'll move on to look at how these reusable objects can be given a bit of "intelligence" about their own construction, making it easier to quickly and easily change not just size and texturing (as was done previously) but other major physical characteristics of the object as well. This will be done using the #if...#else...#end group of functions, with the addition of #ifndef for #include-able objects.
We'll start by using the #declare function to set up a sample object that can be variable in it's dimensions...a simple coffee table. The actual example files used throughout this lesson are contained in this file.
// ---- Coffee Table Definition ----
// Uses approx. scale of 1 unit = 1 foot
#declare Width=1.5
#declare Length=4
#declare Height=1.25
#declare Surface=texture{T_Wood7}
object {
union {
box
{<0,Height-.1,0>,<Length,Height,Width>} // Top
box
{<.1,0,.1>,<.25,Height-.1,.25>} // Legs
box
{<Length-.25,0,.1>,<Length-.1,Height-.1,.25>}
box
{<.1,0,Width-.25>,<.25,Height-.1,Width-.1>}
box
{<Length-.25,0,Width-.25>,<Length-.1,Height-.1,Width-.1>}
}
texture{Surface}
}
The coffee table definition involves some simple math to calculate the sizes and positions of the table top and the four legs. These calculations might yield odd results if the dimensions of the table were either too small, or were defined in as negative numbers. We can hope that we'll always remember to define the dimensions correctly - or we can add in some extra code that tests the numbers given and makes corrections as necessary. Let's set it up so that the minimum Width, Length, and Height dimensions allowed are 1, 1, and .5 units, and also test for negative values, switching them back to positive.
// ---- Coffee Table Definition ----
// Uses approx. scale of 1 unit = 1 foot
#declare Width=.5
#declare Length=-3
#declare Height=-1.25
#declare Surface=texture{T_Wood7}
#declare Width=abs(Width)
#declare Length=abs(Length)
#declare Height=abs(Height)
#if (Width<1) #declare Width=1 #end
#if (Length<1) #declare Length=1 #end
#if (Height<.5) #declare Height=.1 #end
object {
union {
box
{<0,Height-.1,0>,<Length,Height,Width>} // Top
box
{<.1,0,.1>,<.25,Height-.1,.25>} // Legs
box
{<Length-.25,0,.1>,<Length-.1,Height-.1,.25>}
box
{<.1,0,Width-.25>,<.25,Height-.1,Width-.1>}
box
{<Length-.25,0,Width-.25>,<Length-.1,Height-.1,Width-.1>}
}
texture{Surface}
}
| BONUS INFORMATION: It's usually a good idea to let the user know when things have been done such as changing values that they have entered. This can be done through the use of a #debug statement. What #debug does is to post a message to the message area during rendering, which the user can then read and choose to fix or ignore. For example, in our code here we might want to say something like the following: Please note that the "\n" at the end of the debug statement is the equivalent of a line feed, it places the message on a line by itself in the message window. There is also a stronger command for use when conditions are detected that mean the entire render should be aborted until the user has dealt with them. It is the #error statement, and is formatted in the same way as #debug. |
Right now our table is very simple and plain. Suppose we wanted to have some optional components of the table, such as cross-bracing for the legs, or even a different style of legs altogether. Again, we can use the #if...#else...#end set to add some more functionality.
// ---- Coffee Table Definition ----
// Uses approx. scale of 1 unit = 1 foot
#declare True=1
#declare False=0
#declare Width=.5
#declare Length=-3
#declare Height=-1.25
#declare LegStyle=2
#declare Brace=True
#declare Surface=texture{T_Wood7}
#declare Width=abs(Width)
#declare Length=abs(Length)
#declare Height=abs(Height)
#if (Width<1) #declare Width=1 #end
#if (Length<1) #declare Length=1 #end
#if (Height<.5) #declare Height=.1 #end
object {
union {
box
{<0,Height-.1,0>,<Length,Height,Width>} // Top
#if (LegStyle=1)
box
{<.1,0,.1>,<.25,Height-.1,.25>} // Legs
box
{<Length-.25,0,.1>,<Length-.1,Height-.1,.25>}
box
{<.1,0,Width-.25>,<.25,Height-.1,Width-.1>}
box
{<Length-.25,0,Width-.25>,<Length-.1,Height-.1,Width-.1>}
#if (Brace)
cylinder
{<.175,Height/2,.175>,<.175,Height/2,Width-.175>,.05}
cylinder
{<Length-.175,Height/2,.175>,<Length-.175,Height/2,Width-.175>,.05}
cylinder
{<.175,Height/2,Width/2>,<Length-.175,Height/2,Width/2>,.05}
#end
#else
box {<.1,0,.1>,<.3,.1,Width-.1>}
//Legs
box
{<Length-.3,0,.1>,<Length-.1,.1,Width-.1>}
box
{<.15,.1,.2>,<.25,Height-.1,Width-.2>}
box
{<Length-.25,.1,.2>,<Length-.15,Height-.1,Width-.2>}
#if (Brace)
cylinder
{<.175,Height/2,Width/2>,<Length-.175,Height/2,Width/2>,.1}
#end
#end
}
texture{Surface}
}
Now we have a coffee table that can appear in any size larger than 1,1.5 with four different possible leg combinations - four plain legs, four plain legs with crossbracing, two slab legs, or two slab legs with a lengthwise brace. At this point, let's do like we did in the previous lesson, and seperate out the definition of the object to a separate #include-able file. We'll now have two separate file - the master file, where the variable are set up, and the #include file, where the object is defined. But what if the user forgets to declare one or more of the variables? How can the #include file be set up to detect and correct for this?
We have a variation of #if available, known as #ifndef, or "if not defined." What we can do is add a series of #ifndef...#else...#end statements at the beginning of our file, which will test to see if the variables exist, create them if they don't, and apply our existing "are the variables valid?" tests to them if they do.
// ---- Coffee Table Definition ----
// Uses approx. scale of 1 unit = 1 foot
#declare True=1
#declare False=0
#declare Width=-1.5
#declare Height=1.25
#declare Brace=True
#declare Surface=texture{T_Wood14}
object {
#include "coffee4b.inc"
}
#ifndef (Width)
#declare Width=1.5
#else
#declare Width=abs(Width)
#if (Width<1) #declare Width="1"
#end
#end
#ifndef (Length)
#declare Length=4
#else
#declare Length=abs(Length)
#if (Length<1) #declare
Length="1" #end
#end
#ifndef (Height)
#declare Height=1.25
#else
#declare Height=abs(Height)
#if (Height<.5) #declare
Height=".1" #end
#end
#ifndef (Surface)
#declare Surface=texture{T_Wood7}
#end
#ifndef (LegStyle)
#declare LegStyle=1
#end
#ifndef (Brace)
#declare Brace=False
#end
object {
union {
box
{<0,Height-.1,0>,<Length,Height,Width>} // Top
#if (LegStyle=1)
box
{<.1,0,.1>,<.25,Height-.1,.25>} // Legs
box
{<Length-.25,0,.1>,<Length-.1,Height-.1,.25>}
box
{<.1,0,Width-.25>,<.25,Height-.1,Width-.1>}
box
{<Length-.25,0,Width-.25>,<Length-.1,Height-.1,Width-.1>}
#if (Brace)
cylinder
{<.175,Height/2,.175>,<.175,Height/2,Width-.175>,.05}
cylinder
{<Length-.175,Height/2,.175>,<Length-.175,Height/2,Width-.175>,.05}
cylinder
{<.175,Height/2,Width/2>,<Length-.175,Height/2,Width/2>,.05}
#end
#else
box {<.1,0,.1>,<.3,.1,Width-.1>}
//Legs
box
{<Length-.3,0,.1>,<Length-.1,.1,Width-.1>}
box
{<.15,.1,.2>,<.25,Height-.1,Width-.2>}
box
{<Length-.25,.1,.2>,<Length-.15,Height-.1,Width-.2>}
#if (Brace)
cylinder
{<.175,Height/2,Width/2>,<Length-.175,Height/2,Width/2>,.1}
#end
#end
}
texture{Surface}
}
Part 2 of the "#if #else #end #ifndif" tutorial
<Crystal Clarity>
<Topas Try Me's> <Povabilities> <Soap Box> <Cranky's
Corner>
<Top> <Home>
<CG Web Board> <Contact>
The Rendering Times: Design and Copyright © 1997 -- DCS & WorkForce Graphics. All rights reserved. Reproduction in whole or in part in any form or medium without the express written permission of DCS and/or WorkForce Graphics is prohibited.