Saturday, May 2, 2015

A ghost tale behind the scenes (and some Blender tips)

The apprentice

Sarah wanted to learn the secrets of the afterlife and spells to bring spirits back to Earth. She knew of a magician that took her under his tutelage. She learned the basics, but her eagerness about darkness soon gave her away, and the magician became cautious. Expecting that Sarah would steal a small book with the most powerful recipes (for apprentices always wanted to run before they knew how to walk), he cast a spell upon it. The book was sealed.

Five days later, the Full Moon was up in the sky, and Sarah took what she thought her best chance. As the magician predicted, she stole the book and fled, hiding in the cemetery.

She sat on a stub next to the mausoleums, ready to open the book. The book wouldn't open, though. She mumbled, cursing the magician and the book at the same time, and spent a while thinking. She remembered a spell to open sealed boxes, and decided to try. "A closed box and a closed book are the same things. Closed things," were her thoughts.

She put the book on the ground and her hands were over the cover. She said the words, feeling her fingers tingling. Smiling, she looked down, finding that the book had opened. Her eyes danced over the pages and found what she had been searching for. The spell was difficult, but if successful, she could invoke a shadow from the death, a stealthy creature that would follow the people she wanted, making for her to see inside their minds and learn their best kept secrets.

A blurry shape started to show on the mirror. It was a woman. Bald, white, Sarah could see through her. The woman seemed to be sleeping, then she raised her head and started to look around. Sarah was excited and, at the same time, a little scared. She had the creature right in front of her. Now what?

The woman smiled, showing her palms, reaching to the mirror's surface. "Touch my hands, Sarah," she said. Sarah walked closer. Her hands doubted. "I know why you summoned me. I will first visit the magician, and tell you all that he hides in his mind. Touch my hands, Sarah, and it will be done," the woman on the mirror insisted, in soothing tone.

The mirror's surface felt warm in Sarah's hands. The sensations were puzzling. The mirror seemed to melt in her hands while the woman inside started reaching outside, walking through Sarah.

Before she realized, Sarah was inside the mirror, confused. Outside, the ghostly woman was nowhere to be seen. The magician was there, instead. His expression, stern, revealed that the deceiving woman inside the mirror was the actual spell sealing the book. She started to cry, begged him to release her. He only said, "Think about what you did, Sarah. Think. You will be staying here for a long time." He then turned around, and walked away.

This story is also published in The Night Corner

Behind the scenes: Blender tips

WARNING: The following text-article isn't aimed to people completely new to Blender and the insight of building and scripting in SL. You will need some experience in all those fields to follow the ideas I explain.

I've mentioned more than once how I love the fact that we can use SL to build scenes, take pictures, and then use those pictures to create stories with them. Today I also want to share technical details about how I created one item, in case this gives ideas to other people.

This is the mirror I created for the Oneword event, Darkness round (May 2015, so, right now):

This mirror was designed to be used as a photo prop. When you sit on the mirror object, the first animation is a standard I'm looking at myself on the mirror pose. But then, we see that the reflection is showing... a ghost? that is imitating our pose. As we change poses, we see the reflection on the mirror vanishing, then showing a different reflection.

The idea was showing a ghost that emerges on the surface and shows their intention of reaching out to the person on the other side of the mirror. However, I started deciding on the technical details after I had modeled and UV mapped the mirror above.

To begin with, how do we get this ghost showing on the mirror? We do it by adding a separate face over the mirror, in a different material, in Blender:

This sounds fairly easy if you thought of the feature from the beginning, and modeled your object with that in mind. But often will happen something different. For example, I had the mirror completed (UV mapped, and the LOD models were also done) when I thought of the effect:

If you're not too experienced with Blender, and particularly, with UV mapping, you may think that you're doomed, you will have to redo all the UV mapping, redo the LOD models again... I'm going to show that when you think of an addition to your model once it's completed, you may not have to pull your hair.

To begin with, notice where I UV mapped the mirror surface:

This gives me plenty of room to add the overlayed ghost surface (a plane), move it a little above the mirror surface, scale it (in this case, it was S X 0.5), unwrap only the just added plane, and then move the face on the UV layout all the way to the right (you just have to hold CTRL to snap to grid over the UV/Image Editor while you grab in X):

Then I make sure of adding a plane on the medium LOD model, make it have the same size and position than in the high LOD, and then unwrap that plane alone (Since I scaled using S X 0.5, I easily get the same size). I assign that face to the same material that the high LOD used, then move the face to the same position in the UV map. Once done, I can now do the same on the low LOD model. Using CTRL to snap to grid over the UV/Image Editor ensures that the face will be UV mapped on the same place in all high, medium and low LOD models. I didn't do a lowest LOD model for this, because it being a piece of furniture, I don't expect it to be seen from very far away. So I reduced this last LOD to the minimum number of triangles the uploader allows, to keep the LI as low as possible. I used a box for physics.

This setup allows us to show the ghost over the mirror, or hide it, showing only the mirror. But there's another issue, which I thought of after I had added this plane.

The prop has six different poses (then mirrors), and it shows six different images of the ghost. This means, six different textures. Because textures have to fully load, this can ruin the effect when changing poses, showing gray textures while they arrive to our computers. They eventually load, but it would be a lot smoother, and credible, for the prop, if there's no wait time once we see that the mirror prop is fully rezzed and textured.

So, what do we do now?

This was my solution: To begin with, we're talking about six textures. If I use one 512x512 texture for the mirror surface and the ghost, I can use a 1024x1024 texture to put four textures with different ghost setups:

So this means that just two textures cover my six ghost positions:

Of course, I will need of some scripting to correctly change repeats and offsets in each pose. The important thing is that I have reduced the need of using six textures, to needing two textures. I can easily preload those two textures if I have two more separate SL-faces, each one of them containing one texture, and having the transparency turned all the way up to 100% on those two. How do we translate two SL-faces to Blender? Two more materials.

At the moment, our object has three materials: the cast iron, the mirror surface, and the ghost plane. SL limits mesh objects up to eight materials. This means I can still use five materials, which is cool, for I just need two, after having simplified six textures to just two.

The simplest way I found to do this inside Blender was this (then of course you have to repeat these steps per LOD model):

Duplicate the ghost-face in Blender, move it a little behind the mirror itself, scale it down (for example, S 0.5; use a scale value that you can easily replicate in your LOD models). Since you've duplicated an already UV mapped face, you have not to think at all in UV maps. Not that it matters in this particular case, for the preloading faces will be 100% transparent, but in other cases, this could be relevant.

We've duplicated a plane. A plane is a quad: Two triangles. Convert that quad into two triangles with the Quad to Tris function under the faces menu (CTRL F). Now create two extra materials. Assign one of those triangles to one of the extra materials. The other triangle to the other material. Rinse, repeat in the Medium and Low LODs. Done.

Maybe I could have decided on using 256x256 textures for mirror and ghost. Then just one 1024x1024 texture would make it, for it can hold up to sixteen 256x256 textures. But thinking of the size of the object and the quality of the textures, I decided on 512x512 as base. The reason being, 256x512 are actually what's used by the mirror, and then 256x512 for the ghost. Had I gone for 256x256 per frame, only 128x256 would be for the mirror, and 128x256 would be for the ghost. The quality loss would be noticeable on the ghost. Still, it's just two textures we're talking about, not six.

If you're using AVsitter, all you need now is coding a script that will be listening to AVsitter messages. When AVsitter tells you that a pose has been selected, you will know which pose is the selected one. Make your script change texture UUID and texture repeats/offsets depending on the selected pose by using llSetLinkPrimitiveParamsFast. The list you have to send, to change repeats and offset, will have the format:

[PRIM_TEXTURE, face, texture, repeats, offsets, rotation_in_radians]

In case you've fiddled with scripts, but are not familiar with this function:

  • PRIM_TEXTURE is literal text, it's a constant name and so it has to be written exactly that way.
  • face refers to the face number. Check this link if you don't know how to obtain the face number of a SL-face.
  • texture is your texture UUID. Make sure of making your script no modify for next owner so it can't be open and read! (Click here for more about permissions if you're not familiar with them.)
  • repeats refers to the horizontal and vertical repeats of the texture. You have to write them like this: <horizontal_repeat, vertical_repeat, 0>
  • offsets refers to the horizontal and vertical offset of the texture. You have to write it like this: <horizontal_offset, vertical_offset, 0>
  • rotation_in_radians is the rotation of the texture. Since we're not changing it, we just write 0 in there, but if you want to change it, remember that LSL is expecting radians! You only know the angle in degrees? No problem: write this for the angle: your_angle_in_degrees * DEG_TO_RAD (DEG_TO_RAD is literal text, it's a constant name that has to be written exactly that way.)

(Sadly, llScaleTexture and llOffsetTexture are not a viable choice for an application like this.)

You're finally done. Have a great day :-)


Mesh body: Lara, from Maitreya
Mesh hands: Lara's hands, from Maitreya
Mesh feet: Lara's feet, from Maitreya

Skin: Lulu 02 C, Jamaica, from Glam Affair
Freckles: Cassiopea Cosmetics, A (tn), from Glam Affair

Hair: Windswept, Red eye flight (and tinted), from Clawtooth
Headpiece: Darcy flowers headband, Quarter of Bliss, from Ariskea
Dress: Sylfai gown, primrose, from Evie's Closet (Evangelina Miles)

Pose and prop: Looking inside (the mirror), Black Tulip (mine), (currently at Oneword).

Windlight: [TOR] FOGGY - Silent Heck

No comments:

Post a Comment