Feedback

Please leave feedback and comments. I am always interested to hear how people get on using these LScripts!
Showing posts with label Custom. Show all posts
Showing posts with label Custom. Show all posts

Wednesday, 24 September 2014

LScript - Custom_Shadow


LScript (Layout) adds a shadow visual aid to Layout. It is purely a visual cue for objects positioned or sitting on the ground plane.

There are three types available
  • Simple - Basic distance from ground plane
  • Simple (Projected) - Projected style shadow (experimental)
  • Object (Projected) - Projected shadow of object (experimental)
Changes
  • Error found by erikalst has now been fixed
  • Shadow will nolonger disappear if object drops below ground plane

Compatible with Newtek LightWave 9.6 and above.

// LScript Custom Object - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/*  
    LScript Custom Object - Shadow

    Custom_Shadow.ls

*/

@version 2.4
@warnings
@script custom
@name *Shadow

    // Title
    sTitle = "*Shadow";

    // Version
    sVersion = "v1.0";  

    // Items
    Item; // Item
    LightItem = nil; // Item
    LightItemName = "nil";

    bCreate; // Create
    iSteps = 32; // Circle detail
    sType = @"Simple","Simple (Projected)","Object (Projected)"@;
    iType = 1; // 1 = Simple, 2 = Complex
    nDegStep = 360 / iSteps; // Degree per step
    nOffset = 0.0001;
    nTime; // Time

    vColor = <75.0,75.0,75.0>; // Color;

create: ma
{
    bCreate = false; // Create

    setdesc(sTitle + " " + sVersion + " - " + sType[iType]);

    Item = ma; // Item
}

destroy
{
}

newtime: frame, time
{
    nTime = time;
}

init
{
}

process: ca
{
    // Create - invalid argument fix
    if(bCreate == false){bCreate = true; return;}

    // Item
    if(Item)
        {
        vnRight = normalize3D(Item.getRight(nTime));
        vnUp = normalize3D(Item.getUp(nTime));
        vnForward = normalize3D(Item.getForward(nTime));
        vWorldPosition = Item.getWorldPosition(nTime);
        vScaling = Item.getScaling(nTime);

        aBoundingBox = Item.position(getlayernumber(Item));

        nSize = ((aBoundingBox[2].x - aBoundingBox[1].x) +
                 (aBoundingBox[2].y - aBoundingBox[1].y) +
                 (aBoundingBox[2].z - aBoundingBox[1].z)) * vScaling * 0.333333; // Size of object averaged

        nHeight = (aBoundingBox[2].y - aBoundingBox[1].y) * vScaling.y;

        nBottom = min(vWorldPosition.y - (aBoundingBox[2].y * vScaling.y),vWorldPosition.y - (aBoundingBox[1].y * vScaling.y));
        }
    else
        {
        vnRight = <0.0,0.0,0.0>;
        vnUp = <0.0,0.0,0.0>;
        vnForward = <0.0,0.0,0.0>;
        vWorldPosition = <0.0,0.0,0.0>;
        vScaling = <0.0,0.0,0.0>;
        nHeight = 0.0;
        nSize = 0.0000001;
        }


    // Light Item
    if(LightItemName != "nil") {LightItem = Light(LightItemName); LightItemName = "nil";}
    if(LightItem)
        {
        vLight = LightItem.getWorldPosition(nTime);
        }
    else
        {
        TempItem = Light(1);
        vLight = TempItem.getWorldPosition(nTime);
        }
    if(vLight.y < 0.0) return; // Break

// Simple

    if(iType == 1) // Type 1 = Simple
      {
      nRadius = (nSize * 0.5) * (1 - ((1 / nSize * 0.5) * max(0.0,(vWorldPosition.y - (nHeight * 0.5)) )));
      if(nRadius < 0.0) return; // Check

      // Calculate circle
      nDegree = 0;
      iPoints = 1;

      for(d = 0; d <= iSteps; d++)
        {
        vPoint = <(cos(DEGtoRAD(nDegree)) * nRadius),nOffset,(sin(DEGtoRAD(nDegree)) * nRadius)>;
        aPoints[iPoints] = vPoint + ; // Store vertex
        iPoints++; // Count
        nDegree += nDegStep; // Add step
        }

      aPoints[iPoints] = aPoints[1]; // Add copy of first point

      // Draw
      ca.setColor(vColor * (1/255)); // Set color
      for(p = 1; p < iPoints; p++)
        {
        ca.drawTriangle(,aPoints[p],aPoints[p + 1],SYS_WORLD);
        }  

      }

// Simple (Projected)

    if(iType == 2)
      {
      // Circle center
      aIntersect = lineplaneintersect3D(vLight,normalize3D(vWorldPosition - vLight),<0.0,0.0,0.0>,<0.0,1.0,0.0>);
      if(aIntersect[1] == false) return; // Break No shadow
      vCenter = aIntersect[3] + <0.0,nOffset,0.0>;

      aOrthonormal[1] = normalize3D(vLight - vWorldPosition);
      vPoint = pointplane3D(vWorldPosition + <1.0,0.0,1.0>,vWorldPosition,normalize3D(vWorldPosition - vLight));
      aOrthonormal[2] = normalize3D(vPoint - vWorldPosition);       
      aOrthonormal[3] = normalize3D(crossproduct3D(aOrthonormal[2],aOrthonormal[1]));

      nRadius = nSize * 0.5; // Radius
      nDegree = 0;
      iPoints = 1;

      for(d = 0; d <= iSteps; d++)
        {
        vPoint = (aOrthonormal[2] * (cos(DEGtoRAD(nDegree)) * nRadius)) + 
                 (aOrthonormal[3] * (sin(DEGtoRAD(nDegree)) * nRadius)) + vWorldPosition;
        aIntersect = lineplaneintersect3D(vLight,normalize3D(vPoint - vLight),<0.0,0.0,0.0>,<0.0,1.0,0.0>);
        aPoints[iPoints] = aIntersect[3] + <0.0,nOffset,0.0>; // Store vertex
        iPoints++; // Count
        nDegree += nDegStep; // Add step
        }

      aPoints[iPoints] = aPoints[1]; // Add copy of first point

      // Draw
      ca.setColor(vColor * (1/255)); // Set color
      for(p = 1; p < iPoints; p++)
        {
        ca.drawTriangle(vCenter,aPoints[p],aPoints[p + 1],SYS_WORLD);
        }  
      }

// Object (Projected)

    if(iType == 3)
      {
      if(Item == nil){return;}

      for(p = 1; p <= Item.polygonCount(); p++)
        {
        aPoints = nil;
        for(v = 1; v <= Item.vertexCount(Item.polygons[p]); v++)
          {
          vPoint = Item.position(Item.vertex(Item.polygons[p],v));
          vPoint = (vnRight * vPoint.x * vScaling.x) +
                   (vnUp * vPoint.y * vScaling.y) +
                   (vnForward * vPoint.z * vScaling.z) + vWorldPosition;

          aIntersect = lineplaneintersect3D(vLight,normalize3D(vPoint - vLight),<0.0,0.0,0.0>,<0.0,1.0,0.0>);
          aPoints[v] = aIntersect[3]; 
          }

        // Draw
        ca.setColor(vColor * (1/255)); // Set color
        if(Item.vertexCount(Item.polygons[p]) == 3)
          {
          ca.drawTriangle(aPoints[1],aPoints[2],aPoints[3],SYS_WORLD);             
          }
        else
          {
          ca.drawTriangle(aPoints[1],aPoints[2],aPoints[3],SYS_WORLD);             
          ca.drawTriangle(aPoints[1],aPoints[3],aPoints[4],SYS_WORLD);             
          }
      
        }
      }

}

// CONVERSIONS

DEGtoRAD: n // Degree to radian
{
    return(n * (3.1415926535 / 180));
}

RADtoDEG: n // Radian to degree
{
    return(n * (180 / 3.1415926535));
}

// VECTOR 3D

crossproduct3D: v1,v2 // v
{
    // Vector
    return();
}

distance3D: v1, v2 // n
{
    // Vector
    return(sqrt(((v2.x - v1.x) * (v2.x - v1.x)) +
                ((v2.y - v1.y) * (v2.y - v1.y)) + 
                ((v2.z - v1.z) * (v2.z - v1.z))));
}

dotproduct3D: v1,v2 // n
{
    // Vector
    return(v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
}

lineplanedistance3D: v1,vn1,v2,vn2 // n
{
    // Vector - v1 v2 is Vector / vn1 vn2 is Vector Normal
    nNumerator = dotproduct3D(vn2,v1) + dotproduct3D(-v2,vn2);
    nDenomimator = dotproduct3D(vn2,vn1);
    if(nDenomimator <> 0.0){return(-(nNumerator / nDenomimator));} else{return(0.0);}
}

lineplaneintersect3D: v1,vn1,v2,vn2 // a[1] b (true / false)
                                    // a[2] n (distance)
                                    // a[3] v (vector)
{
    // Vector - v1 v2 is Vector / vn1 vn2 is Vector Normal
    nNumerator = dotproduct3D(vn2,v1) + dotproduct3D(-v2,vn2);
    nDenomimator = dotproduct3D(vn2,vn1);
    if(nDenomimator <> 0.0){nDistance =  -(nNumerator / nDenomimator);} else{ nDistance = 0.0;}
    if(nDistance >= 0.0){a[1] = true;}else{a[1] = false;} // True / False
    a[2] = nDistance; // Distance
    a[3] = v1 + (vn1 * nDistance); // Vector
    return(a);
}

normal3D: v1,v2 // vn
{
    // Vector
    return();
}

magnitude3D: v // n
{
    // Vector
    return(sqrt((v.x * v.x) + (v.y * v.y) + (v.z * v.z)));
}

normalize3D: v // v
{
    // Vector normalize to 0 - 1
    nMagnitude = magnitude3D(v);
    if(nMagnitude <> 0) nMagnitude = 1 / nMagnitude;
    return(v * nMagnitude);
}

orthonormal3D: vn // a[1] vn (vector normal)
                  // a[2] vn (vector normal)
                  // a[3] vn (vector normal)
{
    // Orthonormal Vectors from Vector Normal
    a[1] = vn;
    if(vn.x |= vn.y)
        {
        nMagnitude = 1 / sqrt(vn.x * vn.x + vn.z * vn.z);
        a[2] = <-vn.z * nMagnitude,0.0,vn.x * nMagnitude>;
       }
    else
        {
        nMagnitude = 1 / sqrt(vn.y * vn.y + vn.z * vn.z);
        a[2] = <0.0,vn.z * nMagnitude,-vn.y * nMagnitude>;
        }
    a[3] = crossproduct3D(a[1],a[2]);
    return(a);
}

pointplane3D: v1,v2,vn2 // v
{
    // Vector - v1 is Vector / v2 is Vector on Plane / vn2 is Vector Normal on Plane
    return(v1 + (dotproduct3D(vn2,v2) - dotproduct3D(vn2,v1)) * vn2);
}

sqrlinemagnitude3d: v1,v2 // n
{
    // Vector square magnitude of v1 to v2
    return((v2.x - v1.x) * (v2.x - v1.x) + (v2.y - v1.y) * (v2.y - v1.y));
}

getlayernumber: item
{
    if(item.totallayers == 1){return(1);}
    sTokens = parse(":",item.name);
    iLayer = 0;
    if (strleft(sTokens[2],5)=="Layer")
      {
      iLayer = integer(sTokens[2]);
      }
    else
      {
      iTotal = item.totallayers;
      for(i = 1; i <= iTotal; i++)
        {
        if(item.layerVisible(i) == 1)
          {
          if(item.layerName(i) == sTokens[2])
            {
            iLayer = i;
            break;
            }
          }
        else
          {
          iTotal++;
          }
        }
      }
  return iLayer;
}

load: what,io
{
    if(what == SCENEMODE)   // processing an ASCII scene file
    {
        iType = io.read().asInt();
        vColor = io.read().asVec();
        nOffset = io.read().asNum();
        LightItemName = io.read().asStr();

        setdesc(sTitle + " " + sVersion + " - " + sType[iType]);
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        io.writeln(iType);
        io.writeln(vColor);
        io.writeln(nOffset);

        if(LightItem != nil)
            {
            io.writeln(string(LightItem.name));
            }
        else
            {
            io.writeln("nil");
            }  
    }
}

options
{
    reqbegin(sTitle + " " + sVersion);

    ctrl_c0 = ctlchoice("Type",iType,@"Simple","Simple (Projected)","Object (Projected)"@);
    ctrl_c1 = ctlcolor("Color",vColor);
    ctrl_c2 = ctlnumber("Offset",nOffset);

    ctlsep();
    ctrl_l0 = ctllightitems("Light Item",LightItem);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    return if !reqpost();

    iType = getvalue(ctrl_c0);
    vColor = getvalue(ctrl_c1);
    nOffset = getvalue(ctrl_c2);
    LightItem = getvalue(ctrl_l0);

        setdesc("*Shadow - " + sType[iType]);

    reqend();
}
All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs