************************************************************* Cyber Shadows Creates a "shadow object" on a solid horizontal floor. Cyberplan: Gavin Doughtie 73637,641 Cybertrig: Brad Christie 76167,1461 ************************************************************* How to use Cyber Shadows ------------------------ There are three parts to a shadow: a light source, an object, and a surface that gets the shadow. In Cyber Shadows, the surface must be a flat horizontal object of a solid color. The obect you want shadowed has to be above or resting on the surface. Finally, the light source has to be high enough above the object so that the shadow remains inside the CAD-3D universe. (To create more room for your shadow, just scale down your object and increase the zoom.) Here's what you need to set up before calling the shadow subroutine: 1. An object named "floor". You can use a stretched-out, squashed cube, or the GRID object Tom Hudson created with his FUNCTION.CTL program (it's in the LAMP.3D2 file in the LAMP demo folder). If you're using a custom palette, be sure to use several shades for this object. 2. The object you want shadowed, named "object". (Use the RENAME command if necessary, then after calling the shadow subroutine RENAME it back.) It can be a simple as a cube or as complex as a skeleton, the shadow code doesn't care. Keep in mind, though, that the shadow is a clone of the object, so you need free vertices and faces equal to those used by the object. (But see the Hints section below for a way to get around this limitation.) 3. An object named "lightA", in the position where you want the "A" light source. Any object will do, but for simplicity a small cube works well. If your light is fixed during the animation, just go to CAD-3D, create a cube from the primitives icon/menu, scale it down 50% once or twice, and put it in about the same location as your light source. You don't need to be terribly accurate. If you want to move your light source during your animation, don't use the DIRECT command, but instead move the light object (lightA) using the MOVETO command. (Don't forget that x,y,z for MOVETO are 100x that for DIRECT!) Cyber Shadows will place the A light source for you. 4. Set the variable "Aintense", to a value between 0 and 7. (Try 7 for starters.) This tells Cyber Shadows the brightness to use for light A. 5. Finally, you need to set the value of the variable "Ashadcolr", to tell the shadow code what color to use for the shadow. It should be the same color as the floor, but darker. To figure out what number to use, load your floor object and select the Recolor item from the Colors menu in CAD-3D. Find your floor, and, starting with 1 at the bottom color, count up until you hit the color of your floor, marked with "<". That number is the color of the floor. There should be several darker colors of the same color group (within one of the brackets to the left of the color bars) below the floor color; if not, then change your palette or floor color so that there are. You want to use one of these darker colors for your shadow, so set Ashadclr to something like your floor color plus two. You may need to experiment a bit to find the shadow color that looks the best. After you're set up, making the shadow is simple. It's just one command: GOSUB Ashadow. Your shadow is a new object, named "shadow". Select all your objects, do a superview, and there it is! Helpful Hints ------------- To cast shadows from more than one object, use the RENAME command to coordinate shadow calls. You'll need to RENAME the created shadows as well, or else you'll get a CAD-3D error. For example, code to generate a robot arm shadow might look like: RENAME base,object:GOSUB shadow RENAME object,base:RENAME shadow,shad1 RENAME arm,object:GOSUB shadow RENAME object,arm:RENAME shadow,shad2 RENAME hand,object:GOSUB shadow RENAME object,hand A good way to draw one of these shadow scenes is to generate superviews of floor, shadows, and objects separately, using the VTOBGND command to paste each element on the previous superview. If you have Tom's anti-aliaser desk accessory (see appendix E of your Cyber Control manual) you can make the shadows more realistic by "fuzzing" them with a couple of ANTI commands before adding the rest of the objects. Continuing with the robot arm, this would look like: CLRBGND:BACKGND YES,NO ; make a picture of the floor, move it to the background CLRGRP:SELECT floor:SUPERVIEW:VTOBGND ; add the shadows and fuzz them, move result to background CLRGRP:SELECT shad1,shad2,shadow:SUPERVIEW:ANTI:ANTI:VTOBGND ; finally, add the real objects CLRGRP:SELECT base,arm,hand:SUPERVIEW:ANTI There are routines Bshadow and Cshadow for generating shadows using lights B and C. You will need to set the appropriate variables - Bshadcolr and Bintense for light B, Cshadcolr and Cintense for light C. The size of the shadow is adjusted assuming that the angle between light and object is constant, which is true only for a light a great distance away. If your light object is close to the edge of the CAD-3D universe, Cyber Shadows will assume that you want "outside" lighting (see page 81 of your CAD-3D manual), and will perform the necessary math to simulate a distant light source during shadow generation. However, if your light object is well inside the CAD-3D universe, Cyber Shadows will interpret this as saying you want "inside" lighting. Because of the conflict with shadow sizing, shadows of connected objects (like an object tree) might be disconnected. So, to make good-looking shadows, stick to the rule: - Don't cast shadows of connected objects, such as an object tree, using inside lighting. - If you're trying to make a shadow of a complex object and are running out of room in CAD-3D when the object is CLONEd to make the shadow, you can try the following: 1. Make a .3Dx file containing only your complex object. You'll also need another 3Dx file containing all your objects, if you don't already have one. 2. Find the CLONE command in the Cyber Shadows code (there's only one) and change CLONE to RENAME. 3. Arrange your code to first LOAD3D all your objects, then setup and call Cyber Shadows, then do a SUPERVIEW of only the floor and shadow followed by a VTOBGND command. Now KILL shadow and MERGE3D your .3Dx file containing only your complex object. Finally, with BACKGND YES,NO (or YES,YES for stereo), select all your objects _except_ the floor and do a final SUPERVIEW. Cyber Shadow Trig ----------------- You don't need to understand this section to use Cyber Shadows. It is provided for the more mathematically inclined readers who want an understanding of how Cyber Shadows works. There are two problems to be solved: generation of the shadow and aligning it with the light and object. Let's begin with the first problem and assume for the moment that the light source is directly to the right of the object (xyangle=0). For simplicity, let's use a cube, sitting on the floor, as an object. What we want to do is tilt the cube away from the light, flatten it onto the floor, and stretch it to the correct length. But how much to tilt and stretch? To solve this, it's best to think of the cube shadow as two parts: the part cast by the left face (remember, the light source is to the right), and the part cast by the base. If we lift the cube a fraction of a millimeter and look in the crack, there's the base part of the shadow. Clearly, it's the same size as the base of the cube. The other part we can get from shadangle: Length = height/tangent(shadangle). Now realizing that stretching the shadow doesn't change the _relative_ sizes of its two parts, we can use this information to set up a ratio: Base_shadow/Face_shadow = 1/tangent(shadangle) The tangent of 45 degrees is 1, giving a shadow the same length as the cube face. So far, so good. Now let's figure out the shadow lengths we get by tilting the cube and flattening it. The formulas to use for this are: Base_shadow = base_length*cos(tilt_angle) Face_shadow = face_height*sin(tilt_angle) Since sin(0)=0 and cos(0)=1, no tilt angle gives a full base shadow and no face shadow - we've just flattened the cube into the base. Now substitute these two equations in the one before, and assume base_length = face_height since we're working with a cube, and we get: cos(tilt_angle)/sin(tilt_angle) = 1/tangent(shadangle) or, tangent(tilt_angle) = 1/tangent(shadangle) which is true only if tilt_angle = 90-shadangle. (This property of tangents is also used in the arctangent function below.) Now to calculate the correct amount to stretch, remember that the base shadow of our cube must be the same size as the base. The tilting and flattening shrank it to base_length*cos(tilt_angle), so to restore it we need to divide it by cos(tilt_angle), or sin(shadangle). (Yes, it really helps to know these trig relationships!) The second problem - lining up the shadow correctly with light and object - is a bit easier. If the light source isn't conveniently located where we want it, namely to the right of the object, we'll just rotate light and object until it is, cast the shadow, then rotate object, light, and shadow back to the original angle. Actually, the light doesn't need to be rotated since it's not being operated on, and more processing time can be saved by cloning the object to make the shadow before rotating, and just rotating the shadow. One additional complication: since shadows extend away from rather than towards a light, the tilt angle rotation needs to be negated. Now we need to put the shadow in the correct location with the XLATE command. After all this rotation and stretching, it's no surprise that the shadow doesn't end up right where we want it. But by using an arbitrary rotation point set to the center of the object, we can keep the shadow centered on the object, so at least we know where it is. Now it needs to be lined up with the object. One way to do this is to use a bunch of IF/THEN ALIGN statements, to line up the object depending on the direction of the light source. But there's a simpler way to do it with just one XLATE command. We know the length of the shadow, it's shadow_length = base_length + height/tangent(shadow_angle) or, shadow_length = base_length + height*dx/dz if dx is the x-coordinate difference between light and object, and dz is the z-coordinate difference. Now picture this centered on our object - the amount of shadow extending out the wrong way (towards the light) is the shadow length minus the object length, then divided by two (because there's an equal amount extending out the other side). This is (shadow_length - base_length)/2 = (base_length + height*dx/dz - base_length)/2 = height*dx/(2*dz) which is the amount to move the shadow in the x-direction. (The same formula, but using dy in place of dx, gives the y-displacement.) Here's the trick: since dx is a directed length (i.e., it can be negative), the formula works for any light location above the object. But again, the actual displacement needs to be negated because shadows extend away rather than towards the light. But wait! What about an object that's not sitting on the floor? A shadow directly underneath it isn't going to look right, we hear you say. Okay, this can be fixed by using a ratio: shadow_displacement/height_off_floor = dx/dz Remember that dx and dz are the x and z difference between light and object. (It may help to draw a picture if you're puzzled by this ratio.) So, the amount we need to XLATE is shadow_displacement = height_off_floor*dx/dz and, again, the result needs to be negated. € €À’€€À€@à€@`@€à@—