Don't click here unless you want to be banned.

LSL Wiki : LibraryParametricSurfaceRezzer

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl423.us.archive.org
The following is a set of scripts for rezzing surfaces from arbitrary parametric equations.

Pictures: 1, 2, 3.

//Parametric Surface Rezzer
//by Seifert Surface
//Nov 2006

//////PARAMETERS//////

//Example surface, WARNING: rezzes 200 prims

float scale = 1.0;     //scales the surface in all directions. If this is 2.0 the surface will be twice as large as if it is 1.0
float depth = 0.01;  //thickness of triangles rezzed

float min_u = -4.0;
float max_u = 4.0;
integer steps_u = 10;

float min_v = -4.0;
float max_v = 4.0;
integer steps_v = 10;

vector f(float u, float v)   //the parametric function
{
    return <u, v, 2.0 * llSin(u) * llSin(v)>;
}

//////END OF PARAMETERS//////

//Description:

//This collection of scripts rezzes a surface defined by a parametric function. The surface is made out of 
//triangles, one prim per triangle. There will be at most 2*steps_u*steps_v triangles in the final surface 
//(it is possible to have fewer triangles as the script does not rez degenerate triangles). To change the 
//surface rezzed, edit the PARAMETERS section above.

//Do whatever you want with this script. I'll be annoyed if someone tries to sell it to newbies, but I think the
//chances of that are slim!

//Instructions: 

//There are three scripts. The scripts "surface_rezzer" (this script), and "triangle_detailer" go in the 
//prim that will do the building. Another script, "triangle_rezzee" goes inside another prim, which must be 
//called "triangle".  The prim "triangle" goes in the inventory of the builder prim. 

//To build the surface, touch the builder prim. The surface will be built centered on the location of the 
//builder prim when touched. Be careful when rezzing surfaces near the ground, as the builder can get stuck
//trying to move to a position to rez something when that position is underground.

//Once the surface is rezzed, the following commands can be shouted on channel 347:

//"die" - Deletes all rezzed triangles (in range of your shout).
//"clear" - removes scripts from all rezzed triangles (in range of your shout).

//If you prefer, you can have the triangles remove their scripts as soon as they are in position, there is 
//a commented-out line in the triangle rezzee script which can be uncommented to do this.

//Have fun!

// Seifert Surface
// 2G!tGLf 2nLt9cG

integer comm_channel = -61347732;
integer rez_counter;
vector origin;
float delta = 0.01;

rez_triangle(vector a, vector b, vector c)
{
    a = origin + scale * a;
    b = origin + scale * b;
    c = origin + scale * c;
    //check for 2 vertices in the same place
    if(llVecDist(a,b) < delta || llVecDist(b,c) < delta || llVecDist(c,a) < delta)
    {  //if so, don't try to rez the triangle
        return;
    }
    float cosA = (b - a) * (c - a);
    float cosB = (c - b) * (a - b);
    float cosC = (a - c) * (b - c);  //signs -ve means obtuse angle
    if(cosA < 0.0)  //so the angle at a is obtuse, meaning the opposite edge must be the base of the prim
    {
        triangle(a, b, c, TRUE);
    }
    else if(cosB < 0.0)
    {
        triangle(b, c, a, TRUE);
    }
    else if(cosC < 0.0)
    {
        triangle(c, a, b, TRUE);
    }
    else //all acute angles... so we can choose which way to base the prim, so as to minimise the
    {        //error introduced by the shear value having a resolution of only 0.01
        float error1 = triangle(a,b,c,FALSE);
        float error2 = triangle(b,c,a,FALSE);
        float error3 = triangle(c,a,b,FALSE);
        if(error1 < error2)
        {
            if(error1 < error3)
            {
                triangle(a,b,c,TRUE);
            }
            else 
            {
                triangle(c,a,b,TRUE);
            }
        }
        else
        {
            if(error2 < error3)
            {
                triangle(b,c,a,TRUE);
            }
            else
            {
                triangle(c,a,b,TRUE);
            }
        }
    }
}
         
float triangle(vector a, vector b, vector c, integer rez)
{    
    float width = llVecDist(b, c);
    vector left = llVecNorm(b - c);
    vector fwd = llVecNorm(left % (a - c));
    vector up = fwd % left;
    float height = (a - c) * up;
    float y_shear = 0.5 - ((b-a) * left) / width;
    
    if(rez)
    {
        vector  center = 0.5 * ( (b+c) + (height * up)  );
        vector scale = <depth, width, height>;
        rotation rot = llAxes2Rot(fwd, left, up);
        llMessageLinked(LINK_THIS, comm_channel + rez_counter, (string)scale + "|" + (string)y_shear, NULL_KEY);
        
        while(llVecDist(llGetPos(), center) > 9.5)
        {
            llSetPos(center);
        }
        llRezObject("triangle", center, ZERO_VECTOR, rot, comm_channel + rez_counter);
        rez_counter += 1;
        return -1.0;
    }
    else
    {
        y_shear = (float)llRound(y_shear * 100.0) / 100.0;
        return llVecDist(a, 0.5 * (b + c) + height * up + y_shear * width * left); 
        //error between where the vertex of the triangle should be and would be...
    }
}

rez_surface()
{
    integer i;
    integer j;
    float scale_u = (max_u - min_u) / (float)steps_u; 
    float scale_v =  (max_v - min_v) / (float)steps_v; 
    for(i=0; i<steps_u; i+=1)
    {
        for(j=0; j<steps_u; j+=1)
        {
            vector A = f(min_u + scale_u * i, min_v + scale_v * j);
            vector B =  f(min_u + scale_u * (i + 1), min_v + scale_v * j);
            vector C =  f(min_u + scale_u * i , min_v + scale_v * (j + 1));
            vector D =  f(min_u + scale_u * (i + 1) , min_v + scale_v * (j + 1));
            rez_triangle(A, B, C);
            rez_triangle(B, D, C);
            //llSleep(0.2); //in some very laggy situations this may be necessary to add, shouldn't be necessary
            //only use if the triangle_detailer gets backed up on its list.
        }
    }
}

default
{
    touch_start(integer num)
    {
        if(llDetectedKey(0) == llGetOwner())
        {
            origin = llGetPos();
            rez_surface();
            while(llVecDist(llGetPos(), origin) > 9.5) //go back to the start
            {
                llSetPos(origin);
            }
            llSetPos(origin);
            llOwnerSay("Done!");
        }
    }
}

//Triangle Detailer
//by Seifert Surface
//Nov 2006

integer comm_channel2 = 61347732;
list rezzees;
list tri_data;

default
{
    state_entry()
    {
        llListen(comm_channel2, "", NULL_KEY, "");
    }
    link_message(integer sender, integer num, string str, key id)
    {
        rezzees += [num];
        tri_data += [str];
        if(llGetListLength(rezzees) > 10)
        {
            llSay(DEBUG_CHANNEL, "Detailer list getting long...");
        }
    }
    listen(integer chan, string name, key id, string msg)
    {
        //llOwnerSay((string)llGetFreeMemory() + " " + (string)llGetListLength(rezzees));  //in case you want to see if the detailer is getting overloaded
        integer who = llListFindList(rezzees, [(integer)msg]);
        if(who != -1)
        {
            llShout((integer)msg, llList2String(tri_data, who));
            rezzees = llDeleteSubList(rezzees, who, who);
            tri_data = llDeleteSubList(tri_data, who, who);
        }
    }
    
}

//Triangle Rezzee
//by Seifert Surface
//Nov 2006

integer comm_channel = -61347732;
integer comm_channel2 = 61347732;
integer me;
integer listen_control;
integer times_to_ask = 10;

default
{
    state_entry()
    {
        llListen(347, "", "", "");
    }
    on_rez(integer param)
    {
        if(param != 0)
        {
            me = param;
            llSetObjectName((string)(me - comm_channel));
            listen_control = llListen(me, "", "", "");
            llShout(comm_channel2, (string)me);
            llSetTimerEvent(5.0);
        }
    }
    listen(integer chan, string name, key id, string msg)
    {
        if(msg == "die")
        {
            llDie();
        }
        else if(msg == "clear")
        {
            llRemoveInventory(llGetScriptName());   
        }
        else if(chan == me)
        {
            list data = llParseStringKeepNulls(msg, ["|"], []);
            vector scale = (vector)llList2String(data, 0);
            if(scale.x < 0.01)
            {
                scale.x = 0.01;
            }
            if(scale.y < 0.01)
            {
                scale.y = 0.01;
            }
            if(scale.z < 0.01)
            {
                scale.z = 0.01;
            }
            float y_shear = (float)llList2String(data, 1);
            llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_BOX, 0, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>, <1.0, 0.0, 0.0>, <0.0, y_shear, 0.0>, PRIM_SIZE, scale]);  
            //llRemoveInventory(llGetScriptName());   //if you want to remove scripts as soon as possible, uncomment this.
            llListenRemove(listen_control);
            llSetTimerEvent(0.0);
        }
    }
    timer()
    {
        llShout(comm_channel2, (string)me);
        times_to_ask -= 1;
        if(times_to_ask <= 0)
        {
            llSetTimerEvent(0.0);
            llSay(DEBUG_CHANNEL, "no reply after 10 tries");   
        }
    }
}
Here are some example parametric equations to plug in. The number of prims used can be reduced by lowering the steps_u and steps_v variables, though the surfaces will not look as good. It is also a good idea to lower the scale number as well, to avoid prims trying (and failing) to scale to above 10m along any dimension. The parametric equations are from: http://vmm.math.uci.edu/3D-XplorMath/Surface/gallery.html
//Sphere, with a slight twist 
//224 prims
float depth = 0.01;
float scale = 3.0;

float min_u = 0.0;
float max_u = TWO_PI;
integer steps_u = 16;

float min_v = 0.0;
float max_v = PI;
integer steps_v = 8;

vector f(float u, float v)
{
    return <llSin(u + 0.5 * v) * llSin(v), llCos(u + 0.5 * v) * llSin(v), llCos(v)>;
}
//Klein Bottle
//800 prims, large (rez in a sandbox)
float depth = 0.01;
float scale = 5.0;

float min_u = 0.0; 
float max_u = TWO_PI; 
integer steps_u = 20;

float min_v = 0.0;
float max_v = TWO_PI;
integer steps_v = 20;

float a = 2.0;
vector f(float u, float v)
{
    float temp = (a + llCos(u * 0.5) * llSin(v) - llSin(u*0.5)*llSin(2*v));
    return < temp * llCos(u), temp * llSin(u), llSin(0.5*u)*llSin(v) + llCos(0.5*u) * llSin(2*v)>;
}
//Dini's Surface
//800 prims, large (rez in a sandbox)
float depth = 0.01;
float scale = 10.0;

float min_u = -5.0;
float max_u = 5.0;
integer steps_u = 20;

float min_v = -3.14159;
float max_v = PI;
integer steps_v = 20;

vector f(float u, float v)
{
    float psi = 1.2; //this can be from 0 to PI
    float sinpsi = llSin(psi);
    float cospsi = llCos(psi);
    float g = (u - cospsi * v) / sinpsi;
    float s = llPow(2.7182818, g);
    float r = (2 * sinpsi) / (s + 1 / s);
    float t = r * (s - 1 / s) * 0.5;
    
    return <u - t, r * llCos(v), r * llSin(v)>;
}
//Boy's surface
//1250 prims, large
float depth = 0.01;
float scale = 25.0;

float min_u = 0.0;
float max_u = PI;
integer steps_u = 25;

float min_v = 0.0;
float max_v = PI;
integer steps_v = 25;

float E = 2.718281828;

float Exp(float x)
{
    return llPow(E, x);
}
float Cosh(float x)
{
    return 0.5 * (Exp(x) + Exp(-x));
}
float Sinh(float x)
{
    return 0.5 * (Exp(x) - Exp(-x));
}

vector f(float u, float v)
{
    float x = llCos(u) * llSin(v);
    float y = llSin(u) * llSin(v);
    float z = llCos(v);
    float ef = 0.5 * ( (2 * x*x - y*y - z*z) + 2*y*z*(y*y - z*z) + z*x*(x*x - z*z) + x*y*(y*y - x*x) );
    float g = llSqrt(3.0) * 0.5 * ( (y*y - z*z) + z*x*(z*z - x*x) + x*y*(y*y - x*x) );
    float h = (x+y+z) * ( llPow(x+y+z, 3.0) + 4 * (y - x)*(z - y)*(x - z)  );
    return <ef,g,h * 0.125>;
}
Comments [Hide comments/form]
Oooh.
-- DolusNaumova (2006-11-21 13:48:56)
Attach a comment to this page: