Jump to content

Help understanding faces and rotations in prims


KevinLeap
 Share

You are about to reply to a thread that has been inactive for 3942 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I am new at scripting and am trying to learn how to develop scripts to assist building. I am studying the OpenAlign script by Edward L. Platt and find that I am super confused by some of the operations it performs when translating from rotations to faces to textures. Is there any reference that explains how prims information is accessed, or the meta model used to record this information? Any assistance or suggestions would be appreciated.

 

Thank you

 

 

Link to comment
Share on other sites

Faces are easier than rotations.

To find out which face you want to texture:-

  1. Edit the object
  2. Set the Edit mode to Select Face
  3. Select the face you want to texture
  4. Use Ctrl+Alt+Shift+T to get texture information and the relevant face number.
  5. Use the face number in your script

Has anyone made a reference model? Not really, though I suppose you could take a look at the Ivory Tower of Prims.

Link to comment
Share on other sites

Thanks, for the info, but I'm talking about how to understand the programatic aspect of doing this...

 

The script I am reading talks about Euler coordinates and converting from global rotations to local rotations. I want to find a reference that describes how this information is kept so that I have half a chance to understand the script I am working with. The OpenAlign script tries to make secondary prims match the texture mapping of the primary prim. It seems to do this ok, but does not adjust the offsets on the textures correctly to match the horizonatl or vertical distance of the prim from the primary. Reading the script, it seems to do some things as though by magic making it very difficult to understand where I can make adjustments to the code to add in the behavior I want.

Some reference documentation on how the prim faces are stored might enable me to understand this better.

I may be asking a question that is so far over my head that I cannot pose it correctly.


Thank you.

Link to comment
Share on other sites

Aha, no problem. I think we missed each other. My responses are keyed to the perceived skill level, maturity and technical capability of the user I'm addressing; determination of this is not an exact science.

I am not familiar with OpenAlign, it may be rewarding for you to paste the script contents into a post here, using the Code button (5th icon along in the Post Message > Body section, looks like a clipboard with a 'C' on it) so that I and others here can be sure of the script you're trying to adjust. Users here might also be able to expand on the parts that seem to be magical.

Prim faces, internal rotation and other such features are very much dependant on prim type and other prim attributes. Rotations are tricky in themselves, but all can be reduced to either radians (euler), quarternoins (rotation) or degrees (like the Edit box). I am not sure what you are trying to achieve but it seems unlikely that a single script will work for this in every possible instance and application. Perhaps explain what you're trying to do, and add a picture or two?

 Links have been included with some reference information, but I personally never found the explanations too helpful. http://wiki.secondlife.com might also be useful, but I have found it lacks decent examples.

Link to comment
Share on other sites

The code for OpenAlign 1.1 can be found at http://ucslteam.wikispaces.com/Texture+Align for those of you interested in the program. But I have to question how useful it might be to a person starting out to learn LSL, in that many of the things being done would be somewhat opaque without a deeper understanding of what primitives are about.

 

I'll second Freya's suggestion to go through the work stations in the Ivory Tower of Prims, which is an excellent coverage of the subject. And, after working through that, doing your own experimentations to determine exactly what does what to which in the (somewhat) lengthy parameter list each prim has.

 

