.comment-link {margin-left:.6em;}
Moriash Moreau: My Second Life
Friday, August 31, 2007
 
CyberExtruder
Recently, I dropped by the CyberExtruder on Avatar Island, in order to try and upgrade my skin. In order to obtain your own custom head, your avatar must take a trip through the CyberExtruder 500. This is a rather nifty bit of showmanship, taking your av through various processes to supposedly mold and model the new mask around your old avatar head. Really quite slick. They put on a good show.


I say "supposedly" because the whole operation (which takes a minute or two) is merely eye candy. I took a ride through the noise, particle, and shiny-bedecked contraption, as you can see above. The end result was that I was presented with a unique key number and a URL for the CyberExtruder website. From there, I was asked to upload a "passport photo" style photograph. They had many tips on the website, but basically you're encouraged to conceal any hints of life or personality. Don't smile, don't wear glasses, keep your hair out of your eyes... Basically try as hard as possible to look like that driver's license photo taken after a four hour wait at the DMV. Once said death mask is uploaded, the CE site processes it and presents you with a preview of the image as a 3D model.


Alas, it seems that a photo-sourced SL skin of myself is not in the cards for me. The website does give you a chance to reject the uploaded photo and try again. My problem was that I would have needed a new head.

While I was reasonably happy with the eyes and nose (considerable appearance slider tweaking would have still been required to get the shape right, an expected and not unreasonable task), the mouth and beard were deal breakers. I don't quite know what my problem was with the mouth. Upon closer inspection of my mugshot, it's clear that my whole face is ever-so-slightly crooked. And, evidently, the process magnified this imperfection. Not so good for one's self esteem, really.

I would have tried again, perhaps getting someone else to take the picture and coach me in getting my facial features held symmetrical in the photo, but my RL beard was a more serious problem. By its very nature, the single-photo-sourced CyberExtruder process cannot deal with full beards. Details are cropped off at the sides of the face, as they aren't directly visible in the head-on mugshot. Instead, the beard simply fades off into a smooth, generic skin tone match. This process seems to work fine for normal, clean-shaven faces (or those with front-heavy facial hair), but I expect that a live artist, multiple camera views, and probably quite a few US bucks would be required to faithfully model my head.

Ah, well, I think I can deal with my current skin for a while longer.
Sunday, August 26, 2007
 
Roto-Tracker
Yesterday evening, I blitzed through a small, artsy project. Basically, it's a primitive drum loop tracker, allowing the user to pick out simple repeating patterns with various percussion instruments.

Note: I don't really know anything about MIDIs, MODs, or related software. And I haven't thought seriously about the mechanics of making music since childhood piano lessons and chorale in high school. Any relationship between terminology and technical correctness is therefore purely coincidental.


The concept is fairly straightforward. A central physical rotor smoothly turns (counterclockwise) through 360 degrees, using llTargetOmega. Spaced out over 180 degrees (22.5 degrees apart) are eight collision sensors (shown as white columns of light), which use filtered collision events and llVolumeDetect to sense the passing of the rotor. Each time the rotor passes through the sensor's volume, the light briefly flickers off (as if the rotor is blocking it- a superfluous effect, but kind of neat) and the selected sound sample is played. The rotor moves on, the next sample is played, and so on.

Each collision sensor comes loaded with 15 drum sounds, including various tom-toms, a bass drum, a taiko drum, a snare, a couple of cymbals, some wood blocks and, of course, a cow bell. The user cycles through the sound samples by clicking on the base of the lights. The sounds for a given sensor can be turned off altogether, as well.

The rotor has three speeds: low (about 48 beats per minute), medium (96 BPM), and high (192 BPM), where a "beat" in this case is defined as a single sample played by a sensor. The random control directs the eight sensors to select random sound samples, or randomly turn themselves off. A sync control is provided to synchronize the rotors of multiple adjacent Roto-Trackers, allowing more complex patterns. Using multiple trackers, and a relatively lag-free sim (unfortunately, severe lag sometimes pulls rotors back out of sync), some fairly complex drum loops can be created.


I've created an installation of three Roto-Trackers next to the Librarium's Symposium gallery, here in Abitibi (SLurl link). Not much to the installation, really. Just a chair at optimal listening location, and a sensor-driven start/stop control. The latter, the black truncated cone at left, checks for avatars on the parcel. If 30 seconds pass with no avatars standing on the parcel (both in range of the sensor, and standing in a location with the same parcel name), the rotors will shut down. If an avatar wanders onto the plot and sticks around for up to 30 seconds, they'll start back up. While I don't think these devices generate an irresponsible drain on system resources, there is quite a bit going on: three physical rotors, up to ten collisions per second, and an equal number of triggered sounds and prim status changes. Well worth the time to shut down the works when there's nobody around to hear it.
Wednesday, August 22, 2007
 
