In my previous article, I showed how to set up communication between different scripts in a set of linked prims. In this article I will explore this a little further, and show how to make it more flexible and easier to use.

First, we need a way of finding the link numbers of the prims in a set. Although it is possible to work this out manually, it is tedious and error-prone, and the more prims that are linked, the worse this becomes.

Let’s try an alternative. Give each of the prims a unique name (or at least unique within the link-set). This is probably a useful thing to do anyway.

Once this is done, you can set up variables for the prims that a script is interested in, and then locate the linked prims by name, using llGetLinkName function. Call this when the script is reset or the prim is rezzed.

Here’s a small example:

// This will hold the link number for the prim we
// want to send messages before.
integer LINK_TARGET = -1;
// A function to read the link numbers.
getLinks()
{
    integer i;
    // How many prims are linked?
    integer linkcount = llGetNumberOfPrims();
    // Reset our link target number, just to be
    // safe.
    LINK_TARGET = -1;
    // Work through the prims, looking for our
    // target.
    for (i = 1; i <= linkcount; ++i)
    {
        string str = llGetLinkName(i);
        if (str == "LINK_TARGET_NAME")
        {
            // Found it. Store the link number.
            LINK_TARGET = i;
        }
        // We can obviously extend this to
        // look for and record the link
        // numbers of other prims.
    }
    // If we didn't find our target, report this
    // to the owner.
    if (LINK_TARGET == -1)
    {
        llOwnerSay("Could not find LINK_TARGET_NAME");
    }
}
default
{
    state_entry()
    {
        getLinks();
    }
    on_rez(integer param)
    {
        getLinks();
    }
    touch_start(integer count)
    {
        // Make sure we actually found our target
        // prim.
        if (LINK_TARGET != -1)
        {
            // Send the message to it.
            llMessageLinked(LINK_TARGET, 0, "MESSAGE", NULL_KEY);
        }
    }
}

The only thing to be careful about here is that if you change the link order (by unlinking and re-linking your prims in a different order), you have to make sure that all the scripts are reset.

One convenient way of doing this is to include a RESET command which is sent from the root prim to all the other prims. When they receive this command, they should call llResetScript() to reset themselves:

link_message(integer sender, integer cmd, string param, string id)
{
    // Assume we have defined CMD_RESET somewhere.
    if (cmd == CMD_RESET)
    {
        llResetScript();
    }
}

Now, how about passing different types of parameters, other than simple strings? If you only want to pass a single value, a straight-forward typecast is all that is required. For example, suppose we want to have a message that tells another prim to move to a specific position. To do this, we want to send a vector. We can do this like this:

llMessageLinked(TARGET, CMD_MOVE, (string)<128.0,128.0,128.0>, NULL_KEY);

The receiving prim can convert this back into a vector in a similar way:

link_message(integer sender, integer cmd, string param, string id)
{
    if (cmd == CMD_MOVE)
    {
        vector pos = (vector)param;
        llSetPos(pos);
    }
}

(Of course, I am assuming you have set up a CMD_MOVE variable in both scripts, with the same value in each. It would also be sensible to provide some kind of error-trapping, in case the parameter string does not actually hold a vector. If it doesn’t, you will end up with a vector of .)

What about passing more than one parameter between the scripts? The main trick here is for the sending script to pack the parameters into a string, and then the receiving script uses llParseString2List() to extract the result.

In this example, I am separating the parameters with a semi-colon. Here is the sender’s code:

llMessageLinked(TARGET, CMD_MOVE, "<1.0,1.0,1.0>;Move!", NULL_KEY);

The receiver needs to unpack this, like so:

link_message(integer sender, integer cmd, string params, key id)
{
    if (cmd == CMD_MOVE)
    {
        list parameters = llParseString2List(params, [";"], [""]);
        vector moveBy = (vector)llList2String(parameters, 0);
        string command = llList2String(parameters, 1);
        // Do something with the results
        // ...
    }
}

Note that when extracting the vector, I am extracting the parameter from the list as a string, and then typecasting it to a vector, because the parameter is stored as a string in the list (llParseString2List will extract the contents as string), and llList2Vector will not perform a typecast itself.

By combining the getLinks() function and the ability to pass multiple parameters, you can construct a flexible and fairly robust system for passing information between linked prims.

A final caveat: don’t overdo this. Every script takes up resources. If you have an object with a large number of scripts all communicating with one another you can seriously contribute to lag. If you find yourself doing this, it is worth rethinking how your object is working, and whether there is a simpler way of doing things.

Sooner or later, if you are creating gadgets that do useful things, you will find the need to have some communication between scripts in different prims.

There are two basic methods of doing this. One is to use the llMessageLinked() function, the other is to use a chat channel. In this article I am going to look at using llMessageLinked, but it is important to understand when to use which option.

Let me start, then, by briefly looking at the chat channel option.

The main advantage of this option is that the prims which contain the communicating scripts do not have to be linked. This allows prims to communicate across an entire sim (note that there is no easy way to communicate across different sims short of using an external web-service of some kind).

The main disadvantage, and this is a biggie, is that using a chat channel normally requires the scripts to set up Listeners which are constantly active. This adds to simulator lag, and is something that therefore should be minimised.

If your scripts absolutely need to be run in unlinked prims, or in prims which are in separate objects, however, the chat channel option is probably the only way to go.

However, if your scripts are part of a set of linked prims, the llMessageLinked function is a better option, and it is this option that I am going to cover.

llMessageLinked takes a number of parameters, although you rarely need to make use of all of them. The first parameter is crucial, though, as it is the number of the prim that you are sending the message to. It can also be one of a set of special values, the most useful of which are probably the following:

LINK_ALL_OTHERS – this sends the message to all other prims except the current one.

LINK_ALL_CHILDREN – this sends the message to all prims which are children of the root prim.

LINK_ALL – this sends the message to all the prims in set, including the one that the message is sent from.

The second parameter is an integer. This can be used as an identifier of the type of message. For example, you could set up the following constants in each script:

integer CMD_INIT = 1;
integer CMD_MOVE = 2;	// I'll use this in my examples below

You would then pass the appropriate value to llMessageLinked.

The third parameter is a string. This can be used to pass parameters to the receiving scripts. If you only need one parameter, this is simple. Remember that you can use LSL’s type-casting to let you put (for example) numbers into this parameter. I’ll show an example of this later.

The final parameter is a key.

At the receiving end, the message() function will be called when a message is received from an llMessageLinked() call. It is passed five values, the first of which is the number of the sending prim, and the other four are the four parameters from llMessageLinked().

As an example, lets create a system whereby touching the root prim will move the linked prim. In itself, this isn’t exactly useful, but it could be used as the basis of (for example) some kind of ‘sliding door’ system.

Create two prims, and link them together.

Create a new script in the root prim (note that if you create a script while a link set is selected, the script will automatically be created in the root prim).

In our script, we will have a setting which tells us if the other prim is in its original position. If it is, when the owner touches the root prim, we move the other prim a short distance away. If it is not, we will move it back.

Here is the basic script:

integer hasMoved = FALSE;
float moveBy = 1.25;
// Commands
integer CMD_MOVE = 1;
integer CMD_RESTORE = 2;
default
{
    touch_start(integer count)
    {
        // Only respond to our owner.
        if (llDetectedKey(0) == llGetOwner())
        {
            if (hasMoved)
            {
                // Tell the other prim to restore its original position.
                llMessageLinked(2, CMD_RESTORE, "", NULL_KEY);
                hasMoved = FALSE;
            }
            else
            {
                // Tell the other prim to move by a specified distance. Note
                // that we are type-casting the distance to a string.
                llMessageLinked(2, CMD_MOVE, (string)moveBy, NULL_KEY);
                hasMoved = TRUE;
            }
        }
    }
}

Save the script.

Now, tick the ‘Edit individual prims’ checkbox, and select the other prim. Create a script in this prim. In this script, we will detect the message from the root prim, and respond accordingly:

vector originalPos;
// Commands
integer CMD_MOVE = 1;
integer CMD_RESTORE = 2;
default
{
    state_entry()
    {
        originalPos = llGetLocalPos();
    }
    on_rez(integer param)
    {
        originalPos = llGetLocalPos();
    }
    link_message(integer sender, integer num, string params, key id)
    {
        // Check that this came from the main script.
        if (sender == 1)
        {
            // Find out which command was received
            if (num == CMD_MOVE)
            {
                // Read our local position (i.e. relative
                // to the link-set object)
                vector pos = llGetLocalPos();
                // Adjust it -- note that we can typecast
                // the string parameter to a float.
                pos.x += (float)params;
                // Set the new position
                llSetPos(pos);
            }
            else if (num == CMD_RESTORE)
            {
                // Restore our original position
                llSetPos(originalPos);
            }
        }
    }
}

Save the script, close the Build dialog, and test the object.

You should find that this works, and touching the object will move the second prim. Touching it again will move it back to its original position.

However, there are some problems with this system. For example, we need to know the link number of the prim that we want to send a message to. When there are only two prims (as in our example) this is simple, but if there are a number of prims, it can get difficult to keep track of this (especially if you
unlink and relink the prims while you are building your object, as is quite likely).

Also, the string that we are using to pass a parameter to the linked prim seems a little restrictive.

In the next article I’ll look at both of these issues, and some possible solutions (though as a hint for the parameters, remember that you can typecast a list).

A few months ago I decided it was finally time to ditch Microsoft, and I purchased a MacBook Pro. It’s excellent, and I can’t say that I’ve regretted it in any way.

Except…

There is one application which has caused me some problems, and that is Second Life. What a surprise.

For the benefit of anyone else who is using a MacBook Pro, here are a few notes of things that I have learnt that are of use when running Second Life (these notes apply to Mac OS 10.4 (Tiger) – I don’t intend to update to Leopard until the various issues with it have been fixed. Never buy the first release of anything!).

Nvidia Graphics Card Driver

Recent MacBook Pros use an Nvidia GeForce 8600M GT graphics card. On the Mac, the driver for this graphics card is bugged. Seriously, seriously bugged. Using it will bring your Mac grinding to a halt within minutes, to the extent that only a forced reset (see Emergency Shutdown below) will get you out.

The problem appears to lie with Apple, although there are some question-marks over this. For example, although World Of Warcraft users have reported similar problems, it does not seem to be universal (personally, WOW runs impeccably on my own machine).

There are two possible work-arounds. One is to use a virtual machine with Windows (via BootCamp seems the best option). I have no personal experience with this, but I understand that it works well. I am tempted to try it at some point.

The other work-around is not straight-forward, but it is what I am doing at the moment. The key lies in using an alternative driver, actually for another video card (this seems a somewhat scary option, but I have been doing it for several months without problems).

Being able to specify an alternative driver, however, is not something that comes with the standard Mac OS X install, and is not straight-forward to set up. If you want to go down this route, the following link will take you to instructions on how to do this (it will also give some more inforation about the problem):

MacBook Pro Graphics Freeze Work-around

The downside to this is that some graphic options which should be available will be disabled, because they are not available for this particular driver.

The other downside is that this work-around does not really work under the Windlight version. If Windlight goes live without this graphics problem being fixed, it might meant the end of Second Life for MacBook Pro users.

Keyboard shortcuts

For the MacBook Pro, assuming that you are using the laptop’s own keyboard, here are the key translations you need:

Right-click: Click + Command (Apple) key
Fly up: e or FN + UP
Fly down: c or FN + DOWN
Delete
: FN + Backspace
Debug menus: CTRL+Option+D

Note that even if you have a mouse with a right-click available, this doesn’t seem to work in Second Life on the Mac.

Emergency Shutdown

I’ve never seen this documented by Apple (maybe they don’t like to admit that it would ever be necessary), but my experience with PCs prompted me to try it out, and it does indeed work.

If you ever get into the situation where the Mac completely hangs — the cursor stops moving, there is no response to any key-presses — there is a way to force the Mac to shutdown (being a laptop, of course, just pulling the plug out won’t help — it will switch to battery instead).

Hold down the power button. If the ‘shut-down’ dialog appears, you can breathe a sigh of relief, and shut down normally. If not, keep the button held down. After about 4 seconds the Mac should shut down (with a rather disturbing ‘clink’ on my machine!). You may well find that when you boot up again it takes longer than usual — I suspect that this is because it has noticed the forcible shutdown, and is performing various hardware checks (especially hard-drive checks) to make sure everything is still functioning correctly.

This is not something you want to make a habit of.

Second Life is the only application I have come across which has ever forced me into this situation. No comment!

This is a simple but effective way to create a ‘draped cloth’ effect that can be used as the base texture of (for example) capes or curtains. I’m afraid that this one is specific to the Gimp graphics program, although possibly other programs will have similar features.

Start with an empty picture, at a large size such as 512 x 512, or even 1024 x 1024. I do this with all my textures. Starting large and scaling down usually works well, and sometimes actually improves things by removing or hiding small glitches, whereas it is well-nigh impossible to get good results by starting small and scaling up.

Find the Solid Noise option, under the Filters/Render/Clouds menu.

Set the options so that the X size is set to the maximum, or somewhere near it, and the Y size is set to the minimum, 0.0. You can try experimenting with different values, but you need to be aware that setting the Y size to anything other than the minimum can make it more difficult to create a seamless texture.

You should already see the drape effect.

If you want to increase or decrease the ‘depth’ of the effect, use the Brightness and Contrast — lowering the Contrast will make the effect shallower, increasing the depth (especially in conjunction with decreasing the Brightness) will make the effect deeper.

I would now colorise the texture. Select the Colorise option. Adjust the Hue slider to get the colour you want. Play with the other two sliders to tweak the result.

At this point, the drape will tile horizontally, but probably not vertically. There is a fairly easy way to fix this.

Start by selecting the top half of the image (you don’t have to be exact, but make sure that the top edge is at 0). Feather this fairly drastically, possibly to something like 50 pixels, then copy it. Paste it back in, flip it vertically, then move it down to the bottom, being careful not to move it horizontally.

If you find that the texture does not tile horizontally, you can apply a similar technique to the left and right sides of the texture.

The end result should be tileable. This technique of copying and pasting the top/bottom (and equally the left/right) halves of an image can often be used to make an image tileable if it has right/left or top/bottom symmetry.

Here is an example of the final result:

Drape texture

Sometimes it is useful to be able to change or apply textures through a script. Imagine, for example, a button or switch where you want to change the appearance when the user clicks on it.

There are a number of functions in the LSL library for dealing with textures. In this post I will cover the most basic of them. I’ll go into more details in subsequent posts.

Applying a Texture

Applying a texture to a prim is probably the simplest thing that can be done when scripting textures. You can use the llSetTexture function to do this, which simply needs the texture, and the side to apply the texture to. I’ll discuss prim sides a bit later, but for the example I’ll use the ALL_SIDES constant, which will apply the texture to all sides of the prim.

There are two different ways of specifying the texture. You can either use the name of the texture, or you can use the asset UUID of the texture.

To use the name, the texture must be included in the prim’s contents (just drag the texture from your inventory into the contents list of the prim).

Assume we have a texture called “test”. This script will apply the texture to all sides of the prim when the prim is touched:

default
{
    touch_start(int number)
    {
        llSetTexture("test", ALL_SIDES);
    }
}

Alternatively, we can specify the asset UUID. To find the UUID, right-click on the texture in your inventory, and select the Copy Asset UUID option. You can then paste the result into the script, like so:

default
{
    touch_start(int number)
    {
        llSetTexture("3c8f1c70-671a-4cb6-9f06-58b95c77e6a6", ALL_SIDES);
    }
}

The advantage with using the UUID is that the texture does not need to be in the prim’s inventory, it only needs to exist somewhere in SL’s asset server.

Note that the asset UUID in the above code is a real one, and will get you a “test card” pattern that you can use for testing offsets (see below).

Aside: What happens if you upload a texture into your inventory, get the UUID for it, then delete the texture? Will the texture vanish from Second Life altogether? No, it won’t. Once a texture is uploaded, it is permanently added to the asset server, and deleting it from your inventory has no effect on it — you simply won’t be able to refer to it by name any longer. It will still exist on the server, and you can still use the UUID to refer to it in a script.

Sides

Suppose you want to apply a texture to just one side of a prim. To do this you simply specify the side number:

llSetTexture(“test”, 1);

Ah, but how do you know which side has which number? That’s the tricky bit. Assume that you have just rezzed a cube, and haven’t rotated it in any way. The sides will be numbered as follows:

top: 0
side with lowest y: 1
side with highest x: 2
side with highest y: 3
side with lowest x: 4
bottom: 5

If you hollow the cube, side 5 is the inside (yes, all four interior sides count as a single side), and the bottom becomes side 6.

Working out the side numbers for a rotated cube, or for a more complex prim, gets rather more difficult, and can involve a lot of trial and error. A better way is to use the debug menu. If you don’t have the debug menu displayed, press CTRL+ALT+D to reveal it.

To get information about one side of a prim, tick the ‘Select Texture’ option in the build dialog, select the prim side that you want to know about, then press CTRL+SHIFT+ALT+T. Information about the prim side will be displayed, including the side number.

Scaling and Offsetting

Once a texture is applied, you can scale and offset it using the llScaleTexture and llOffsetTexture functions.

llScaleTexture(0.5, 2.0, ALL_SIDES);

llOffsetTexture(0.5, 0.0, ALL_SIDES);

The horizontal and vertical parameters taken by these functions are exactly the same as those on the texture tab of the build dialog, so you can use the build dialog to help find the appropriate values.

If you have already worked with textures you will know that a scaling of 1.0 x 1.0 will fit the texture to the size of the prim, whereas higher values will tile the texture, and lower values will only display part of the texture.

For example, a value of 0.25 will display one quarter of the texture, stretching it to fit the prim. Which quarter of the texture is actually displayed depends on the offset, and the way in which the offset works is not immediately obvious.

Basically, the offset is from the centre of the texture. An offset of 0.0 x 0.0 will therefore centre the texture. How other offset values affect the texture is easier to explain using an actual example.

Here is the testcard texture which I mentioned above, applied initially with an offset of 0.0 x 0.0:

Test Card example 1

If you change the horizontal offset to 0.25 you get this:

Test Card example 2

Try changing the horizontal scaling to 0.25, and the horizontal offset to 0.0. This produces the following, which is actually displaying the centre of the scaled texture, showing half of one band of colour, and half of the other.

Test Card example 3

To offset it so that we are centred in a band of colour, we need to use an offset of 1/8, or 0.125. Set the horizontal offset to this value, and we get a single band.

Test Card example 4

To centre each band in turn, use the following offsets:

-0.375
-0.125
0.125
0.375

Obviously, this only works when the horizontal scale is 0.25.

Using scaling and offsetting to select just one portion of a texture can help to make more efficient use of textures, especially if you have a prim which needs to sometimes change appearance — you can pack the different images into a single texture, and select the appropriate part of the texture using the scale and offset. The alternative method is to have multiple textures, but this means that when the texture is changed, there is a delay while the new texture is loaded. Using the scale and offset method, the texture is already fully loaded, and the prim changes appearance almost instantly.

I’ll cover this more in a later post.

Links

You will find a lot of useful information about the texture-handling functions on the LSL Wiki:

LSL Wiki

Arcana Nuevo

I thought I’d start the new year with an introduction to a place that I’ve been intending to blog about for a while, but haven’t got round to, at least until now. I was introduced to it by Saffia Widdershins of PrimPerfect magazine (thanks, Saffia!).

I’ve never played any of the Myst series of computer games, but I’ve seen plenty of screen-shots from it, and once played through part of a demo, so I’m quite familiar with famously attractive look of it.

Unsurprisingly, there have been attempts to recreate that look in Second Life (the creators of Myst themselves did, but only temporarily). This site, Arcana Nuevo, owned and created by Angelica Zuma, is one of the most successful that I’ve seen.

When you teleport in, you land at the telehub beside the shop (where you can buy furniture in the same style as the main building). Walking through the shop and out the other side, you come to the steps that lead up to the imposing entrance:

From here you walk through a corridor beneath a waterfall, leading into the main bulk of the castle. There is plenty to see and explore, and I’ve put together a Snapzilla photo album of some of the scenic views (see the links at the bottom of the post).

One notable highlight, at least for me, is the small ‘office’ that you find at one end of a corridor near the entrance. Apparently this is based directly on one of the locations in Myst:

The castle is definitely one of the places in Second Life that deserves to be visited.

Links

Photo Album

SLURL for Arcana Nuevo

Holly wreathI know from my blog stats that I have a steady and slowly rising number of readers, so to all of you who have been following my blog over the past months, thanks for being there and giving some point to my ramblings.

I hope you have a very merry Christmas, and I’ll be back when the festivities are over.

Enjoy.

In my previous blog entry about creating a HUD, I briefly mentioned that it was possible, but not necessarily easy, to have dynamic output on a HUD.

Here is a relatively simple way of doing this, along with a script that makes use of the technique. It relies on three simple facts relating to the floating text that can appear above a prim. First, this text still appears even when the prim is used in a HUD; second, it is then only visible to the wearer; and finally, the floating text can have multiple lines. We can use this to create a screen display for the HUD.

As an example, let’s create a ‘green-screen’ monitor for a HUD. Create a basic HUD window (a simple block prim), and add two more prims, one directly above the other. The upper prim will provide the background, the lower prim will generate the text.

Set the upper prim’s color to black, and size it to something suitable (the actual size depends on the number of lines of text you will be displaying, so some trial and error is probably required). Link the prims, and attach the result as a HUD. See my previous article if you need more details about creating a HUD.

Now we need a script to generate our dynamic text. The following script implements a scrolling display, and adds a line to the display every time the owner clicks the text prim (just as a demonstration). Create a new script in the lower prim, and copy the script into it, replacing the default script.

The result should look something like this:

integer linePos = 0;
list lines;
integer listLength;
vector textColor = ; // Green
init()
{
    clear();
}
clear()
{
    lines   = ["", "", "", "", ""];
    listLength = llGetListLength(lines);
    linePos = 0;
    updateDisplay();
}
setLine(integer lineNo, string lineText)
{
    // If the requested line number is past the end of
    // the list of lines, scroll the lines.
    if (lineNo > listLength)
    {
        lines = llList2List(lines, 1, listLength - 1);
        lines += "";
        lineNo = listLength - 1;
    }
    lines = llListReplaceList(lines, [lineText], lineNo, lineNo);
    updateDisplay();
}
updateDisplay()
{
    string output;
    integer i;
    integer count = listLength;
    for (i = 0; i < count; i++)
    {
        output += llList2String(lines, i) + "\n";
    }
    llSetText(output, textColor, 1.0);
}
addLine(string lineText)
{
    setLine(linePos, lineText);
    if (linePos < listLength)
      linePos++;
}
default
{
    state_entry()
    {
        init();
    }
    touch_start(integer count)
    {
        // This is just a dummy example of how to update
        // the display. When the owner touches the prim
        // we will add a message to the display. We'll
        // check that it was the owner who touched us,
        // although that isn't really necessary if this
        // is in a HUD. 
        if (llDetectedKey(0) == llGetOwner())
        {
            addLine("Touched at " + llGetTime());
        }
    }
    on_rez(integer param)
    {
        init();
    }
}

Shopping malls are two-a-penny in Second Life. In fact, in some places it’s hard to move without finding yourself in another mall. Most of them, let’s face it, are badly designed, or even not designed at all, being little more than a motley collection of stores all jumbled together.

There are exceptions. Pixel Dreams, owned and created by Tya Fallingbridge, is one of them. From the very first glimpse that you get, you can tell that this is something a little different, a little more stylish than the usual mall:

First glimpse of Pixel Dreams

Rather than a disparate collection of differently designed shops, Pixel Dreams shares the same basic ‘look’ throughout. The Girls’R’Us shop adds an appropriate dash of pink (!), but the rest of the shops share a similar black and white color scheme. The interiors are more varied, but still equally attractive:

Pixel Mode interior:

Pixel Mode

And when you have finished your shopping, you can dance the night away at Pixel Dream’s own dance club, Schmooze:

Schmooze

There are more pictures of Pixel Dreams in my Snapzilla photo-album — see the link below.

Links

Photo Album

SLURL for Pixel Dreams

I’ve done a number of posts now about scripting, so maybe it’s time to move on to a new subject. I’m going to assume (as I did with scripting) that you are already familiar with the basics of texturing in Second Life, and also that you are probably familiar with a suitable graphics package for creating or adjusting textures.

Recently I’ve started experimenting with drop-shadows, and on reading Iris Ophelia’s article in New World Notes I see that I am not the only one. Drop- shadows are evidently the new thing!

But what is a drop-shadow, and why would you want one? An illustration is in order. Here is a snap-shot of one of the rooms of my SL home, Morgridge Mansion:

Morgridge Mansion without shadows

The key thing to note is that in real life there would be an element of shadowing beneath the objects (especially the chairs and the table). Let’s add this in Second Life:

Morgridge Mansion with shadows

Much better. A nice bit of added realism (to be honest, I’ve slightly overdone some of the shadowing, just to make it stand out for this illustration). You’ll notice that I’ve also added a shadow behind the portrait on the wall.

So…how is it done?

Well, I don’t know how other people do it, but I’ll explain how I achieved the effect.

The first thing you need is a shadow texture. For the Mansion I created two textures, one circular, and one square. I won’t give exact details on how to do this, because they depend on which graphics package you use (personally I use The Gimp, which is free, powerful). If you aren’t familiar with creating textures, I’ve included links to my own shadow textures, which you can feel free to copy and use — see the bottom of this post.

If you want to try creating your own shadow texture, these are the steps that I took. Translate them to suit your own graphics package:

I used a 128×128 graphic (shadows don’t need a high-resolution, so this size is perfectly adequate) with transparency. I then selected an area about 3/4 of the size of the entire graphic, feathered it to about 25 pixels (you can play about with this — it will determine how quickly your shadow ‘fades out’ towards the edges), and used a blend fill of black to dark gray to fill the area. The end result (in both square and circular versions):

(To be honest, I’m not happy with the square version, which has something of an ‘X’ effect to it. More work required, methinks.)

Ok, now we’ve got our texture, how do we apply this in Second Life?

Start with a new prim — cube for square shadows, cylinder for circular shadows. Resize the Z-scale to the minimum, 0.01, and adjust the X and Y scales until the prim is slightly larger than the object that you want to shadow (if you are adjusting the prim using the ‘grab handles’ rather than entering numbers into the dialog, you probably want to scale the X/Y size first, before minimising the Z scale).

You now need a completely transparent texture. There is a transparent texture in the default library, but unfortunately it is not completely transparent, and will leave you with an ugly white edge. I’d avoid it and use your own texture. If you don’t have a fully-transparent texture, I’ve included a link to mine at the bottom of this post.

Apply the texture. Then select the ‘Edit Texture’ option from the build dialog, and select the top surface of the prim. Apply the shadow texture to this surface.

Move the prim so that it is directly beneath the object that is to be shadowed.

On the Features tab of the build dialog, adjust the transparency. The higher the transparency, the more subtle the shadow. I’ve found that a value of between 40 and 60 seems to work best. Experiment.

Link the shadow prim to the main object, and you’re done.

And finally

The transparency of the shadow prim affects the darkness of the shadow, and the best value to use depends on where the object is located. It would be handy to give the owner of the object a way of adjusting this. Here’s a simple script that does just that. Drop this script into the shadow prim. Each time the owner clicks on it, the transparency will increase by 10 (fading the shadow). When the transparency reaches 100, the next click will return it to 0 (completely black):

// Default transparency value. Change to suit.
float transparency = 50.0;
// Amount to change transparency on each click.
float changeBy     = 10.0;
default
{
    touch_start(integer count)
    {
        // Only allow the owner to change the shadow.
        if (llDetectedKey(0) == llGetOwner())
        {
            // Adjust the transparency value.
            transparency = transparency + changeBy;
            if (transparency > 100.0)
            {
                transparency = 0.0;
            }
            // Apply the new value to the prim. llSetAlpha
            // works in reverse to the Transparency value
            // in the build dialog (!), so we'll subtract from
            // 100 to make them match.
            llSetAlpha(1.0 - (transparency / 100.0), ALL_SIDES);
        }
    }
    changed(integer change)
    {
        // Reset the script when the owner changes,
        // otherwise llGetOwner() might return the
        // wrong value.
        if (change & CHANGED_OWNER)
        {
            llResetScript();
        }
    }
}

Downloadable textures

Circular shadow texture

Square shadow texture

Fully-transparent texture