Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Discussion: Parametric Surface Rezzer

Seifert Surface
Mathematician
Join date: 14 Jun 2005
Posts: 912
11-21-2006 01:00
This is mirrored in the lslwiki.

The following is a set of scripts for rezzing surfaces from arbitrary parametric equations.

Pictures: 1, 2, 3.
CODE

//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_v; 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!");
}
}
}
CODE

//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);
}
}
}
CODE

//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.
CODE

//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)>;
}
CODE

//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)>;
}
CODE

//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)>;
}
CODE

//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>;
}
_____________________
-Seifert Surface
2G!tGLf 2nLt9cG
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Original Thread
11-23-2006 09:54
/15/8b/150227/1.html
_____________________
i've got nothing. ;)
Kaiser Bogomil
Registered User
Join date: 15 Mar 2006
Posts: 20
11-27-2006 07:04
This is great script! I will be using this one!

Thank you Seifert!

BTW - here's a sugestion for for a next step: boolean volumes.
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
11-27-2006 07:13
Yep, A great script to learn with. I rezzed each of the included shapes, one by one. Also added color and shininess into the llSetPrimParameters in the Triangle Rezzee script. Interesting, moving the rezzer around to rezz the prims instead of rezzing all of the prims and them moving to thier location. By the rezzer moving , I never encountered the problem of running into the grey goo fence even when rezzing Boy's surface.
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
Joannah Cramer
Registered User
Join date: 12 Apr 2006
Posts: 1,539
11-27-2006 09:00
Hmm crazy as the thought is, it wouldn't be too complicated to combine the triangle calculator with notecard reader, and rezz instead meshes from say, wavefront .obj format or something similar?

(crazy because both prim counts and memory requirements for storage of vertex data while building could be quite enormous..)
Seifert Surface
Mathematician
Join date: 14 Jun 2005
Posts: 912
11-27-2006 13:03
Kaiser: not sure what you mean by "boolean volumes". We can't do boolean subtraction on individual prims. I guess it would be possible to rig up something to make large copies of ordinary prims (with many triangle prims used for each large prim, I believe this is one of the things that Xyobject does) and then do boolean subtraction on those large models. Is that what you mean?

Jesse: I'd be surprised if any process that involves only one object rezzing hit the grey goo fence - it shouldn't as I understand the fence. Moving the rezzer rather than the rezzees: I don't think it really makes much difference in the end, just a different way to do things.

Joannah: Check out this script by Jeffrey Gomez does what I think you're thinking of (check later in the thread for a notecard reader version). My triangles are sometimes slightly more accurate than how Jeffrey was doing it then, although the script as is produces very satisfactory results. Presumably it shouldn't be hard to hack my triangles into his script.
_____________________
-Seifert Surface
2G!tGLf 2nLt9cG
Joannah Cramer
Registered User
Join date: 12 Apr 2006
Posts: 1,539
11-27-2006 14:04
From: Seifert Surface
Joannah: Check out this script by Jeffrey Gomez does what I think you're thinking of

Aye, that's the one i was thinking of... it's using cubes as base if i recall right, so figured with the triangle-oriented code instead the results could be nicer ^^
Seifert Surface
Mathematician
Join date: 14 Jun 2005
Posts: 912
11-27-2006 14:44
From: Joannah Cramer
Aye, that's the one i was thinking of... it's using cubes as base if i recall right, so figured with the triangle-oriented code instead the results could be nicer ^^
No, it's the same. Both Jeffrey's and my scripts use cubes as the base, and turn them into triangles using taper.
_____________________
-Seifert Surface
2G!tGLf 2nLt9cG
Joannah Cramer
Registered User
Join date: 12 Apr 2006
Posts: 1,539
11-27-2006 16:07
D'oh, considering that's how even Lindens do their prism prims, i have no idea what i was thinking *><*
Kaiser Bogomil
Registered User
Join date: 15 Mar 2006
Posts: 20
12-06-2006 08:48
From: Seifert Surface
Kaiser: not sure what you mean by "boolean volumes". We can't do boolean subtraction on individual prims. I guess it would be possible to rig up something to make large copies of ordinary prims (with many triangle prims used for each large prim, I believe this is one of the things that Xyobject does) and then do boolean subtraction on those large models. Is that what you mean?

I don't know if I'm using the right term here with "boolean volumes"... but it sounds like you get my drift. I don't think I'd approach the problem with prim subtraction - instead I'd try to subtract one parametric function from another & then render/rez the prims from the resultant function. In other words - imagine you have two volumes where each may be assigned a value of 0 (invisible) or 1 (visible). Then given you had two point sets to represent each volume where each set is defined by parametric functions - find the result of combining the two sets & then render the resultant set. For example, say you have two sphere's of equal size & you assign a value of 1 to sphere 1 & a value of 0 to sphere 2. You place them so that one surface intersects the center of the other. (not prims) Then you AND the two together - you should get a hollow volume in the middle. Then - using your surface rezzer you construct the resulting surfaces. The visible result should look like a sphere with a crater in it.
Seifert Surface
Mathematician
Join date: 14 Jun 2005
Posts: 912
12-06-2006 14:57
Ok, the two spheres example made it clearer.

Unfortunately it isn't as simple as "subtracting the functions" to get the effect you're after.

At the very least, in order to get such a surface rezzed you need to get an equation for the (one dimensional) curve of intersection between the two (two dimensional) surfaces. For surfaces generated by arbitrary parametric equations I don't think there is a nice way to express the curve as another parametric equation, which we would need in order to rez surfaces with that curve as boundary.

For specific simple cases, such as the two spheres, it shouldn't be too hard to work out the parametric equations by hand, then use the surface rezzer to make them, but in general this is hard.
_____________________
-Seifert Surface
2G!tGLf 2nLt9cG
Sanderman Cyclone
Registered User
Join date: 29 Jun 2006
Posts: 8
01-20-2007 12:43
Hi, I'm working on a prim based vertex modelling tool that, when finished, should be of help in building particular builds. The tool I'm making relies on the creation of triangles just as these scripts here. I'm not as good in math and had problems creating the triangles. I was wondering If you would give me permission to use part of your work, the triangle creation part, in my project. It will be a free and open source tool when it is done, and u Seifert Surface will also get credit.
Ged Larsen
thwarted by quaternions
Join date: 4 Dec 2006
Posts: 294
01-20-2007 14:49
From: Sanderman Cyclone
Hi, I'm working on a prim based vertex modelling tool that, when finished, should be of help in building particular builds. The tool I'm making relies on the creation of triangles just as these scripts here. I'm not as good in math and had problems creating the triangles. I was wondering If you would give me permission to use part of your work, the triangle creation part, in my project. It will be a free and open source tool when it is done, and u Seifert Surface will also get credit.


In the comments of his primary script, Seifert Surface writes:
From: someone
//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!


So I think you're covered.

His triangle rezzer function(s) are great -- I used it a few days ago for a geodesic dome generating script.
Seifert Surface
Mathematician
Join date: 14 Jun 2005
Posts: 912
01-22-2007 00:22
From: Ged Larsen
So I think you're covered.
Yup, go for it :)
_____________________
-Seifert Surface
2G!tGLf 2nLt9cG