August Update
It's amazing how time works, sometimes. Weeks pass like days, yet days seem to take weeks. Or something like that. Sounded more profound in my head.

So, here it is, four weeks since my last update. Unfortunately, my RL has sapped both time and motivation for enjoying my SL, lately. So there's really not much to report here. Been kind of coasting since the Relay, in any case. I'd been working so long toward that goal that I hadn't given any thought at all to what would happen after. And now that it's disappeared from the collective SL unconscious for another year, I'm kind of floundering. I have found time and volition to work on a couple of silly projects, though.


Behold the amazing Mo-Tech Stress Relief HUD. Under pressure? Feeling stressed out? Just touch the red STRESS button, and a sheet of our patented Stress Relief Paper (AKA Bubble Wrap) will instantly appear. Just pop, pop, pop your cares away! And don't worry, once you pop that last bubble, the Stress Relief HUD will automatically create more. Now available for free from your friends at Mo-Tech Industries! Get yours now!

Ahem. Got a bit carried away there. Anyway, if you'd like a Stress HUD, you can pick one up on the second floor of the Mo-Tech shop. Link's up there on the right.

This one proved to be kind of an interesting project, mostly due to the number of prims involved. By necessity, each bubble is its own prim. Oh how I wish LSL had some method of returning which face was clicked! It would have reduced the prim count by at least four or five fold. As it was, this simple HUD weighs in at 79 prims. And that was after cutting it down multiple times.

I opted for a centralized script method, mostly to keep the sim from grinding to a screeching halt each time it was rezzed. It would have been much easier to put a script in each bubble, but sixty-some-odd scripts (one per whole bubble) for each HUD would have been a tad irresponsible. I'd intended using bitwise operators to track the status of each prim, with the prim at link number 1 being represented as bit 1 (2^1), link 2 being bit 2 (2^2), link 3 being bit 3 (2^3) and so on. You can probably see the flaw in this proposition: it would ultimately end up with 79 bits. (I tracked the 10 or so non-bubble prims as dummy values in the set, so that I wouldn't have to come up with an alternative numbering scheme. Much easier to just keep everything keyed to its link number.) This comes out to an integer potentially as large as 2^80 - 1. Strangely enough, LSL just isn't prepared to deal with numbers like 1,208,925,819,614,629,174,706,175.

Fortunately, I figured this out before wasting a lot of time on clueless debugging after the fact. (Surprisingly, too, considering that this is the first project I've done that even attempted to use bitwise operations. Oh well, maybe next time.) Instead, I settled on a list of integer 1's and 0's for status indicators. Prim 1 ended up as list entry 1, prim 2 as entry 2, and so on. Each time a bubble is touched, the script checks its link number, and compares it to the value in the list. If it's 1, it pops the bubble (swapping from a whole to a popped bubble texture, and playing one of three random popping sounds) and swaps the value to 0. When all the values are 0, revert all the bubbles back to 1, reset the popped bubble textures to unpopped, and we're good to go.

As an aside, I also tried using one long string instead of a list, and using string search and replace operations to check each time (character "1" in spot 47 corresponding to link 47, and so on). I timed each operation, and found that, in this instance, they were about equally fast. (A pokey half second per search, give or take a few hundredths. Oh Mono, where art thou?) Kind of surprising. I'd heard that string operations were generally faster than lists. Not this time, anyway. Worth noting, although your mileage may vary with more complex list items.


The other recent project is a working umbrella. This started out as an attempt to get my head around sculpties. Actually, I'd intended the bubble wrap to be my first significant sculpty project, but I couldn't make a convincingly "smooshed" bubble model. I'll probably come back to that later, when my skills improve and when I figure out some of the more sophisticated freeware modeling software. I'd love to make giant-size, three-dimensional, functional bubble wrap. Perhaps with a diving board, and a modest push to loft the av into the air with each pop... Hrm. Okay, maybe I'll get back to this sooner than later. It'll be a metric assload of prims, but I think I can make it work out.

But I digress. Sculpty umbrella. The umbrella fabric (two prims, one open, one closed) was made using Yuzuru Jewell's Rokuro software, set for six-fold symmetry (would have preferred eight, to match the typical large umbrella, but this looks convincing enough). The animations were made using Vinay Pulim's Avimator. Nothing terribly cutting edge or original about this one. Touch, and it swaps from the closed sculpt (switching to alpha 0.0) to the open sculpt (alpha 1.0), and triggers the Hold Umbrella animation. Touch it again, and it reverses the process and shuts down the animation.

From there, scope creep kicked in. It wasn't enough to just have a functioning umbrella! That just wouldn't be me.

First, I added in a simple parachute function. The basic function came together easily enough: run a timer, check for avatar status each tick. If the avatar is in the air and not flying, he must be falling. Trigger a custom falling animation (hanging free from the umbrella, which is pointing straight above), run an llSetForce to reduce gravity, and use impulses to prevent speed from exceeding a fixed downward velocity. Easy enough.

I've found that the fall-down effect will trigger if an avatar hits the ground faster than about 15 m/s. Currently, the umbrella limits falling speed to 10 m/s, but does nothing to limit lateral speed. So, if someone were to start falling with a good amount of forward velocity (say by turning off flight while flying forward at full speed), he'd still potentially hit the ground too fast and fall down. I spent some time trying to come up with a parasailing variant but, for now, I'll just stick with the safe-fall option for vertical movement. Maybe I'll get around to making it into a high-performance aerial vehicle at some future date.

As it turned out, dealing with the animations turned out to be kind of tricky. The problem is that the position of the avatar's hand changes relative to the umbrella's desired orientation. Basically, I had to come up with a way to rotate the attachment for each condition: held and falling. The held rotation needs to be free-floating, so that the end user can tweak it for his own needs. The falling rotation needs to leave the umbrella pointing straight up.

Rotation is easy, simply a matter of calling llSetLocalRot. But I never could find a way to rotate an attachment to an arbitrary rotation relative to the world. llSetRot, llSetLocalRot, llLookAt, llRotLookAt... All end up changing behavior relative to the attachment point. I'm stumped. I ultimately ended up having to rotate the umbrella attachment until it looked more or less vertical when the fall animation was called, then using llGetLocalRot to get the rotation. That rotation was hard coded into the script. Inelegant, but it works. If anyone out there knows a way to make an attachment rotate to face an arbitrary direction (say true North or straight up) from an arbitrary attachment point (say right hand), please leave me a comment.

From there, I ended up adding a slightly modified version of the elevation control script from my ancient Personal Gravity Control HUD (my clunky version of a flight assist). Type "/1 345", and the umbrella will pop open and fly to 345 meters, dragging the user behind it. It's nice to have canned scripts like that lying around, ready to enhance any random product that comes along with only a couple of minor tweaks.

I'm doing something similar with a generalized version of a menu-driven color control script. Activate the color menu, and select the desired color from the dialog box. Simple, and part of multiple projects already, but I've never taken the time to make it truly universal. Now, if I can just work out a vexing bug with the brightness control (allowing the user to pick, say, light, medium, and dark blue), I'll have a useful canned script that can be used with projects from now on. Well worth the time, even if this umbrella never makes it to public distribution.

Next up, perhaps, is a particle rainstorm that appears on demand. Or maybe I'll just leave well enough alone. We'll see.
Wednesday, August 01, 2007
 
Webcam
Whilst attempting to hook up my walk webcam as a media stream, I ran into some frustrations. Evidently, images loaded as media streams (whether loaded directly, or via SMIL) are cached by the SL client. So, if you load a stream like http://www.domain.com/image.jpg, and later change image.jpg, the original image will continue to be loaded from the cache. Very annoying, especially when you're setting up something like a webcam that loads a new version of an image file every XX seconds.

Finally, after much beating-of-the-head-against-the-wall and aimless googling, I ran across nand Nerd's Sculpty Previewer. Evidently, he was having similar problems using media streams to preview sculpt textures without having to upload them. But, nand found a workaround: fool the SL client into thinking the media stream is a brand new URL each time, by giving it some garbage parameters that will be ignored when the stream is reloaded. In this case, dropping in a random integer as an HTTP GET, which will be ignored by the client.

The trick is that the cached image is indexed on the overall URL. Each time the stream is reloaded, it is cached anew, even if the actual object (picture, SMIL file, whatever) has the same filename. nand's solution is one of those forehead-slappingly obvious hacks that, nonetheless, require a deep and thorough understanding of the underpinnings of both the web and the SL client to conceive. Most good hacks are like that. Pure genius!

In any case, here is a heavily commented version of the script I used to display my webcam pictures during the SL Relay for Life, should anyone else run into similar problems. Be sure and read the comments before using.The concept is worth putting in the back of your metaphorical toolbox, in any case. Could come in handy someday!