Library: 3D Model Importer (Beta and Disclaimer)
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
01-08-2005 17:23
Some yahoo had to do it eventually. If that yahoo has come and gone, and I just don't know about it, I won't be surprised. Here's my beta version of a 3D model importer that runs on Wavefront OBJ code. This current version allows for roughly 100-some faces per run for now, but that's just due to limitations on the script buffer that I'm sure smart people will be able to get around.  But before we get to the code... DISCLAIMER: THIS TYPE OF SCRIPT WILL NOT DESTROY PRIM BUILDING Period. Since it's very limited in its current version, and every face becomes at least one prim, you can begin to see that this is very limited technology. However, for those of you that have always longed to build shapes outside of Second Life, this finally gives you the option to use them. Also, for those of you worried that you will lack tools outside of Second Life, I have provided my recommendations hardcoded in the script itself. I'm also a stingy 3D designer, so naturally I can offer good suggestions. Heck, I do my work with free modellers - enough to impress - but this isn't about my modelling capabilities. It's about all of yours'. Oh yes, and try to keep face sizes within 10m squared. Bad Things Will Happen if you don't. Included is a test sphere to make sure it works properly. ... Now, let's just hope I can figure out how these blasted UV coordinates work...  ... see revised code below.
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
01-10-2005 18:30
I am currently: Working on the UV code. Might not work so well, given SL UV mapping has severe margin for error. For now, though, an edit to the Facemaker code. This should make faces more accurate at a cost of more calculation time. Oh, and use tris for these. They're safer. ... see revisions below.
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
01-17-2005 16:39
The following two are fixes to optimize the code. Unfortunately, UVs are still in the beta stages, if that - see this thread for details. List of fixes in this version: - Faces now much, much faster, since I'm using projections now instead of my minimum value approach. - Faces now support up to eight vertices apiece. - There should be a smaller margin of error between faces - Models scale to size of root prim (the one running the script) Project notes: - Decided to scrap prim-based importing in favor of solely this, for the time being. Find me a good modeller that acts like Second Life, though, and I'll consider it.  - UV code is in the very, very beta stage and does not work perfectly. I have to scale back my time on this project, so I've posted the code for that to the other thread. That also only seems to work well with tris, and has a margin of error that's hard to best using Second Life.  //============================================================================ // OBJ Model Importer For Second Life // Written by Jeffrey Gomez // // Permissions Granted to Edit, Copy, Transfer, and Sell this script // to any user, so long as this comment set remains intact, and is // granted WITHOUT ANY WARRANTY. USE AT OWN RISK. And enjoy. =] // // Any unauthorized or illegal usage of this script, as dictated by International Laws // of Copyright or Linden Labs voids any license to use this script. Creator of // this script is not responsible for said use. So please, don't come after me. :D // // Original Date of Creation: January 7th, 2005 // // Forum Thread URL(s): // http://forums.secondlife.com/showthread.php?t=32491 // http://forums.secondlife.com/showthread.php?t=32283 // // // Special Thanks: // Xylor Baysklef for reminding me that projections exist // Strife Onizuka for various suggestions for UVs // // // Suggested Free Tool URLS: // Paint - The GIMP: www.gimp.org // 3D - Blender: www.blender.org // 3D - Anim8or: www.anim8or.com // UV Mapper - UV Mapper: www.uvmapper.com // Text Editor - jEdit: www.jedit.org // // Suggested Inexpensive Tool URLS: // 3D - Milkshape (~$25): www.swissquake.ch/chumbalum-soft // UV Mapper - UV Mapper Pro (~$25): www.uvmapper.com // // ... so don't complain I never did anything for you. =P // // // Script Purpose and Usage: // The purpose of this script is very simple. For quite some time now, people // have been griping that there has been no way to import models from 3D tools // directly into Second Life. This script uses a common methodology of 3D // design tools, tris, to mimic faces in Second Life. // // To use this script set, simply place the Prim Face Code into a Cube Prim, // place this code into another object, then place said Cube Prim into the // object. Once you have done so, open up your OBJ file in a text editor with // macro capability (see links above), and convert it into string data for a // list. To do this easily, as data should have quotes and be separated by // commas, I like to use a macro of the following Keystrokes: // // Home + " + End + " + , + Down Arrow // // You can use that for virtually the entire thing. Once you have done that, // input the data into the lists provided in Global Variables below. Simply // copy/paste the data as it appears in the sample lists, moving to a new list // every line the compiler throws an error (meaning you've reached the list's // data capacity). Once all that is done, touch the base object once and watch // the fun! // // // Script Limitations: // Since this is user-written technology, as opposed to admin-sponsored, I've // had to use the limitations of the system. As such, the real bottleneck here // is nothing more than how long lists can be and prims you have. Therefore, // the number of prims your dream object will be can easily get out of hand in// a hurry. Do not attempt this script with more than 1,000 faces to render, // unless you know what you're doing. // // // Official Plans for the Future of this Script: // This version of the script, at least, does not yet support the use of UV // coordinate data. However, since that is something that is included in an // OBJ file text dump, expect that to be something to go in relatively soon. //============================================================================
//============================================================================ // // Disclaimer: // // Unless you are a heavy LSL nerd, as I am, DO NOT read beyond this point. If // you do, don't blame me if your head explodes. // //============================================================================
//============================================================================ // // Global Variables // // list vertex = [ //Define your list of vertices here "v 0.000000 11.503699 0.000000", "v 0.000000 -11.746301 0.000000", "v 5.812500 -10.188846 0.000000", "v 5.033772 -10.188846 2.906250", "v 2.906250 -10.188846 5.033772", "v 0.000000 -10.188846 5.812500", "v -2.906250 -10.188846 5.033772", "v -5.033772 -10.188846 2.906250", "v -5.812500 -10.188846 0.000000", "v -5.033772 -10.188846 -2.906250", "v -2.906250 -10.188846 -5.033772", "v -0.000000 -10.188846 -5.812500", "v 2.906250 -10.188846 -5.033772", "v 5.033772 -10.188846 -2.906250", "v 10.067545 -5.933801 0.000000", "v 8.718750 -5.933801 5.033772", "v 5.033772 -5.933801 8.718750", "v 0.000000 -5.933801 10.067545", "v -5.033772 -5.933801 8.718750", "v -8.718750 -5.933801 5.033772", "v -10.067545 -5.933801 0.000000", "v -8.718750 -5.933801 -5.033772", "v -5.033772 -5.933801 -8.718750", "v -0.000000 -5.933801 -10.067545", "v 5.033772 -5.933801 -8.718750", "v 8.718750 -5.933801 -5.033772", "v 11.625000 -0.121301 0.000000", "v 10.067545 -0.121301 5.812500", "v 5.812500 -0.121301 10.067545", "v 0.000000 -0.121301 11.625000", "v -5.812500 -0.121301 10.067545", "v -10.067545 -0.121301 5.812500", "v -11.625000 -0.121301 0.000000", "v -10.067545 -0.121301 -5.812500", "v -5.812500 -0.121301 -10.067545", "v -0.000000 -0.121301 -11.625000", "v 5.812500 -0.121301 -10.067545", "v 10.067545 -0.121301 -5.812500", "v 10.067545 5.691199 0.000000", "v 8.718750 5.691199 5.033772", "v 5.033772 5.691199 8.718750", "v 0.000000 5.691199 10.067545", "v -5.033772 5.691199 8.718750", "v -8.718750 5.691199 5.033772", "v -10.067545 5.691199 0.000000", "v -8.718750 5.691199 -5.033772", "v -5.033772 5.691199 -8.718750", "v -0.000000 5.691199 -10.067545", "v 5.033772 5.691199 -8.718750", "v 8.718750 5.691199 -5.033772", "v 5.812500 9.946244 0.000000", "v 5.033772 9.946244 2.906250", "v 2.906250 9.946244 5.033772", "v 0.000000 9.946244 5.812500", "v -2.906250 9.946244 5.033772", "v -5.033772 9.946244 2.906250", "v -5.812500 9.946244 0.000000", "v -5.033772 9.946244 -2.906250", "v -2.906250 9.946244 -5.033772", "v -0.000000 9.946244 -5.812500", "v 2.906250 9.946244 -5.033772", "v 5.033772 9.946244 -2.906250" ]; list vertex2 = [ ];
list faces = //Define your list of faces here [ "f 2/1/1 3/2/2 4/3/3", "f 1/4/4 52/5/5 51/6/6", "f 2/7/1 4/3/3 5/8/7", "f 1/9/4 53/10/8 52/5/5", "f 2/11/1 5/8/7 6/12/9", "f 1/13/4 54/14/10 53/10/8", "f 2/15/1 6/12/9 7/16/11", "f 1/17/4 55/18/12 54/14/10", "f 2/19/1 7/16/11 8/20/13", "f 1/21/4 56/22/14 55/18/12", "f 2/23/1 8/20/13 9/24/15", "f 1/25/4 57/26/16 56/22/14", "f 2/27/1 9/24/15 10/28/17", "f 1/29/4 58/30/18 57/26/16", "f 2/31/1 10/28/17 11/32/19", "f 1/33/4 59/34/20 58/30/18", "f 2/35/1 11/32/19 12/36/21", "f 1/37/4 60/38/22 59/34/20", "f 2/39/1 12/36/21 13/40/23", "f 1/41/4 61/42/24 60/38/22", "f 2/43/1 13/40/23 14/44/25", "f 1/45/4 62/46/26 61/42/24", "f 2/47/1 14/44/25 3/48/2", "f 1/49/4 51/50/6 62/46/26", "f 3/2/2 15/51/27 16/52/28", "f 3/2/2 16/52/28 4/3/3", "f 4/3/3 16/52/28 5/8/7", "f 16/52/28 17/53/29 5/8/7", "f 5/8/7 17/53/29 18/54/30", "f 5/8/7 18/54/30 6/12/9", "f 6/12/9 18/54/30 7/16/11", "f 18/54/30 19/55/31 7/16/11", "f 7/16/11 19/55/31 20/56/32", "f 7/16/11 20/56/32 8/20/13", "f 8/20/13 20/56/32 9/24/15", "f 20/56/32 21/57/33 9/24/15", "f 9/24/15 21/57/33 22/58/34", "f 9/24/15 22/58/34 10/28/17", "f 10/28/17 22/58/34 11/32/19", "f 22/58/34 23/59/35 11/32/19", "f 11/32/19 23/59/35 24/60/36", "f 11/32/19 24/60/36 12/36/21", "f 12/36/21 24/60/36 13/40/23", "f 24/60/36 25/61/37 13/40/23", "f 13/40/23 25/61/37 26/62/38", "f 13/40/23 26/62/38 14/44/25", "f 14/44/25 26/62/38 3/48/2", "f 26/62/38 15/63/27 3/48/2", "f 15/51/27 27/64/39 16/52/28", "f 27/64/39 28/65/40 16/52/28", "f 16/52/28 28/65/40 29/66/41", "f 16/52/28 29/66/41 17/53/29", "f 17/53/29 29/66/41 18/54/30", "f 29/66/41 30/67/42 18/54/30", "f 18/54/30 30/67/42 31/68/43", "f 18/54/30 31/68/43 19/55/31", "f 19/55/31 31/68/43 20/56/32", "f 31/68/43 32/69/44 20/56/32", "f 20/56/32 32/69/44 33/70/45", "f 20/56/32 33/70/45 21/57/33", "f 21/57/33 33/70/45 22/58/34", "f 33/70/45 34/71/46 22/58/34", "f 22/58/34 34/71/46 35/72/47", "f 22/58/34 35/72/47 23/59/35", "f 23/59/35 35/72/47 24/60/36", "f 35/72/47 36/73/48 24/60/36", "f 24/60/36 36/73/48 37/74/49", "f 24/60/36 37/74/49 25/61/37", "f 25/61/37 37/74/49 26/62/38", "f 37/74/49 38/75/50 26/62/38", "f 26/62/38 38/75/50 27/76/39", "f 26/62/38 27/76/39 15/63/27" ]; list faces2 = [ "f 27/64/39 39/77/51 40/78/52", "f 27/64/39 40/78/52 28/65/40", "f 28/65/40 40/78/52 29/66/41", "f 40/78/52 41/79/53 29/66/41", "f 29/66/41 41/79/53 42/80/54", "f 29/66/41 42/80/54 30/67/42", "f 30/67/42 42/80/54 31/68/43", "f 42/80/54 43/81/55 31/68/43", "f 31/68/43 43/81/55 44/82/56", "f 31/68/43 44/82/56 32/69/44", "f 32/69/44 44/82/56 33/70/45", "f 44/82/56 45/83/57 33/70/45", "f 33/70/45 45/83/57 46/84/58", "f 33/70/45 46/84/58 34/71/46", "f 34/71/46 46/84/58 35/72/47", "f 46/84/58 47/85/59 35/72/47", "f 35/72/47 47/85/59 48/86/60", "f 35/72/47 48/86/60 36/73/48", "f 36/73/48 48/86/60 37/74/49", "f 48/86/60 49/87/61 37/74/49", "f 37/74/49 49/87/61 50/88/62", "f 37/74/49 50/88/62 38/75/50", "f 38/75/50 50/88/62 27/76/39", "f 50/88/62 39/89/51 27/76/39", "f 39/77/51 51/6/6 40/78/52", "f 51/6/6 52/5/5 40/78/52", "f 40/78/52 52/5/5 53/10/8", "f 40/78/52 53/10/8 41/79/53", "f 41/79/53 53/10/8 42/80/54", "f 53/10/8 54/14/10 42/80/54", "f 42/80/54 54/14/10 55/18/12", "f 42/80/54 55/18/12 43/81/55", "f 43/81/55 55/18/12 44/82/56", "f 55/18/12 56/22/14 44/82/56", "f 44/82/56 56/22/14 57/26/16", "f 44/82/56 57/26/16 45/83/57", "f 45/83/57 57/26/16 46/84/58", "f 57/26/16 58/30/18 46/84/58", "f 46/84/58 58/30/18 59/34/20", "f 46/84/58 59/34/20 47/85/59", "f 47/85/59 59/34/20 48/86/60", "f 59/34/20 60/38/22 48/86/60", "f 48/86/60 60/38/22 61/42/24", "f 48/86/60 61/42/24 49/87/61", "f 49/87/61 61/42/24 50/88/62", "f 61/42/24 62/46/26 50/88/62", "f 50/88/62 62/46/26 51/50/6", "f 50/88/62 51/50/6 39/89/51" ]; // // //============================================================================
generateFace(string face) { list vertices = []; vector primSize = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0); //======================================================================== //Step One: Find our vertices //Basically, this is where we convert our face gibberish into my gibberish //I won't go at length to explaining this, save to say it's just taking //the face values from our notecard, finding their counterpart vertices //(as in a real 3D engine), and spitting them out one by one. Since //faces can be more than just tris, I've written it thusly: // //Note this will scale the model based on the size of the root prim this //is in (Thanks, Arkyan Soujourner). //======================================================================== while(llSubStringIndex(face," ") != -1) { face = llDeleteSubString(face,0,llSubStringIndex(face," ")); string ourString; ourString = llList2String(vertex,(integer)llGetSubString(face,0,llSubStringIndex(face,"/") - 1) - 1); ourString = llDeleteSubString(ourString,0,1); while(llSubStringIndex(ourString," ") != -1) ourString = llGetSubString(ourString,0,llSubStringIndex(ourString," ") - 1) + "," + llGetSubString(ourString,llSubStringIndex(ourString," ") + 1,llStringLength(ourString) - 1); ourString = "<" + ourString + ">"; vector this = (vector)ourString; this = <this.x * primSize.x,this.y * primSize.y,this.z * primSize.z>; vertices += this; //Huzzah! Unless you screwed something up, we now have vector values! } //======================================================================== //Step Two: Generate list of three vertices for use //Just a simple list of values... // //Let's just bruteforce it. //======================================================================== integer i = 0; integer loop = llGetListLength(vertices) - 2; for(i = 0; i < loop; i++) { integer j; integer k; integer l; if(i == 0) { j = 0; k = 1; l = loop + 1; // You } else if(i == 1) { j = 1; k = 2; l = loop + 1; // Should } else if(i == 2) { j = 2; k = loop; l = loop + 1; // See } else if(i == 3) { j = 2; k = 3; l = loop; // A } else if(i == 4) { j = 3; k = loop - 1; l = loop; // Pattern } else if(i == 5) { j = 3; k = 4; l = loop - 1; // Forming } list currentVertices = [llList2Vector(vertices,j),llList2Vector(vertices,k),llList2Vector(vertices,l)]; //======================================================================== //Step Three: Find our largest edge. Since we only have 90 degrees //to work with by using Top Shear, and a triangle contains 180 degrees, //finding the largest edge of the three, by elimination, should give us //which vertices to base the prim on, and which to base our shear value on //Note that, since the trig tools for LSL are rudimentary at best, this is //a mite bit harder than it should* be. //======================================================================== float edge1 = llVecMag(llList2Vector(currentVertices,0) - llList2Vector(currentVertices,1)); float edge2 = llVecMag(llList2Vector(currentVertices,1) - llList2Vector(currentVertices,2)); float edge3 = llVecMag(llList2Vector(currentVertices,2) - llList2Vector(currentVertices,0)); integer largestEdge = 1; //default value if(edge2 >= edge1 && edge2 >= edge3) largestEdge = 2; else if(edge3 >= edge1 && edge3 >= edge2) largestEdge = 3; //======================================================================== //Step Four: The Hard Part (TM). If you haven't already wetted yourself by //reading the above, then this part will call for a clean change of //underwear. Now that we have our vertices and our largest edge, we need //to map each corner of a prim to them! And yes, that's even harder than //it sounds. // //So, sufficiently scared yet? Unless you're Xylor, you should be. //======================================================================== vector vector1; vector vector2; vector vector3; if(largestEdge == 1) { vector1 = llList2Vector(currentVertices,0); vector2 = llList2Vector(currentVertices,1); vector3 = llList2Vector(currentVertices,2); } else if(largestEdge == 2) { vector1 = llList2Vector(currentVertices,1); vector2 = llList2Vector(currentVertices,2); vector3 = llList2Vector(currentVertices,0); } else if(largestEdge == 3) { vector1 = llList2Vector(currentVertices,2); vector2 = llList2Vector(currentVertices,0); vector3 = llList2Vector(currentVertices,1); } llRezObject("Prim Face",llGetPos(),<0,0,0>,<0,0,0,1>,1); llSay(897,(string)vector1 + (string)vector2 + (string)vector3); } //Just kidding! The hard part happens in the actual faces. }
//============================================================================ //Enter the actual entrance code of the function. //Surprisingly, this doesn't do much, so I'll leave you to figure it out. //============================================================================
default { state_entry() { llSetText("",<1,1,0>,1.0); llSetObjectName("Facemaker"); } touch_start(integer total_number) { state de_facer; } } state de_facer { state_entry() { integer i; integer length = llGetListLength(faces); if(length > 0) for(i = 0; i < length; i++) generateFace(llList2String(faces,i)); length = llGetListLength(faces2); if(length > 0) for(i = 0; i < length; i++) generateFace(llList2String(faces2,i)); llSay(0,"Completed"); } }
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
01-17-2005 16:43
Part two of post above. Post buffer. //============================================================================ // Prim Face Creation Code // // For Use with Jeffrey Gomez's OBJ Model Importer For Second Life // // For Usage Instructions, Rights, and Other Relevant Info, See Other Script. // // Major Variables: // float thickness = 0.02; //Thickness of each face. string sim = ""; //Desired sim for script; Initialization only! //============================================================================
vector Proj(vector u, vector v) { // Return the projection of u onto v. // Special Thanks to Xylor Baysklef for jogging my memory on this return ( (u * v) / (v * v) ) * v; }
vector crossProduct(vector one, vector two) { //======================================================================== // This returns a Cross Product of two vectors. If you have no idea what // that means, look it up. // // Note no actual call to this function exists. This is because it exists // in LSL's modulus (%) command. It's simply from old code. //======================================================================== return <(one.y * two.z) - (one.z * two.y),(one.z * two.x) - (one.x * two.z),(one.x * two.y) - (one.y * two.x)>; }
integer g_listener = FALSE; //Just a measly listener. Ho hum. Don't hurt me. default { state_entry() { g_listener = llListen(897,"Facemaker","",""); llSetObjectName("Prim Face"); } on_rez(integer total_number) { if(llGetNumberOfPrims() > 1) llDie(); sim = llGetRegionName(); } //======================================================================== // Most of the hard stuff happens here. I'll explain it each time we run // across something, so if you don't understand it, that's my fault. // This data is called by a listener event, the listener of which is // promptly removed to save server load and keep faces from listening to // every command. Trust me, I had that happen. It wasn't pretty. //======================================================================== listen(integer chan, string name, key id, string msg) { llListenRemove(g_listener); //==================================================================== // // Phase One: Get Our Vectors // // Nothing unduly interesting here. We just take our string and get // the vector values we want from them. // //==================================================================== vector vector1 = (vector)llGetSubString(msg,0,llSubStringIndex(msg,">")); msg = llDeleteSubString(msg,0,llSubStringIndex(msg,">")); vector vector2 = (vector)llGetSubString(msg,0,llSubStringIndex(msg,">")); msg = llDeleteSubString(msg,0,llSubStringIndex(msg,">")); vector vector3 = (vector)llGetSubString(msg,0,llSubStringIndex(msg,">"));
//==================================================================== // // Phase Two: Edge Detection Calls // // Now comes the fun stuff. Since we've been passed our largest edge, // vector one and two, which prevents our script from causing problems // later, we now need to find which edge is closer to the odd vector // out (vector3). We do this because the smallest edge, or closest // vector, to it will make for a handy little edge on a 3D parallelo- // gram that we have to construct to find out points in this script // // If you're not lost yet, don't worry. There are plenty of places // along the way to fall off the bus. =] // //==================================================================== float edge1 = llVecMag(vector1 - vector3); float edge2 = llVecMag(vector2 - vector3); vector vect = (vector1 + vector2 + vector3) / 3; //Failsafe initialization //This constructs the last edge of our parallelogram. if(edge1 < edge2) { vect = vector3 - vector1; vect += vector2; } else { vect = vector3 - vector2; vect += vector1; } //==================================================================== // // Phase Three: Lots of Stuff Happens // // No better way to put it. Now, the reason we created that 3D // parallelogram (remember? That shape in math class that everyone // just called a crooked box) is because it's a pretty handy shape, // since the corners all have the same angle and, more importantly, // we can use one to find out the center of mass of the face! // // And now, for those of you that flunked math class. Center of Mass // is just a really long way of saying "Average Them, Stupid." // // Unfortunately, even with that center, we're not done. Once we have // it, we have to find the Primitive Center that Second Life uses. // That's a little harder. To do that, we borrow something from // Linear Algebra: Projections. Basically, we take a point in 3D and // project it onto a line, find where it is on the line, and go from // there. // // Said number will give us the value we can use to find Second Life's // center, or a fair approximation (see below). We then go from the // center of vectors one and two to the distance we just found. // // And that, ladies and gentlemen, is our center! *applause* // //==================================================================== vector duoCenter = (vector1 + vector2) / 2; vector Center = (vector1 + vector2 + vector3 + vect) / 4; vector dot = vector1 + Proj(Center - vector1,vector2 - vector1); vector Center2 = duoCenter + (Center - dot); //==================================================================== // // Phase Four: The Reason You Flunked Physics Class // // This is rather hard to explain. Simply put, though, a Cross Product // does something very, very very very very ... helpful for us here: // // It gives us a place to go. // // Okay. What it does for us here isn't quite that simple. Actually, // what it does for us is take our values, and extends an axis // perpendicular to them. That might not sound like much here, but // that does something really important, because the Linden sponsored // command, llAxes2Rot, turns axes into a rotation! Thanks, Lindens! // // </shameless plug> // // Anyway, after we do that, we finally go to where we want to go // and rotate to the proper rotation. // //==================================================================== vector fwd = ((vector2 - duoCenter) / llVecMag(vector2 - duoCenter)) % ((Center - dot) / llVecMag(Center - dot)); rotation rot = llAxes2Rot(fwd,((Center - dot) / llVecMag(Center - dot)) % fwd,(Center - dot) / llVecMag(Center - dot));
vector pos = llGetPos(); integer i = 0; while(pos + Center2 != llGetPos()) { i += 1; if(llGetRegionName() != sim) llDie(); llSetPos(pos + Center2); if(i >= 100) llDie(); } llSetPos(pos + Center2); llSetRot(rot); //==================================================================== // // Phase Final: "Tri" Means "Three" // // This took me a little while to figure out. What we do now is take // all of our data from above, and put a new dot on that imaginary // parallelogram, right on the edge between vector3 and the last // corner that we made earlier. We do this to toy with the Top Shear // value of a prim to emulate the final vertex. To do that, we just // see how far vector3 is from that new dot, and convert it to // something Second Life understands. // // Once that's done, we get to resize and reshape our prim, and we're // done! // // ... but wait, now all I have is a triangle! // // Ah, but that's the beauty of it. See, all those little triangles // will now take the shape of whatever your original object was! // //==================================================================== vector transpose = Center2 + (Center - dot); float shear = llVecMag(transpose - vector3) / llVecMag(vector2 - vector1); if(llVecMag(vector1 - dot) > llVecMag(vector2 - dot)) shear *= -1;
vector size = <thickness,2 * llVecMag(vector2 - duoCenter),2 * llVecMag(dot - Center)>;
llSetPrimitiveParams([PRIM_SIZE,size]); llSetPrimitiveParams([PRIM_TYPE,PRIM_TYPE_BOX,00,<0.000000, 1.000000, 0.000000>,0.000000,<0.000000, 0.000000, 0.000000>,<1.000000, 0.000000, 0.000000>,<0.000000, shear, 0.000000>]); integer j; integer tot = llGetInventoryNumber(INVENTORY_SCRIPT); for(j = 0; j < tot; j++) { if(llGetInventoryName(INVENTORY_SCRIPT,j) != llGetScriptName()) llRemoveInventory(llGetInventoryName(INVENTORY_SCRIPT,j)); } llRemoveInventory(llGetScriptName()); } } Re, Shadow Weaver: Yes, it converts Wavefront OBJ data into primitives, polygon by polygon. Since most 3D modellers (including those I suggested) can export to a Wavefront OBJ... 
|
Shadow Weaver
Ancient
Join date: 13 Jan 2003
Posts: 2,808
|
01-18-2005 09:59
So please to clarify this basically this program will take a .obj from wavefront currently and depending on the number of faces will convert those faces into individual primatives within SL to create the shape of the object you created in wavefront?
Interesting Idea severe drawbacks with the number of prims you have to utilize.
I do mean its unfortunate that we cannot import created .obj files but if we did then we would have 10 million xwing fighters and other things freely distributed in .obj format as well which then would restrict viewer capabilities even more.
I must congratulate you on your efforts here and will be following it much more closely as I am very interested in its outcome.
Sincerely, Shadow Weaver
_____________________
Everyone here is an adult. This ain't DisneyLand, and Mickey Mouse isn't going to swat you with a stick if you say "holy crapola."<Pathfinder Linden> New Worlds new Adventures Formerly known as Jade Wolf my business name has now changed to Dragon Shadow. Im me in world for Locations of my apparrel Online Authorized Trademark Licensed Apparel http://www.cafepress.com/slvisionsOR Visit The Website @ www.slvisions.com
|
Synergy Belvedere
Prim Reaper
Join date: 7 Jul 2004
Posts: 253
|
01-26-2005 12:41
**Bows down and worships you**
Simply awesome!
|
Nicky Turnbull
Registered User
Join date: 6 Feb 2005
Posts: 25
|
02-07-2005 16:07
one question, the first script goes into a random object (a cube prim i guess) and then the second script goes in a cube prim and then is put in the random object?
then how do u get the .obj to text? do can i use monkey boxer? i have uv mapper and milkshape 3d.
so the macro text then goes in above the "v and below the //define????????????
//================================================== ========================== // // Global Variables // // list vertex = [ //Define your list of vertices here RIGHT HERE? "v 0.000000 11.503699 0.000000",
and what about making new lists???
thanks for your help, i've tried making models in milkshape and its easier than in second life, i have a nice paintball gun modeled, should only be 28 faces too
|
Nicky Turnbull
Registered User
Join date: 6 Feb 2005
Posts: 25
|
02-07-2005 16:15
one question, the first script goes into a random object (a cube prim i guess) and then the second script goes in a cube prim and then is put in the random object?
then how do u get the .obj to text? do can i use monkey boxer? i have uv mapper and milkshape 3d.
so the macro text then goes in above the "v and below the //define????????????
//================================================== ========================== // // Global Variables // // list vertex = [ //Define your list of vertices here RIGHT HERE? "v 0.000000 11.503699 0.000000",
and what about making new lists???
thanks for your help, i've tried making models in milkshape and its easier than in second life, i have a nice paintball gun modeled, should only be 28 faces too
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
02-08-2005 11:23
Any prim will do for both scripts. Simply deposit the face code in a prim, the importer code into another prim, then put the prim-with-face-code into your second prim. Any program that will output a Wavefront .OBJ will suffice. There's a small problem with programs that use more than six significant digits in their points (ie. 1.12345678 throws an error), but most do not and I can fix this if it becomes a severe problem. Simply outputting the OBJ file by another program will fix this, presently. You put your vertices (those with a "v"  in the vertex list, and your polygons/faces (those with an "f"  in the faces list. Adding more lists would require rewriting much of the code. You can do so if you want... but I wouldn't advise it unless you know what you're doing. I have reasons for those limitations. Hope that helps.
_____________________
---
|
Alysa DeFarge
Registered User
Join date: 31 Jan 2005
Posts: 77
|
02-09-2005 12:27
I'm very interrested in this.. I do alot of 3d modelling and making of furniture, clothing etc... Am I understanding it right as in, each face of the model, will be 1 or more prims? so if I make something like this for example My Clock [img src=http://www.models-by-jenc.com/Rendo-thumbs/JenCClockTN.jpg] with all the beveled edges and rounded parts this thing could be in the millions of prims??
|
Alysa DeFarge
Registered User
Join date: 31 Jan 2005
Posts: 77
|
02-09-2005 12:30
I'm very interrested in this.. I do alot of 3d modelling and making of furniture, clothing etc... Am I understanding it right as in, each face of the model, will be 1 or more prims? so if I make something like this for example My Clock with all the beveled edges and rounded parts this thing could be in the millions of prims??
|
Mia Jackson
Second Life Resident
Join date: 25 Oct 2004
Posts: 86
|
02-09-2005 12:55
Could someone tell me...in newbie terms lol, what this program does? It seems like its very important, but I have no idea why. 
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
02-10-2005 17:41
Posting replies here is a tad difficult. I may start adding comments to the top via edits (which don't wait for authorization) if needed. Alysa: Correct - unless the beveled edges are done with a NURBs algorithm, it'll probably result in several prims to make a curve. Since it would be difficult to use LSL to generate prims as a "best fit" to a mesh without having the script be unbelievably slow (I've given it thought though!), the script above will split curves and faces into tris and spit out a prim for each one. Sounds authoritarian, but it falls on the creator to create a model that's prim-efficient. I am working on other options, but for now this is the easiest method, for me as for users. In layman terms, the script takes the polygon data from a file (Wavefront OBJ format), and converts it to prims for each polygon. This can get unwieldy in a hurry, but works great for very large builds, as a reference, or just for the heck of it. Hopefully I'll get to developing the other methods I have ideas for, but with my day schedule, that's not a promise. 
_____________________
---
|
Csven Concord
*
Join date: 19 Mar 2005
Posts: 1,015
|
03-21-2005 12:48
interesting. this sounds like .map exporters - where each face is extruded. i'll have to play with this. but also wondering if anyone has had problems with "overlap". the .map exporters i've used tend to create co-spatial multiples; unnoticed until you try to edit.
|
Jacob Thatch
Senior Member
Join date: 31 Mar 2005
Posts: 146
|
.........duuuhhhh...ummmmm
04-12-2005 21:25
yeah...... seeing how i am no scripter and my shirt says im with stupid and points up i was wandering if someone couled maybe help me use this in game, im almost always on sl on my free time. this wouled be greatly apreciated, i have a wearwolf 3d modle a friend gave me and wouled like to uploed it to sl. 
|
Onyx Claveau
Registered User
Join date: 9 Jul 2005
Posts: 5
|
This is going to sound quite stupid but...
07-13-2005 17:47
Is there some sort of program or anything that will take my large list of vertices and faces and surround them with the quotations and the comma needed for the script? It takes way too long to copy and paste each vertice and face number into the script.
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
07-13-2005 18:19
Yep! Download the text macro I provided up at the top and run it in any program that supports macros. And yes, a better version of this is coming as soon as I can devote the time to it. 
_____________________
---
|
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
|
Notecard reading abilities for Jeffrey's script
07-14-2005 11:53
Here's a modification of jeffrey's rezzing script. It allows you to put the vertex and face data into notecards instead of lists. However, it still needs to be in the same format. The face notecard should be named "faces" (without quotes), though this can be changed by modifying the global constant named FACE_CARD_NAME. Each line in the face notecard should be something like this: f 35/72/47 48/86/60 36/73/48 The vertex notecard should be named "vertices" (without quotes), though this can be changed by modifying the global constant named VERTEX_CARD_NAME. Each line in the vertex notecard should be something like this: v 0.000000 5.691199 10.067545 Both notecards must be in the inventory of the object and must have full permissions for the rezzor to function. The parser will ignore lines in the faces notecard that don't start with an "f", but if there is any whitespace or incorrectly formatted text in the vertices notecard, then the script will choke and shut down. I wrote it so it would hit the dataserver as little as possible, and thus it should be reasonably quick, though Jeffrey's original script will undoubtedly be faster (LSL is slow at reading notecards). Be EXTREMELY careful with this, each face is a seperate prim, so if you try and rez 50,000 prims, your neighbors might want to kill you  Ive programmed it so that if it is touched while the reading process is occuring, it shuts itself down, so if you inadvertantly start it, just touch it to shut it back down. Though note that it does *not* undo what has already been done, so if you dont catch your mistake quick, you'll still end up with a 10,000 prim mess. // Version 0.3.1 //================================================== ========================== // OBJ Model Importer For Second Life // Written by Jeffrey Gomez // Notecard capabilities added by Christopher Omega // // Permissions Granted to Edit, Copy, Transfer, and Sell this script // to any user, so long as this comment set remains intact, and is // granted WITHOUT ANY WARRANTY. USE AT OWN RISK. And enjoy. =] // // Any unauthorized or illegal usage of this script, as dictated by International Laws // of Copyright or Linden Labs voids any license to use this script. Creator of // this script is not responsible for said use. So please, don't come after me. :D // // Original Date of Creation: January 7th, 2005 // // Forum Thread URL(s): // http://forums.secondlife.com/showthread.php?t=32491 // http://forums.secondlife.com/showthread.php?t=32283 // // // Special Thanks: // Xylor Baysklef for reminding me that projections exist // Strife Onizuka for various suggestions for UVs // // // Suggested Free Tool URLS: // Paint - The GIMP: www.gimp.org // 3D - Blender: www.blender.org // 3D - Anim8or: www.anim8or.com // UV Mapper - UV Mapper: www.uvmapper.com // Text Editor - jEdit: www.jedit.com // // Suggested Inexpensive Tool URLS: // 3D - Milkshape (~$25): www.swissquake.ch/chumbalum-soft // UV Mapper - UV Mapper Pro (~$25): www.uvmapper.com // // ... so don't complain I never did anything for you. =P // // // Script Purpose and Usage: // The purpose of this script is very simple. For quite some time now, people // have been griping that there has been no way to import models from 3D tools // directly into Second Life. This script uses a common methodology of 3D // design tools, tris, to mimic faces in Second Life. // // To use this script set, simply place the Prim Face Code into a Cube Prim, // place this code into another object, then place said Cube Prim into the // object. Once you have done so, open up your OBJ file in a text editor with // macro capability (see links above), and convert it into string data for a // list. To do this easily, as data should have quotes and be separated by // commas, I like to use a macro of the following Keystrokes: // // Home + " + End + " + , + Down Arrow // // You can use that for virtually the entire thing. Once you have done that, // input the data into the lists provided in Global Variables below. Simply // copy/paste the data as it appears in the sample lists, moving to a new list // every line the compiler throws an error (meaning you've reached the list's // data capacity). Once all that is done, touch the base object once and watch // the fun! // // // Script Limitations: // Since this is user-written technology, as opposed to admin-sponsored, I've // had to use the limitations of the system. As such, the real bottleneck here // is nothing more than how long lists can be and prims you have. Therefore, // the number of prims your dream object will be can easily get out of hand in // a hurry. Do not attempt this script with more than 1,000 faces to render, // unless you know what you're doing. // // // Official Plans for the Future of this Script: // This version of the script, at least, does not yet support the use of UV // coordinate data. However, since that is something that is included in an // OBJ file text dump, expect that to be something to go in relatively soon. //================================================== ==========================
//================================================== ========================== // // Disclaimer: // // Unless you are a heavy LSL nerd, as I am, DO NOT read beyond this point. If // you do, don't blame me if your head explodes. // //================================================== ==========================
//================================================== ========================== // // Global Constants // // // Each vertex must be on its own line in the vertex notecard. No whitespace is allowed. // The same rule applies for faces in the face notecard. string VERTEX_CARD_NAME = "vertexes"; string FACE_CARD_NAME = "faces"; string FACE_OBJ_NAME = "Prim Face"; integer CACHE_SIZE = 100; // ^^ The size of the vertex cache. Make it bigger for faster performance, but make it too big and the script may crash. // // //================================================== ==========================
//================================================== ========================== // // Global Variables // // key cacheSource; // Stores the key of the notecard that was used to fill the cache, useful for determining cache freshness. list vertexLines; // List of vertex indexes required by the face currently being processed. (built in state getFace) list vertexes; // List of vertexes required by the face currently being processed. (built in state getVertexes) integer faceLine; // Line in the face notecard that indicates the next face to process list vertexCache; // Cache of vertex lines -> vertex mappings - so the dataserver doesn't need to be used as much. // // //================================================== ==========================
rezFace(list vertexes) { //================================================== ====================== //Step One: Find our vertexes //Basically, this is where we convert our face gibberish into my gibberish //I won't go at length to explaining this, save to say it's just taking //the face values from our notecard, finding their counterpart vertexes //(as in a real 3D engine), and spitting them out one by one. Since //faces can be more than just tris, I've written it thusly: // //Note this will scale the model based on the size of the root prim this //is in (Thanks, Arkyan Soujourner). //================================================== ====================== // We have to do the scaling now so that the values in the cache // aren't specific to any particular scale. integer i = 0; integer len = llGetListLength(vertexes); vector scale = llGetScale(); for (i = 0; i < len; ++i) { vector vertex = llList2Vector(vertexes, i); vertex = <vertex.x * scale.x, vertex.y * scale.y, vertex.z * scale.z>; vertexes = llListReplaceList(vertexes, [vertex], i, i); } //================================================== ====================== //Step Two: Generate list of three vertexes for use //Just a simple list of values... // //Let's just bruteforce it. //================================================== ====================== integer loop = llGetListLength(vertexes) - 2; for(i = 0; i < loop; i++) { integer j; integer k; integer l; if(i == 0) { j = 0; k = 1; l = loop + 1; // You } else if(i == 1) { j = 1; k = 2; l = loop + 1; // Should } else if(i == 2) { j = 2; k = loop; l = loop + 1; // See } else if(i == 3) { j = 2; k = 3; l = loop; // A } else if(i == 4) { j = 3; k = loop - 1; l = loop; // Pattern } else if(i == 5) { j = 3; k = 4; l = loop - 1; // Forming } list currentVertexes = [llList2Vector(vertexes,j),llList2Vector(vertexes,k ),llList2Vector(vertexes,l)];
//================================================== ====================== //Step Three: Find our largest edge. Since we only have 90 degrees //to work with by using Top Shear, and a triangle contains 180 degrees, //finding the largest edge of the three, by elimination, should give us //which vertexes to base the prim on, and which to base our shear value on //Note that, since the trig tools for LSL are rudimentary at best, this is //a mite bit harder than it should* be. //================================================== ====================== float edge1 = llVecMag(llList2Vector(currentVertexes,0) - llList2Vector(currentVertexes,1)); float edge2 = llVecMag(llList2Vector(currentVertexes,1) - llList2Vector(currentVertexes,2)); float edge3 = llVecMag(llList2Vector(currentVertexes,2) - llList2Vector(currentVertexes,0)); integer largestEdge = 1; //default value if(edge2 >= edge1 && edge2 >= edge3) largestEdge = 2; else if(edge3 >= edge1 && edge3 >= edge2) largestEdge = 3; //================================================== ====================== //Step Four: The Hard Part (TM). If you haven't already wetted yourself by //reading the above, then this part will call for a clean change of //underwear. Now that we have our vertexes and our largest edge, we need //to map each corner of a prim to them! And yes, that's even harder than //it sounds. // //So, sufficiently scared yet? Unless you're Xylor, you should be. //================================================== ====================== vector vector1; vector vector2; vector vector3; if(largestEdge == 1) { vector1 = llList2Vector(currentVertexes,0); vector2 = llList2Vector(currentVertexes,1); vector3 = llList2Vector(currentVertexes,2); } else if(largestEdge == 2) { vector1 = llList2Vector(currentVertexes,1); vector2 = llList2Vector(currentVertexes,2); vector3 = llList2Vector(currentVertexes,0); } else if(largestEdge == 3) { vector1 = llList2Vector(currentVertexes,2); vector2 = llList2Vector(currentVertexes,0); vector3 = llList2Vector(currentVertexes,1); } llRezObject(FACE_OBJ_NAME,llGetPos(),<0,0,0>,<0,0,0,1>,1); llSay(897,(string)vector1 + (string)vector2 + (string)vector3); } //Just kidding! The hard part happens in the actual faces. }
cacheVertex(vector vertex, integer line) { integer cacheIndex = llListFindList(vertexCache, [line]); if (cacheIndex != -1) // Remove the entry we're modifying vertexCache = llDeleteSubList(vertexCache, cacheIndex, cacheIndex + 1); if (llGetListLength(vertexCache) / 2 > CACHE_SIZE) // Cache is too big. vertexCache = llDeleteSubList(vertexCache, 0, 1); // Remove the oldest entry vertexCache += [line, vertex]; }
vector getCachedVertex(integer line) { integer cacheIndex = llListFindList(vertexCache, [line]); if (cacheIndex != -1) return llList2Vector(vertexCache, cacheIndex + 1); return ZERO_VECTOR; }
default { state_entry() { llSetText("", <1,1,0>, 1.0); llSetObjectName("Facemaker"); } touch_start(integer total_number) { integer ready = TRUE; if (llGetInventoryKey(FACE_CARD_NAME) == NULL_KEY) { llOwnerSay("Error: \"" + FACE_CARD_NAME + "\" does not exist in the object's inventory."); ready = FALSE; } if (llGetInventoryKey(VERTEX_CARD_NAME) == NULL_KEY) { llOwnerSay("Error: \"" + VERTEX_CARD_NAME + "\" does not exist in the object's inventory."); ready = FALSE; } if (llGetInventoryKey(FACE_OBJ_NAME) == NULL_KEY) { llOwnerSay("Error: \"" + FACE_OBJ_NAME + "\" does not exist in the object's inventory."); ready = FALSE; } if (ready) { // Start from the beginning of the face notecard. faceLine = 0; state getFace; } } } // Used so we can go into state getFace from state getFace. state __getFace{state_entry(){state getFace;}} // In state getFace, we read one face from the face notecard, on the line stored in faceLine. state getFace { state_entry() { llGetNotecardLine(FACE_CARD_NAME, faceLine); } dataserver(key queryid, string data) { if (data == EOF) { llOwnerSay("Completed."); state default; } else { // Parse the line into "f" and "a/b/c" clumps. list parsedLine = llParseString2List(data, [" "], []); if (llList2String(parsedLine, 0) == "f") { integer len = llGetListLength(parsedLine); integer i; for (i = 1; i < len; ++i) { // indexData is in the form "a/b/c", where a. b and c are integers. We want only a. string indexData = llList2String(parsedLine, i); vertexLines += (integer)llGetSubString(indexData, 0, llSubStringIndex(indexData, "/")) - 1; } vertexes = []; ++faceLine; state getVertexes; } else { ++faceLine; state __getFace; } } } touch_start(integer total_num) { llOwnerSay("Rezzing operation aborted."); state default; } }
// Used so we can go into state getVertexes from state getVertexes. state __getVertexes{state_entry(){state getVertexes;}} state getVertexes { state_entry() { // We're using the vertexLines list like a stack, // processing the first element (index 0) in the lines list, // then popping it off in state_exit. if (llGetListLength(vertexLines) == 0) { // We're done getting the vertexes for the face. rezFace(vertexes); state getFace; } else { // We need to get the vertex, first try getting it from the cache, // then use the dataserver. // Before accessing the cache, ensure the cache is fresh. if (cacheSource != llGetInventoryKey(VERTEX_CARD_NAME)) { vertexCache = []; cacheSource = llGetInventoryKey(VERTEX_CARD_NAME); } integer vertexLine = llList2Integer(vertexLines, 0); vector cachedVertex = getCachedVertex(vertexLine); if (cachedVertex != ZERO_VECTOR) { vertexes += cachedVertex; state __getVertexes; } else { llGetNotecardLine(VERTEX_CARD_NAME, vertexLine); } } } state_exit() { // Pop the line we just got finished with off of the stack. vertexLines = llDeleteSubList(vertexLines, 0, 0); } dataserver(key query, string data) { if (data == EOF) { llOwnerSay("Error: Vertex " + (string) llList2Integer(vertexLines, 0) + " required by face on line# " + (string) (faceLine - 1) + " is not defined in the vertex notecard."); state default; } else { if (llGetSubString(data, 0, 0) == "v") { // Turn "v x y z" (where x y and z are floats) into "<x,y,z>" and make it a vector. vector vertex = (vector)("<" + llDumpList2String( llParseString2List(llDeleteSubString(data, 0, 1), [" "], []), ",") + ">"); cacheVertex(vertex, llList2Integer(vertexLines, 0)); vertexes += vertex; state __getVertexes; } else { llOwnerSay("Error: Badly formatted vertice notecard, cannot parse line#" + (string)llList2Integer(vertexLines, 0)); state default; } } } touch_start(integer total_num) { llOwnerSay("Rezzing operation aborted."); state default; } }
Ive tested it with a few models, and it seems to work pretty well. Attached is an example of a vertices and faces notecard. ==Chris
|
Velox Severine
Network Slave
Join date: 19 May 2005
Posts: 73
|
07-15-2005 13:12
_____________________
--BEGIN SIGNATURE STRING-- IkkgY2FtZSwgSSBzYXcsIEkgY29ucXVlcmVkLiIgLS1KdWxpdXMgQ2Flc2Fy --END SIGNATURE STRING--
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
07-16-2005 02:52
Yeah, I know. My newer stuff uses it, and I have a parallel project to start that utilizes precisely that.
_____________________
---
|
Sorgaard Jacques
Registered User
Join date: 8 Feb 2005
Posts: 3
|
Suggestion...
08-12-2005 13:42
It is great work you have done...really. But the main problem topic seems to be connected to the vast number of prims generated ny the script. So, i just had a thought, could the script utilize the VRML or .WRL code instead. VRML uses Geometry data as well as vertex data. In that way you can build effective models using Primitives like Cube or Sphere and have them translated into SL primitives. That would surly generate much more effective models...yes, just a thought!
S J
|
a lost user
Join date: ?
Posts: ?
|
08-29-2005 03:32
so basically would making a 10x10 cube would take 6 prims?
i can still see where this can be helpful for making a house and deleting the unessisary prims ^.^
i am a lil afraid to test it though...
oh heck i will have to try is anyway ^.^
i am trying to think of what OBJ to test it with though...
|
Coadey Concord
Registered User
Join date: 9 Jul 2005
Posts: 25
|
Re: Prim Generator
09-06-2005 09:39
The script is a great idea, and must have taken a lot of work!
However, one of SL's benefits is maintaining a level playing field for builders. With this tool, anyone can download complex OBJ files and auto-rez them with no work at all.
Please keep in mind that people already go nuts with prims, generating Sim lag for everyone, and using this script will probably be considered prim-bombing by land owners.
|
Logan Bauer
Inept Adept
Join date: 13 Jun 2004
Posts: 2,237
|
09-25-2005 09:48
<Puts Jeffrey Gomez bobblehead up on his FIC shrine right between Adam Zaius bobblehead and Hank Ramos bobblehead. Yes, that high up the ladder.  > While I don't use any other 3-D modeling programs much anymore, HOLY CRAPOLA! <is swatted by Mickey Mouse> Amazing stuff.
|
Zodiakos Absolute
With a a dash of lemon.
Join date: 6 Jun 2005
Posts: 282
|
09-26-2005 12:06
From: someone Please keep in mind that people already go nuts with prims, generating Sim lag for everyone, and using this script will probably be considered prim-bombing by land owners. Hmm, you mean on attachments, right? I'm pretty sure you should still be able to use your entire parcel's allotment on prims, regardless of your neighbor's protests. If you can't use all of your allotment of prims on your own land without causing problems, they should be blameing LL, not you. Yes, I can see why this would be bad in the creation of attachments... imagine using this to rez that zillion face avatar...
|