As far as a meta-model for primitives, one can find that in the open source viewer file LLVolume.cpp. However it is not well documented and will most likely leave one more confused than ever (though one of the original developers of SL primitives does take a stab at it in http://www.realityprime.com/blog/2008/08/how-sl-primitives-really-work/ ).

Link to comment
Share on other sites

Thanks for the additional info. You were probably not far wrong when it comes to my expertise and experience, however I have been a life long software developer and this language seems to be a close match to Java and JavaScript with some very interesting additions so with false confidence, I thought I should be able to just open up the code and fix it. However I am brand new to SL scripting and even newer at understanding the environment and data structures that SL uses and this code seems to be much more complex than I had imagined.


I came on this problem when I was trying to build a simple wall with a door and found that making the textures align was more difficult than I anticipated. I bought some scripts to help with alignment (you put the scripts into the contents of the prims and link them together and then typically type "/1 align" to cause the script to make the texture align with the primary prim). I found that the alignment was not being performed reliably and searched for a solution. I found this open source code that looks like it should do what I want, but I find it doesn't seem to adjust the offsets for the textures so that they all line up. I decided that I should be able to understand the code and figure out what was needed to accomplish this. When I opened up the code, I found it to be amazingly complex for what sounds like a simple task. Full of face selection, scaling, cut calculations and rotation translations. Obviously this is open source so whatever additions I put into it will also carry the original copyright info.

I am looking for a reference document that might describe how textures are stored, and how the rotations fit into the scheme. Once I have that, I can either adjust OpenAlign or write my own alignment script.

 

Thank you

 

//// OpenAlign 1.1// Second Life Texture Alignment Script// Copyright 2008 Edward L. Platt// SL: Phil Tracy// E-mail: <elplatt@alum.mit.edu>//// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program.  If not, see <http://www.gnu.org/licenses/>.//////////////////////////////////////////////////////////////////////////  //// GLOBAL VARIABLES //// // Script name in inventorystring SCRIPT_NAME = "OpenAlign"; // Channel to listen oninteger LISTEN_CHANNEL = 1; // 1 for debug mode, 0 otherwiseinteger DEBUG = 0; // Properties of rootvector rootSize;        // Sizevector rootPos;         // Positioninteger rootFaceCount;  // Number of faceslist rootTexScaleList;  // Texture scales (width0,height0,width1...)vector rootCut;         // Cut //// GLOBAL FUNCTIONS //// // Joins string elements from a list with spaces// Calculate the modulus of a / bfloat mod(float a, float b) {    return a/b - llFloor(a/b);} // Broadcast a message on LISTEN_CHANNELbroadcast(string message) {    if (DEBUG) {        llSay(0, message);    }    llSay(LISTEN_CHANNEL, message);} // Get the position, width, and height of the cut faceslist getCutParams(float cutBegin, float cutEnd, rotation q) {     integer beginQuad;  // Quadrant cut begins in    integer endQuad;    // Quadrant cut ends in    vector size;        // Size of this object    vector pos;         // Position of this object     vector beginPos;   // Begin face position    vector endPos;     // End face position    vector beginSize;  // Size of begin face    vector endSize;    // Size of end face     float angle;  // Angle of the face (radians)     // Get size    size = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0);     // Calculate beginning face parameters    angle = cutBegin * TWO_PI - PI*3.0/4.0;    float x;    float y;     // Calculate the dimensions of the beginning face without scaling    if (cutBegin < 0.25) {        y = -0.5;        x = y / llTan(angle);    } else if (cutBegin >= 0.5 && cutBegin < 0.75) {        y = 0.5;        x = y / llTan(angle);    } else if (cutBegin >= 0.25 && cutBegin < 0.5) {        x = 0.5;        y = x * llTan(angle);    } else {        x = -0.5;        y = x * llTan(angle);    }     // Calculate the width of the beginning face with scaling    beginSize.x = llSqrt(size.x*size.x * x*x + size.y*size.y * y*y);     // Set the height of the beginning face    beginSize.y = size.z;     // Calculate beginning face position    beginPos = <x*size.x/2.0, y*size.y/2.0, 0>;    beginPos = beginPos * q;     // Calculate end face parameters    angle = cutEnd * TWO_PI - PI*3.0/4.0;     // Calculate the dimensions of the end face without scaling    if (cutEnd < 0.25) {        y = -0.5;        x = y / llTan(angle);    } else if (cutEnd >= 0.5 && cutEnd < 0.75) {        y = 0.5;        x = y / llTan(angle);    } else if (cutEnd >= 0.25 && cutEnd < 0.5) {        x = 0.5;        y = x * llTan(angle);    } else {        x = -0.5;        y = x * llTan(angle);    }     // Calculate the width of the end face with scaling    endSize.x = llSqrt(size.x*size.x * x*x + size.y*size.y * y*y);     // Set the height of the end face    endSize.y = size.z;     // Calculate beginning face position    endPos = <x*size.x/2.0, y*size.y/2.0, 0>;    endPos = endPos * q;     return [beginPos, beginSize, endPos, endSize];} // Get face list from rotationlist getFaceList(rotation q) {     vector rot;     // Rotation in Euler coordinates    list faces;     // Indices of faces    list newFaces;  // Temporary indices of faces    integer zRot;       // Number of 90 degree Z rotations    integer yRot;       // Number of 90 degree Y rotations    integer xRot;       // Number of 90 degree X rotations     // Get Euler coordinates    rot = llRot2Euler(q);     // Initialize faces    faces = [0, 1, 2, 3, 4, 5];     // Permute faces according to rotations in Z, Y, X order     // Adjust ranges    zRot = (integer)llRound(rot.z / PI_BY_TWO);    yRot = (integer)llRound(rot.y / PI_BY_TWO);    xRot = (integer)llRound(rot.x / PI_BY_TWO);    while (zRot < 0) {        zRot += 4;    }    while (yRot < 0) {        yRot += 4;    }    while (xRot < 0) {        xRot += 4;    }     // Permute faces for Z rotation    while (zRot > 0) {        newFaces = [];        newFaces += llList2Integer(faces, 0);        newFaces += llList2Integer(faces, 4);        newFaces += llList2Integer(faces, 1);        newFaces += llList2Integer(faces, 2);        newFaces += llList2Integer(faces, 3);        newFaces += llList2Integer(faces, 5);        faces = newFaces;        zRot--;    }     // Permute faces for Y rotation    while (yRot > 0) {        newFaces = [];        newFaces += llList2Integer(faces, 4);        newFaces += llList2Integer(faces, 1);        newFaces += llList2Integer(faces, 0);        newFaces += llList2Integer(faces, 3);        newFaces += llList2Integer(faces, 5);        newFaces += llList2Integer(faces, 2);        faces = newFaces;        yRot--;    }     // Permute faces for X rotation    while (xRot > 0) {        newFaces = [];        newFaces += llList2Integer(faces, 3);        newFaces += llList2Integer(faces, 0);        newFaces += llList2Integer(faces, 2);        newFaces += llList2Integer(faces, 5);        newFaces += llList2Integer(faces, 4);        newFaces += llList2Integer(faces, 1);        faces = newFaces;        xRot--;    }     return faces;} // Return the object face index of the specified global face// Faces are specified as "+x", "-y", "cutBegin", "cutEnd", etc.integer getFace(string face, vector cut, rotation q) {     // Variables representing whether a face is present    // 1 is present, 0 is not, except for zp=0 which is always present    integer xp = 1; // +x    integer xm = 1; // -x    integer yp = 1; // +y    integer ym = 1; // -y    integer zp = 0; // +z    integer zm = 1; // -z    integer cb = 1; // cut begin    integer ce = 1; // cut end     list faces;         // List mapping global faces to object faces    string mappedFace;  // Local face, after global face rotated    list faceOrder;     // The order of the faces     // Set face order    faceOrder = ["+z", "-y", "+x", "+y", "-x", "-z", "cutBegin", "cutEnd"];     // Get face mapping    faces = getFaceList(q);     // Map face    if (face == "+z") {        mappedFace = llList2String(faceOrder, llList2Integer(faces, 0));    } else if (face == "-y") {        mappedFace = llList2String(faceOrder, llList2Integer(faces, 1));    } else if (face == "+x") {        mappedFace = llList2String(faceOrder, llList2Integer(faces, 2));    } else if (face == "+y") {        mappedFace = llList2String(faceOrder, llList2Integer(faces, 3));    } else if (face == "-x") {        mappedFace = llList2String(faceOrder, llList2Integer(faces, 4));    } else if (face == "-z") {        mappedFace = llList2String(faceOrder, llList2Integer(faces, 5));    } else {        mappedFace = face;    }     // Determine which faces have been cut away    if (cut.x >= 0.25) {        ym = 0;    }    if (cut.x >= 0.5 || cut.y <= 0.25) {        xp = 0;    }    if (cut.x >= 0.75 || cut.y <= 0.5) {        yp = 0;    }    if (cut.y <= 0.75) {        xm = 0;    }    if (cut.x == 0 && cut.y == 1) {        cb = 0;        ce = 0;    }     // Return face index, -1 if cut away    if (mappedFace == "+x") {        if (xp == 0) {            return -1;        }        return zp+ym+xp;    } else if (mappedFace == "-x") {        if (xm == 0) {            return -1;        }        return zp+ym+xp+yp+xm;    } else if (mappedFace == "+y") {        if (yp == 0) {            return -1;        }        return zp+ym+xp+yp;    } else if (mappedFace == "-y") {        if (yp == 0) {            return -1;        }        return zp+ym;    } else if (mappedFace == "+z") {        return zp;    } else if (mappedFace == "-z") {        return zp+ym+xp+yp+xm+zm;    } else if (mappedFace == "cutBegin") {        if (cb == 0) {            return -1;        }        return zp+ym+xp+yp+xm+zm+cb;    } else if (mappedFace == "cutEnd") {        if (ce == 0) {            return -1;        }        return zp+ym+xp+yp+xm+zm+cb+ce;    }     // This should never happen    return -1;} // Get local size from global size and rotationvector getSize(vector size, rotation q) {     list faceList;   // Mapping from global to local faces    vector newSize;  // Size of <x, y, z> local dimensions    integer face;    // Temporary face index     // Get face mapping    faceList = getFaceList(q);     // Get local face for global x dimension    face = llList2Integer(faceList, 2);    if (face == 2 || face == 4) {        newSize.x = size.x;    }    if (face == 1 || face == 3) {        newSize.x = size.y;    }    if (face == 0 || face == 5) {        newSize.x = size.z;    }     // Get local face for global y dimension    face = llList2Integer(faceList, 3);    if (face == 2 || face == 4) {        newSize.y = size.x;    }    if (face == 1 || face == 3) {        newSize.y = size.y;    }    if (face == 0 || face == 5) {        newSize.y = size.z;    }     // Get local face for global y dimension    face = llList2Integer(faceList, 0);    if (face == 2 || face == 4) {        newSize.z = size.x;    }    if (face == 1 || face == 3) {        newSize.z = size.y;    }    if (face == 0 || face == 5) {        newSize.z = size.z;    }     return newSize;} // Initiates the entire alignment processalign() {    if (llGetLinkNumber() == 1) {        // This is the root object, tell the other objects        // about our position and texture scaling         integer faceCount;  // Number of faces        vector texScale;    // Texture scaling        list texScaleList;  // List of texture scales for each face        list params;        // Primitive params        vector cut;         // Cut         // Get object parameters        cut = llList2Vector(llGetPrimitiveParams([PRIM_TYPE]),2);        faceCount = llGetNumberOfSides();         // Broadcast root parameters        broadcast("faceCount " + (string)faceCount);        integer i;        for (i = 0; i < faceCount; i++) {            texScale = llGetTextureScale(i);            broadcast("texScale " + (string)texScale.x + " " + (string)texScale.y);        }        broadcast("size " + llList2String(llGetPrimitiveParams([PRIM_SIZE]),0));        broadcast("cut " + (string)cut);         // Tell children to finish alignment        broadcast("finish");    } else {         // Child object, reset root parameters        rootFaceCount = 0;        rootTexScaleList = [];    }} // Finish alignment by changing this object's propertiesfinish() {     vector size;          // Size    vector globalSize;    // Size in global coordiantes    vector pos;           // Position    rotation rot;         // Rotation    vector posOffset;     // Offset between this object and root object    float rootTexScaleW;  // Texture scale of root object (width)    float rootTexScaleH;  // Texture scale of root object (height)    vector cut;           // Cut begin and end (in x and y)    list cutParams;       // Cut parameters    list rootCutParams;   // Root cut params    rotation rootRot;     // Root rotation    vector rootGlobalSize;  // Root size in global coordinates     vector cutBeginPos;   // Cut begin face position    vector cutBeginSize;  // Cut begin face size (<width, height, 0>)    vector cutEndPos;     // Cut end face position    vector cutEndSize;    // Cut end face size (<width, height, 0>)     vector rootCutBeginPos;   // Root cut begin face position    vector rootCutBeginSize;  // Root cut begin face size (<width, height, 0>)    vector rootCutEndPos;     // Root cut end face position    vector rootCutEndSize;    // Root cut end face size (<width, height, 0>)     integer face;      // Current face index    integer rootFace;  // Current root face index    float widthOff;    // Texture W offset    float heightOff;   // Texture H offset     float tileSize;    float texScaleW;    float texScaleH;     vector beginNormal;      // Beginning cut face normal    vector endNormal;        // End cut face normal    vector rootBeginNormal;  // Beginning cut face normal for root object    vector rootEndNormal;    // End cut face normal for root object    vector cutOffset;        // Offset between two cut faces    vector cutPlaneOffset;   // Offset in plane of face     // Exit if we are the root object    if (llGetLinkNumber() == 1) {        return;    }     // Get this object's properties    posOffset = llGetLocalPos();    pos = llGetPos();    size = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0);    cut = llList2Vector(llGetPrimitiveParams([PRIM_TYPE]),2);    rot = llGetRot();    globalSize = getSize(size, rot);    rootPos = llGetRootPosition();    rootRot = llGetRootRotation();    rootGlobalSize = getSize(rootSize, rootRot);     // Calculate this object's cut parameters    cutParams = getCutParams(cut.x, cut.y, rot);    cutBeginPos = pos + llList2Vector(cutParams,0);    cutBeginSize = llList2Vector(cutParams,1);    cutEndPos = pos + llList2Vector(cutParams,2);    cutEndSize = llList2Vector(cutParams,3);     // Calculate root cut parameters    rootCutParams = getCutParams(rootCut.x, rootCut.y, rootRot);    rootCutBeginPos = rootPos + llList2Vector(rootCutParams,0);    rootCutBeginSize = llList2Vector(rootCutParams,1);    rootCutEndPos = rootPos + llList2Vector(rootCutParams,2);    rootCutEndSize = llList2Vector(rootCutParams,3);     // Calculate normals using cross product (%)    beginNormal = llVecNorm((cutBeginPos - pos) % <0,0,cutBeginSize.y>/2.0);    endNormal = llVecNorm((cutEndPos - pos) % <0,0,-cutEndSize.y/2.0>);    rootBeginNormal = llVecNorm((rootCutBeginPos - rootPos) % <0,0,rootCutBeginSize.y>/2.0);    rootEndNormal = llVecNorm((rootCutEndPos - rootPos) % <0,0,-rootCutEndSize.y>/2.0);     // Align -X axis faces    face = getFace("-x", cut, rot);    rootFace = getFace("-x", rootCut, rootRot);    if (face != -1 && rootFace != -1) {        rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);        rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);         tileSize = rootGlobalSize.y / rootTexScaleW;        texScaleW = rootTexScaleW * globalSize.y / rootGlobalSize.y;        widthOff = mod(-posOffset.y, tileSize);         tileSize = rootGlobalSize.z / rootTexScaleH;        texScaleH = rootTexScaleH * globalSize.z / rootGlobalSize.z;        heightOff = mod(posOffset.z, tileSize);         llOffsetTexture(widthOff, heightOff, face);        llScaleTexture(texScaleW, texScaleH, face);    }     // Align +X axis faces    face = getFace("+x", cut, rot);    rootFace = getFace("+x", rootCut, rootRot);    if (face != -1 && rootFace != -1) {        rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);        rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);         tileSize = rootGlobalSize.y / rootTexScaleW;        texScaleW = rootTexScaleW * globalSize.y / rootGlobalSize.y;        widthOff = mod(posOffset.y, tileSize);         tileSize = rootGlobalSize.z / rootTexScaleH;        texScaleH = rootTexScaleH * globalSize.z / rootGlobalSize.z;        heightOff = mod(posOffset.z, tileSize);         llOffsetTexture(widthOff, heightOff, face);        llScaleTexture(texScaleW, texScaleH, face);    }     // Align -Y axis faces    face = getFace("-y", cut, rot);    rootFace = getFace("-y", rootCut, rootRot);    if (face != -1 && rootFace != -1) {        rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);        rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);         tileSize = rootGlobalSize.x / rootTexScaleW;        texScaleW = rootTexScaleW * globalSize.x / rootGlobalSize.x;        widthOff = mod(posOffset.x, tileSize);         tileSize = rootGlobalSize.z / rootTexScaleH;        texScaleH = rootTexScaleH * globalSize.z / rootGlobalSize.z;        heightOff = mod(posOffset.z, tileSize);         llOffsetTexture(widthOff, heightOff, face);        llScaleTexture(texScaleW, texScaleH, face);    }     // Align +Y axis faces    face = getFace("+y", cut, rot);    rootFace = getFace("+y", rootCut, rootRot);    if (face != -1 && rootFace != -1) {        rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);        rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);         tileSize = rootGlobalSize.x / rootTexScaleW;        texScaleW = rootTexScaleW * globalSize.x / rootGlobalSize.x;        widthOff = mod(-posOffset.x, tileSize);         tileSize = rootGlobalSize.z / rootTexScaleH;        texScaleH = rootTexScaleH * globalSize.z / rootGlobalSize.z;        heightOff = mod(posOffset.z, tileSize);         llOffsetTexture(widthOff, heightOff, face);        llScaleTexture(texScaleW, texScaleH, face);    }     // Align -Z axis faces    face = getFace("-z", cut, rot);    rootFace = getFace("-z", rootCut, rootRot);    if (face != -1 && rootFace != -1) {        rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);        rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);         tileSize = rootGlobalSize.x / rootTexScaleW;        texScaleW = rootTexScaleW * globalSize.x / rootGlobalSize.x;        widthOff = mod(posOffset.x, tileSize);         tileSize = rootGlobalSize.y / rootTexScaleH;        texScaleH = rootTexScaleH * globalSize.y / rootGlobalSize.y;        heightOff = mod(-posOffset.y, tileSize);         llOffsetTexture(widthOff, heightOff, face);        llScaleTexture(texScaleW, texScaleH, face);    }     // Align +Z axis faces    face = getFace("+z", cut, rot);    rootFace = getFace("+z", rootCut, rootRot);    if (face != -1 && rootFace != -1) {        rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);        rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);         tileSize = rootGlobalSize.x / rootTexScaleW;        texScaleW = rootTexScaleW * globalSize.x / rootGlobalSize.x;        widthOff = mod(posOffset.x, tileSize);         tileSize = rootGlobalSize.y / rootTexScaleH;        texScaleH = rootTexScaleH * globalSize.y / rootGlobalSize.y;        heightOff = mod(posOffset.y, tileSize);         llOffsetTexture(widthOff, heightOff, face);        llScaleTexture(texScaleW, texScaleH, face);    }     // Align cut beginning    face = getFace("cutBegin", cut, rot);    if (face != -1 && rootFace != -1) {         // Compare to root cut begin face        rootFace = getFace("cutBegin", rootCut, rootRot);        cutOffset = cutBeginPos - rootCutBeginPos;        if (rootFace != -1                && llFabs(beginNormal * rootBeginNormal) > 0.9999) {             // Calculate W and H offset for face            cutPlaneOffset.y = cutOffset.z;            cutPlaneOffset.x = llVecMag(cutOffset - <0,0,cutOffset.z>);            if (((cutOffset - <0,0,cutOffset.z>) % rootBeginNormal) * <0,0,1> > 0) {                cutPlaneOffset.x = cutPlaneOffset.x * -1;            }             rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);            rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);             tileSize = rootCutBeginSize.x / rootTexScaleW;            texScaleW = rootTexScaleW * cutBeginSize.x / rootCutBeginSize.x;            widthOff = mod(cutPlaneOffset.x, tileSize);             tileSize = rootCutBeginSize.y / rootTexScaleH;            texScaleH = rootTexScaleH * cutBeginSize.y / rootCutBeginSize.y;            heightOff = mod(cutPlaneOffset.y, tileSize);             llOffsetTexture(widthOff, heightOff, face);            llScaleTexture(texScaleW, texScaleH, face);        }         // Compare to root cut end face        rootFace = getFace("cutEnd", rootCut, rootRot);        cutOffset = cutBeginPos - rootCutEndPos;        if (rootFace != -1                && llFabs(beginNormal * rootEndNormal) > 0.9999) {             // Calculate W and H offset for face            cutPlaneOffset.y = cutOffset.z;            cutPlaneOffset.x = llVecMag(cutOffset - <0,0,cutOffset.z>);            if (((cutOffset - <0,0,cutOffset.z>) % rootEndNormal) * <0,0,1> > 0) {                cutPlaneOffset.x = cutPlaneOffset.x * -1;            }             rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);            rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);             tileSize = rootCutEndSize.x / rootTexScaleW;            texScaleW = rootTexScaleW * cutBeginSize.x / rootCutEndSize.x;            widthOff = mod(cutPlaneOffset.x, tileSize);             tileSize = rootCutEndSize.y / rootTexScaleH;            texScaleH = rootTexScaleH * cutBeginSize.y / rootCutEndSize.y;            heightOff = mod(cutPlaneOffset.y, tileSize);             llOffsetTexture(widthOff, heightOff, face);            llScaleTexture(texScaleW, texScaleH, face);         }    }     // Align cut end    face = getFace("cutEnd", cut, rot);    if (face != -1) {        // Compare to root cut begin face        rootFace = getFace("cutBegin", rootCut, rootRot);        cutOffset = cutEndPos - rootCutBeginPos;        if (rootFace != -1                && llFabs(endNormal * rootBeginNormal) > 0.9999) {             // Calculate W and H offset for face            cutPlaneOffset.y = cutOffset.z;            cutPlaneOffset.x = llVecMag(cutOffset - <0,0,cutOffset.z>);            if (((cutOffset - <0,0,cutOffset.z>) % rootBeginNormal) * <0,0,1> > 0) {                cutPlaneOffset.x = cutPlaneOffset.x * -1;            }             rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);            rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);             tileSize = rootCutBeginSize.x / rootTexScaleW;            texScaleW = rootTexScaleW * cutEndSize.x / rootCutBeginSize.x;            widthOff = mod(cutPlaneOffset.x, tileSize);             tileSize = rootCutBeginSize.y / rootTexScaleH;            texScaleH = rootTexScaleH * cutEndSize.y / rootCutBeginSize.y;            heightOff = mod(cutPlaneOffset.y, tileSize);             llOffsetTexture(widthOff, heightOff, face);            llScaleTexture(texScaleW, texScaleH, face);        }         // Compare to root cut end face        rootFace = getFace("cutEnd", rootCut, rootRot);        cutOffset = cutEndPos - rootCutEndPos;        if (rootFace != -1                && llFabs(endNormal * rootEndNormal) > 0.9999) {             // Calculate W and H offset for face            cutPlaneOffset.y = cutOffset.z;            cutPlaneOffset.x = llVecMag(cutOffset - <0,0,cutOffset.z>);            if (((cutOffset - <0,0,cutOffset.z>) % rootEndNormal) * <0,0,1> > 0) {                cutPlaneOffset.x = cutPlaneOffset.x * -1;            }             rootTexScaleW = llList2Float(rootTexScaleList, rootFace*2);            rootTexScaleH = llList2Float(rootTexScaleList, rootFace*2+1);             tileSize = rootCutEndSize.x / rootTexScaleW;            texScaleW = rootTexScaleW * cutEndSize.x / rootCutEndSize.x;            widthOff = mod(cutPlaneOffset.x, tileSize);             tileSize = rootCutEndSize.y / rootTexScaleH;            texScaleH = rootTexScaleH * cutEndSize.y / rootCutEndSize.y;            heightOff = mod(cutPlaneOffset.y, tileSize);             llOffsetTexture(widthOff, heightOff, face);            llScaleTexture(texScaleW, texScaleH, face);       }    }} // Remove the script from this objectremove() {    llSay(0, "Removing OpenAlign script by Phil Tracy");    llRemoveInventory(SCRIPT_NAME);}  //// DEFAULT STATE SCRIPT ////default{     // Initialize state    state_entry()    {        // Set up a listener on LISTEN_CHANNEL        llListen(LISTEN_CHANNEL,"",NULL_KEY,"");    }     // Called when there is a message on LISTEN_CHANNEL    listen(integer channel, string name, key id, string message) {         // Make sure we're on the right channel        if (channel != LISTEN_CHANNEL) {            return;        }         // Split message into the first word and the rest        integer space = llSubStringIndex(message, " ");        string cmd;        string rest;        if (space != -1) {            cmd = llGetSubString(message, 0, space - 1);            rest = llGetSubString(message, space + 1, -1);        } else {            cmd = message;        }         // Read and execute commands for children        if (llGetLinkNumber() != 1) {            if (cmd == "texScale") {                space = llSubStringIndex(rest, " ");                rootTexScaleList += (float)llGetSubString(rest, 0, space - 1);                rootTexScaleList += (float)llGetSubString(rest, space + 1, -1);            } else if (cmd == "align") {                align();            } else if (cmd == "faceCount") {                rootFaceCount = (integer)rest;            } else if (cmd == "size") {                rootSize = (vector)rest;            } else if (cmd == "finish") {                finish();            } else if (cmd == "cut") {                rootCut = (vector)rest;            }        }         // All objects handle these commands        if (cmd == "align") {            align();        } else if (cmd == "remove") {            remove();        }    }}  

 

Link to comment
Share on other sites

You might want to look at some functions that weren't available back in 2008, when that was written.   I refer in particular to llGetLinkPrimitiveParams (and possibly llGetNumberOfSides).

I'm pretty sure that they, along with llSetLinkPrimitiveParamsFast and PRIM_LINK_TARGET,  would enable you to simplify the OpenAlign script quite a bit.

Link to comment
Share on other sites

Much of what you're asking might have been more appropriate for the Building and Texturing forum, since it isn't directly related to LSL. But, as you have discovered, it's neither trivial nor simple to do texture alignment across surfaces.

 

To write a program to do it, you'll need to master three disciplines- bulding, texturing and LSL coding. For that, I'd recommend http://www.buildersbrewery.com/ , one of the largest buiding and scripting groups in SL that offers a wide assortment of classes in these areas as well as having a very informed and helpful group that is always discussing these issues.

Link to comment
Share on other sites

I've taken a closer look at the script.   In answer to your specific question, the main reference documentation about prim faces is probably in the wiki article,  Face.   The reason the script is so complicated, I think (or one of them) is that we need to know which faces of adjacent prims are next to each other, and also how they're rotated locally.   That's a lot easier to do now than it was in 2008 because we can read llGetLinkPrimitiveParams(LinkNo,[PRIM_ROT_LOCAL]).

I'm not sure I properly understand what you mean about wanting to a "a reference that describes how this information is kept," but all I can do is re-iterate my suggestion about looking at llGetLinkPrimitiveParams, which will return just about anything you need to know about a prim.

Link to comment
Share on other sites

Also you might find the script at http://www.free-lsl-scripts.com/cgi/freescripts.plx?ID=1446 helpful in determining how the faces are numbered and their orientation with each other. It can be quite insightful to "torture" a prim and see how the the face numbering is affected.

 

You'll soon see that each face has its own "up" direction that is independent of its neighbors and that will have to be taken into account in any texture aligning alogorithm.

Link to comment
Share on other sites

Thanks LepreKhaun,

I was unsure myself about where to put this entry when I started. But I thought that the most technical part would be the scripting so I chose here. It wasn't clear to me if the building and texturing forum would have people who understood the complexity of the script to accomplish this. I'll look into the buildersbrewery to see what I can find. 

 

Thanks again for the help

Link to comment
Share on other sites


KevinLeap wrote:

I came on this problem when I was trying to build a simple wall with a door and found that making the textures align was more difficult than I anticipated.

 

Have you tried:  select object-Editt-Texture-Mapping-change from Default to Planar-Select all the faces you want to aline, then check Aline planar faces.  I think the openAline script may have been written before this feature was added to the viewer.

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 3942 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...