2889: Working with very large linksets in Opensim
[Update 20090721:] Added links to source code and a reference, corrected some typos.
[Update 20090723:] You can download an OAR with the sample bottle and the generator at rexxed.com: http://www.rexxed.com/2009/07/klein-bottle/
[Update 20090725:] OSGrid users: the sample bottle and the generator are now available at my store in OSGrid.
Most objects in Opensim and Second Life are made of prims. Indeed, if we exceptuate avies, wearables (i.e., non-attachable clothes and body parts), Linden trees and particles, everything you see is made of prims. Prims are small, often uncomplicated geometrical shapes, like a cube, a sphere or a cylinder. By combining (“linking”) prims, builders create more complex objects like houses, vehicles, shoes, hair, jewellery, etc. When prims are linked, the resulting object remembers the order in which they were linked (which is important, for example when an object is scripted) and some other properties; the set comprised of the linked prims and these additional properties is called a link set or linkset.
Linksets in Second Life have several limitations: two prims can’t be linked if they are too far apart, and an object cannot contain more than 256 prims. This is the cause all kind of problems. For example, if you buy a big house, i.e., a house that has more than 256 prims or that it is very large (and therefore its prims are very far apart), the house can’t be assembled into a single object, because of the above rules. Then the house is normally packaged with a rezzer, a scripted assistant that helps you to position the house; once the house is positioned to your liking, you normally ask the rezzer to freeze the house in place, and then delete the rezzer.
Opensim (when used with an appropriate viewer, like the Hippo viewer) supports large linksets, i.e., objects comprising more than 256 prims. In this post I’ll describe some experiments I made with large and very large linksets. In one of these experiments, I created a single object consisting of 2889 prims. Such extremely large linksets are difficult to manage and create, but once you get them built they work wonderfully.
In August 2008, I visited in the Wales Springs region of Second Life a fantastic sculpture by Suzanne Graves. The sculpture reminded me of a Klein bottle [indeed, technically speaking Ms. Graves’ surface is not Klein-like, because it has an odd number of curls], and I decided to try to write a script to generate Klein bottles (you can find the script in the appendix at the end of this post).
After some attempts, I got the scripts working, and I generated a nice bottle, which I placed on top of my club, in the center of the Condensation Land region in SL. I made a fun video of my friend Ludmilla and myself dancing inside the bottle :-)
Since the bottle existed in Second Life and consisted of thousands of prims, it could not be linked into a single object. The bottle stayed there several months, and when the Openspace fiasco started we had to concentrate in a single island and I had to delete it because Condensation Land got cramped and Second Life has a 15,000 prim limitation.
When I migrated the Condensation Land archipielago to Opensim, I was not able to migrate the bottle, because it was not linked. I still had the program, though. Some tests I made when testing the brand-new Rezzable Private Grid Alpha indicated that the script could not be run unchanged (I tried to run it and brought the sim to its knees :-/). But now I was the owner of my own grid, and could look at the Opensim console while working with the script, so that I could see if something was going wrong, stop the server, etc. And the Hippo Opensim viewer, since version 0.5.0, allowed linksets larger that 256 prims! I absolutely wanted to test this feature and see what could I do with it.
The Opensim experience
I had to adapt my Klein bottle generator for Opensim — the technical details are in the Appendix at the end of the post. Once the generator had run (which took around two hours), I had a collection of 2888 unlinked prims, i.e., the bottle itself (2880 prims), and 8 prims that had beed doubly generated because of a small bug in the program. I then created a central transparent prim destined to serve as the root prim, and started to link the vertices to the root prim.
Up to around 1000 prims everything worked flawlessly. When I tried to link more prims, the linking operation started to be progressively slower; in some cases, I was thrown out of the grid and had to relog. When I got over 2000 prims, further linking was simply impossible: the client got so busy that it stopped responding to pings from the client, and the regions started to drop the scene; the client itself timed out, and threw me out before the linking operation was complete…
What to do? I then realized that I was always using the same linking approach, imported from my SL experience: I was selecting a moderately big number of prims, say 150, and trying to link them to the previously linked large linkset. Maybe if I separately linked the remaining prims into another large linkset, I would be able later to link the two linksets between them? Well, I tried this approach, and it worked! :-) I had to create another, temporary root prim, link the remaining prims to the secondary root prim, link then the two linksets, enter “select linked prims”, unlink the secondary root prim, take the object, and re-rezz it. And that was it! The final linking took some time, but I was not thrown out of Opensim :-), and both taking the object and re-rezzing it took an inordinately big amount of time, but apart from that (which is very understandable if you think of what’s really going on under the hoods) everything worked fine. I was able to move the huge 2889-prims linkset, to rotate it, to copy it, to make it full bright, to apply some glow, and even to set it rotating! :-)
What seems to be happening (this is all inference, I have not looked at the code)? Well, it appears that if you link “n” prims to an existing linkset, this is equivalent to recreating the linkset “n” times, one for each newly linked prim. This is not a problem when the existing linkset is small and the number of prims is also small, but if you’re attempting to link, say, 300 new prims to an existing linkset of 2000 prims, this involves 300 recalculations of a linkset averaging 2150 prims, and this is too much for the client, which hangs miserably.
To the contrary, if you’ve got two large linksets and you try to link them, there’s only one recalculation operation for the new linkset. And this operation, albeit slow, occurs in a lapse of time small enough so that the client does not crash.
Here’s a video of the new bottle, rotating on top of my club in the Condensation Land grid:
Appendix: Program code
Here is the code for the scripts
(I’ll post a link to a downloadable version of the code as soon as I find some time) [Update:] including links to the downloadable source. The main script goes inside a standard cube, and works in the following way: a Klein bottle is a bidimensional surface immersed into a 3D space; apart from an irrelevant twist, it can be considered as the product of two circumferences, and therefore it can be parameterized using two variables “u” and “v”. Some formulas I found at Planetmath calculate the corresponding 3D points taking “u” and “v” as an input.
We generate only the edges (each edge will be a prim; the code for generating the vertices is commented out; I didn’t figure how to generate the sides). Since we are parameterizing in “u” and “v” and we can only generate a finite number of prims, we have to decide on how many partitions of 2*PI we’ll use for “u” and “v”. These are the “m” and “n” variables of our program. In our example, we generate 120 partitions of “u” (the “slices”) and 8 partitions of “v” (the “stripes”).
The program calculates the vertices, and then computes the positions of the edges; the edges are generated by rezzing a small prim (“Cylinder”), which is then rotated, resized and colored; part of this job is done by a small script residing inside “Cylinder”; the script auto-deletes itself on completion.
drawLineSegment routine I cannibalized from
somewhere, but I didn’t write the reference [ I know, I know! :-) If someone knows the reference, I’ll happily include it here] [Update] http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryBezierCurveDemo (thanks, Trevor! :-)).
Please note that I had to insert a
llSleep call after each rezzing — otherwise XEngine starts to choke, compilation starts to fail, and the bottle generation aborts.
Download source code
This is the small script that goes inside “Cylinder”.
Download source code