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)
- 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(); }
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs
No comments:
Post a Comment