LScript (Modeler) creates cables between selected points. You can select more than two points to make it create multiple cables.
All cables are UV Mapped and fully setup for animation in LightWave by just cutting and pasting the two point polys (Surface:DYNAMIC) to one layer and the cables (surface:Cable) in the next layer parenting cables to the Dynamic layer. It was designed to be converted to subdivision surfaces for rendering.
Changes
- Added control reset
- Realtime Preview
Compatible with Newtek LightWave 9.6 and above.
// LScript Modeler - www.StephenCulley.co.uk // // web address: http://www.stephenculley.co.uk // email address: email@stephenculley.co.uk /* LScript Modeler - Cable Modeler_Cable.ls */ @version 2.2 @warnings @script modeler @name *Cable // Title sTitle = "*Cable"; // Version sVersion = "v2.0"; bDone = false; // Done bChange = false; // Change bPreview; // Preview bPreview; nRadius; nRadiusRandom; iSegments; bCapEnd; iSeed; vnGravity; nDroop; nDroopRandom; nTurbulance; nTurbulanceScale; nTurbulanceRandom; nNoise; iUV; ctrl_c0,ctrl_c1,ctrl_c2,ctrl_c3,ctrl_c4,ctrl_c5,ctrl_c6,ctrl_c7,ctrl_c8,ctrl_c9,ctrl_c10,ctrl_c11,ctrl_c12; ctrl_res0; ctrl_prev0; main { // Recall bPreview = recall("bPreview",true); nRadius = recall("nRadius",0.05); nRadiusRandom = recall("nRadiusRandom",0.0); iSegments = recall("iSegments",20); bCapEnd = recall("bCapEnd",false); iSeed = recall("iSeed",1); vnGravity = recall("vnGravity",<0.0,-9.8,0.0>); nDroop = recall("nDroop",0.25); nDroopRandom = recall("nDropRandom",0.0); nTurbulance = recall("nTurbulance",0.0); nTurbulanceScale = recall("nTurbulanceScale",1.0); nTurbulanceRandom = recall("nTurbulanceRandom",0.1); nNoise = recall("nNoise",0.0); iUV = recall("iUV",3); reqbegin(sTitle + " " + sVersion); // Reset / Preview ctrl_res0 = ctlbutton("Reset",50,"button_reset"); // Button Reset ctrl_prev0 = ctlcheckbox("Preview",bPreview); // Preview ctlsep(); // Control ctrl_c0 = ctldistance("Radius",nRadius); ctrl_c1 = ctldistance("Radius Random",nRadiusRandom); ctrl_c2 = ctlinteger("Segments",iSegments); ctrl_c3 = ctlcheckbox("Cap Ends (cross-section)",bCapEnd); ctlsep(); ctrl_c4 = ctlinteger("Seed",iSeed); ctlsep(); ctrl_c5 = ctlvector("Gravity",vnGravity); ctrl_c6 = ctlpercent("Droop",nDroop); ctrl_c7 = ctlpercent("Droop Random",nDroopRandom); ctlsep(); ctrl_c8 = ctldistance("Turbulance",nTurbulance); ctrl_c9 = ctlnumber("Turbulance Scale",nTurbulanceScale); ctrl_c10 = ctlnumber("Turbulance Random",nTurbulanceRandom); ctlsep(); ctrl_c11 = ctldistance("Noise Amount",nNoise); ctlsep(); ctrl_c12 = ctlchoice("Make UVs",iUV,@"Segment","Object","Ratio (1:1)"@,false); // Developer ctlsep(); ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk"); process(); // Process // Refresh ctlrefresh(ctrl_prev0,"refresh"); ctlrefresh(ctrl_c0,"refresh"); ctlrefresh(ctrl_c1,"refresh"); ctlrefresh(ctrl_c2,"refresh"); ctlrefresh(ctrl_c3,"refresh"); ctlrefresh(ctrl_c4,"refresh"); ctlrefresh(ctrl_c5,"refresh"); ctlrefresh(ctrl_c6,"refresh"); ctlrefresh(ctrl_c7,"refresh"); ctlrefresh(ctrl_c8,"refresh"); ctlrefresh(ctrl_c9,"refresh"); ctlrefresh(ctrl_c10,"refresh"); ctlrefresh(ctrl_c11,"refresh"); ctlrefresh(ctrl_c12,"refresh"); if (!reqpost()) { // Cancel if(bDone){undo();} // Undo return; } else { // Ok if(!bDone || bChange) // Process { values(); // Values process(); // Process } // Store store("bPreview",bPreview); store("nRadius",nRadius); store("nRadiusRandom",nRadiusRandom); store("iSegments",iSegments); store("bCapEnd",bCapEnd); store("iSeed",iSeed); store("vnGravity",vnGravity); store("nDroop",nDroop); store("nDropRandom",nDroopRandom); store("nTurbulance",nTurbulance); store("nTurbulanceScale",nTurbulanceScale); store("nTurbulanceRandom",nTurbulanceRandom); store("nNoise",nNoise); store("iUV",iUV); } reqend(); } refresh:value { bChange = true; // Change values(); // Values if(bPreview){process();} // Process } values { bPreview = getvalue(ctrl_prev0); // Preview nRadius = getvalue(ctrl_c0); // n Radius nRadiusRandom = getvalue(ctrl_c1); // n Radius Random iSegments = getvalue(ctrl_c2); // i Segments bCapEnd = getvalue(ctrl_c3); // b Cap End iSeed = getvalue(ctrl_c4); // i Seed vnGravity = normalize3D(getvalue(ctrl_c5)); // vn Gravity nDroop = getvalue(ctrl_c6); // n Droop nDroopRandom = getvalue(ctrl_c7); // n Droop Random nTurbulance = getvalue(ctrl_c8); // n Turbulance if(getvalue(ctrl_c9) <> 0.0){nTurbulanceScale = 1 / getvalue(ctrl_c9);}else{nTurbulanceScale = 0.0;} // n Turbulance Scale nTurbulanceRandom = getvalue(ctrl_c10); // n Turbulance Random nNoise = getvalue(ctrl_c11); // n Noise iUV = getvalue(ctrl_c12); // i UV } button_reset { setvalue(ctrl_c0,0.05); // Radius setvalue(ctrl_c1,0.0); // Radius Random setvalue(ctrl_c2,20); // Segments setvalue(ctrl_c3,false); // Cap End setvalue(ctrl_c4,1); // Seed setvalue(ctrl_c5,<0.0,-9.8,0.0>); // Gravity setvalue(ctrl_c6,0.25); // Droop setvalue(ctrl_c7,0.0); // Droop Random setvalue(ctrl_c8,0.0); // Turbulance setvalue(ctrl_c9,1.0); // Turbulance Scale setvalue(ctrl_c10,0.1); // Turbulance Random setvalue(ctrl_c11,0.0); // Noise setvalue(ctrl_c12,3); // UV } process { // Undo if(bDone){undo();} undogroupbegin(); // Process // Selection - Point (GLOBAL) selmode(GLOBAL); iPointCountBefore = pointcount(); // Selection - Point (DIRECT) selmode(DIRECT); iPointCount = pointcount(); if(iPointCount <= 1) error("None or not enough points selected."); if((iPointCount & 1) != 0) iPointCount--; // Check if odd editbegin(); mapFIXED = VMap(VMSELECT,"FIXED",1); // Selection Map mapUV = VMap(VMTEXTURE,"UV_Cable",2); // UV Map editend(); noiseseed(iSeed); // Noise Seed moninit((iPointCount / 2),"Processing..."); // Progress Monitor editbegin(); for(iCablePoint = 1; iCablePoint <= iPointCount; iCablePoint += 2) { vStartPoint = pointinfo(points[iCablePoint]); vEndPoint = pointinfo(points[iCablePoint + 1]); if(abs(normalize3D(vEndPoint - vStartPoint)) == <0.0,1.0,0.0>) { if(vEndPoint.y <= vStartPoint.y) {vEndPoint += <((random() * 2) - 1) * 0.00001,0.0,((random() * 2) - 1) * 0.00001>;} else {vStartPoint += <((random() * 2) - 1) * 0.00001,0.0,((random() * 2) - 1) * 0.00001>;} } nSegmentInc = 1 / iSegments; nSegment = 0.0; vStart = vStartPoint; vEnd = vEndPoint - vStartPoint; nRadiusMultiplier = nRadius + (random() * nRadiusRandom); nDroopMultiplier = (nDroop * distance3D(vStartPoint,vEndPoint)) + (random() * nDroopRandom * distance3D(vStartPoint,vEndPoint)); // Droop Noise vTurbulanceOffset =* nTurbulanceRandom; // Turbulance Variance aPointsCable[1] = vStartPoint; // Start Point aPointsCable[iSegments + 1] = vEndPoint; // End Point for(iCurrentPoint = 2; iCurrentPoint <= iSegments; iCurrentPoint++) // Middle Points { nSegment += nSegmentInc; // Multiplier nMultiplier = cos((nSegment * 3.1415926535) - 1.57079632675); // Droop aPointsCable[iCurrentPoint] = vStart + (vEnd * nSegment) + (vnGravity * nMultiplier * nDroopMultiplier); // Turbulance if(nTurbulance <> 0.0) { aPointsCable[iCurrentPoint] += cosinenoise3D((aPointsCable[iCurrentPoint] * nTurbulanceScale) + vTurbulanceOffset) * nMultiplier * nTurbulance; } // Noise if(nNoise <> 0.0) { aPointsCable[iCurrentPoint] += <(random() * 2) - 1,(random() * 2) - 1,(random() * 2) - 1> * nNoise; } } // Create Points // Start Point vPoint = aPointsCable[1]; vnForward = normalize3D(aPointsCable[2] - aPointsCable[1]); vnUp = normalize3D(crossproduct3D(vnForward,<0.0,1.0,0.0>)); vnRight = normalize3D(crossproduct3D(vnUp,vnForward)); aPolygonCable[1][1] = vPoint + (vnUp * nRadiusMultiplier) + (vnRight * nRadiusMultiplier); aPolygonCable[1][2] = vPoint + (vnUp * nRadiusMultiplier) + (vnRight * -nRadiusMultiplier); aPolygonCable[1][3] = vPoint + (vnUp * -nRadiusMultiplier) + (vnRight * -nRadiusMultiplier); aPolygonCable[1][4] = vPoint + (vnUp * -nRadiusMultiplier) + (vnRight * nRadiusMultiplier); // Mid Points for(iCurrentPoint = 2; iCurrentPoint <= iSegments; iCurrentPoint++) { vPoint = aPointsCable[iCurrentPoint]; vnForward = normalize3D(aPointsCable[iCurrentPoint + 1] - aPointsCable[iCurrentPoint - 1]); vnUp = normalize3D(crossproduct3D(vnForward,<0.0,1.0,0.0>)); vnRight = normalize3D(crossproduct3D(vnUp,vnForward)); aPolygonCable[iCurrentPoint][1] = vPoint + (vnUp * nRadiusMultiplier) + (vnRight * nRadiusMultiplier); aPolygonCable[iCurrentPoint][2] = vPoint + (vnUp * nRadiusMultiplier) + (vnRight * -nRadiusMultiplier); aPolygonCable[iCurrentPoint][3] = vPoint + (vnUp * -nRadiusMultiplier) + (vnRight * -nRadiusMultiplier); aPolygonCable[iCurrentPoint][4] = vPoint + (vnUp * -nRadiusMultiplier) + (vnRight * nRadiusMultiplier); } // End Point vPoint = aPointsCable[iSegments + 1]; vnForward = normalize3D(aPointsCable[iSegments + 1] - aPointsCable[iSegments]); vnUp = normalize3D(crossproduct3D(vnForward,<0.0,1.0,0.0>)); vnRight = normalize3D(crossproduct3D(vnUp,vnForward)); aPolygonCable[iSegments + 1][1] = vPoint + (vnUp * nRadiusMultiplier) + (vnRight * nRadiusMultiplier); aPolygonCable[iSegments + 1][2] = vPoint + (vnUp * nRadiusMultiplier) + (vnRight * -nRadiusMultiplier); aPolygonCable[iSegments + 1][3] = vPoint + (vnUp * -nRadiusMultiplier) + (vnRight * -nRadiusMultiplier); aPolygonCable[iSegments + 1][4] = vPoint + (vnUp * -nRadiusMultiplier) + (vnRight * nRadiusMultiplier); editend(); // 2 Point Poly Chain // Surface setsurface("DYNAMIC"); changesurface("DYNAMIC"); editbegin(); for(iCurrentPoint = 1; iCurrentPoint <= iSegments; iCurrentPoint++) { aPoints[1] = addpoint(aPointsCable[iCurrentPoint]); aPoints[2] = addpoint(aPointsCable[iCurrentPoint + 1]); addpolygon(aPoints); if(iCurrentPoint == 1) { mapFIXED.setValue(aPoints[1],1); } if(iCurrentPoint == iSegments) { mapFIXED.setValue(aPoints[2],1); } aPoints = nil; } editend(); // Polygon setsurface("Cable"); changesurface("Cable"); editbegin(); nDistance = 0.0; nCircumference = 3.1415926535 * (nRadiusMultiplier * 2); for(iCurrentPoint = 1; iCurrentPoint <= iSegments; iCurrentPoint++) { if(iUV == 1) // UV Segment { aUV[1] = 0.0; aUV[2] = 1.0; } else if(iUV == 2) // UV Object { aUV[1] = (1 / iSegments) * (iCurrentPoint - 1); aUV[2] = (1 / iSegments) * iCurrentPoint; } else if(iUV == 3) // UV Ratio (1:1) { aUV[1] = (1 / nCircumference) * nDistance; nDistance += distance3D(aPointsCable[iCurrentPoint],aPointsCable[iCurrentPoint + 1]); aUV[2] = (1 / nCircumference) * nDistance; } // 1 aPoints[1] = addpoint(aPolygonCable[iCurrentPoint + 1][1]); aPoints[2] = addpoint(aPolygonCable[iCurrentPoint][1]); aPoints[3] = addpoint(aPolygonCable[iCurrentPoint][2]); aPoints[4] = addpoint(aPolygonCable[iCurrentPoint + 1][2]); addpolygon(aPoints); mapUV.setValue(aPoints[1],@aUV[2],0.0@); mapUV.setValue(aPoints[2],@aUV[1],0.0@); mapUV.setValue(aPoints[3],@aUV[1],0.25@); mapUV.setValue(aPoints[4],@aUV[2],0.25@); // 2 aPoints[1] = addpoint(aPolygonCable[iCurrentPoint + 1][2]); aPoints[2] = addpoint(aPolygonCable[iCurrentPoint][2]); aPoints[3] = addpoint(aPolygonCable[iCurrentPoint][3]); aPoints[4] = addpoint(aPolygonCable[iCurrentPoint + 1][3]); addpolygon(aPoints); mapUV.setValue(aPoints[1],@aUV[2],0.25@); mapUV.setValue(aPoints[2],@aUV[1],0.25@); mapUV.setValue(aPoints[3],@aUV[1],0.5@); mapUV.setValue(aPoints[4],@aUV[2],0.5@); // 3 aPoints[1] = addpoint(aPolygonCable[iCurrentPoint + 1][3]); aPoints[2] = addpoint(aPolygonCable[iCurrentPoint][3]); aPoints[3] = addpoint(aPolygonCable[iCurrentPoint][4]); aPoints[4] = addpoint(aPolygonCable[iCurrentPoint + 1][4]); addpolygon(aPoints); mapUV.setValue(aPoints[1],@aUV[2],0.5@); mapUV.setValue(aPoints[2],@aUV[1],0.5@); mapUV.setValue(aPoints[3],@aUV[1],0.75@); mapUV.setValue(aPoints[4],@aUV[2],0.75@); // 4 aPoints[1] = addpoint(aPolygonCable[iCurrentPoint + 1][4]); aPoints[2] = addpoint(aPolygonCable[iCurrentPoint][4]); aPoints[3] = addpoint(aPolygonCable[iCurrentPoint][1]); aPoints[4] = addpoint(aPolygonCable[iCurrentPoint + 1][1]); addpolygon(aPoints); mapUV.setValue(aPoints[1],@aUV[2],0.75@); mapUV.setValue(aPoints[2],@aUV[1],0.75@); mapUV.setValue(aPoints[3],@aUV[1],1.0@); mapUV.setValue(aPoints[4],@aUV[2],1.0@); aPoints = nil; } // Cap End if(bCapEnd == 1) { editend(); setsurface("Cable (cross-section)"); changesurface("Cable (cross-section)"); editbegin(); // Start aPoints[1] = addpoint(aPolygonCable[1][4]); aPoints[2] = addpoint(aPolygonCable[1][3]); aPoints[3] = addpoint(aPolygonCable[1][2]); aPoints[4] = addpoint(aPolygonCable[1][1]); addpolygon(aPoints); mapUV.setValue(aPoints[1],@0.0,1.0@); mapUV.setValue(aPoints[2],@1.0,1.0@); mapUV.setValue(aPoints[3],@1.0,0.0@); mapUV.setValue(aPoints[4],@0.0,0.0@); // End aPoints[1] = addpoint(aPolygonCable[iSegments + 1][1]); aPoints[2] = addpoint(aPolygonCable[iSegments + 1][2]); aPoints[3] = addpoint(aPolygonCable[iSegments + 1][3]); aPoints[4] = addpoint(aPolygonCable[iSegments + 1][4]); addpolygon(aPoints); mapUV.setValue(aPoints[1],@0.0,1.0@); mapUV.setValue(aPoints[2],@1.0,1.0@); mapUV.setValue(aPoints[3],@1.0,0.0@); mapUV.setValue(aPoints[4],@0.0,0.0@); aPoints = nil; } monstep(); // Progress Monitor } editend(); monend(); // Progress Monitor // Selection - Point (GLOBAL) selmode(GLOBAL); iPointCountAfter = pointcount(); if((iPointCountAfter - iPointCountBefore) > 0) { for(s = 1; s <= (iPointCountAfter - iPointCountBefore) ; s++){aSelection[s] = s + iPointCountBefore;} selmode(USER); selpoint(SET, POINTNDX, aSelection); mergepoints(0.0); // Merge Points } // Undo undogroupend(); bChange = false; // Change // Done bDone = true; } // INTERPOLATION cosine1D: n1,n2,i // i = interpolation point (0-1) { i2 = (1 - cos(i * 3.1415926535)) * 0.5; return(n1 * (1 - i2) + n2 * i2); } // NOISE _noiseseed = 1; _noiseresolution = 512; _noise = nil; _noiseperm = nil; noiseinit { randomseed(_noiseseed); // Random Seed for(iN = 1; iN <= _noiseresolution; iN++) { _noise[iN] = (random() * 2) - 1; // -1.0..1.0 _noiseperm[iN] = wrap(1,_noiseresolution,integer(random() * _noiseresolution)); } } noiseseed: seed { _noiseseed = seed; noiseinit(); // Init } noiseresolution: resolution { _noiseresolution = resolution; noiseinit(); // Init } noiseperm1D: n // i { // ! if(_noiseperm == nil){noiseinit();} // Init return(_noiseperm[wrap(1,_noiseresolution,integer(n))]); } noiseperm2D: v // n { return(noiseperm1D(v.y + noiseperm1D(v.x))); } noiseperm3D: v // n { return(noiseperm1D(v.z + noiseperm2D(v))); } noise3D: v // n { // ! if(_noise == nil){noiseinit();} // Init return(_noise[noiseperm3D(v)]); } cosinenoise3D: v // n { v = wrap(1,_noiseresolution,v); vFrac = frac(v); vInt = v - vFrac; nA1 = noise3D( ); nA2 = noise3D( ); nA3 = noise3D( ); nA4 = noise3D( ); nA = cosine1D(cosine1D(nA1,nA2,vFrac.x),cosine1D(nA3,nA4,vFrac.x),vFrac.z); nB1 = noise3D( ); nB2 = noise3D( ); nB3 = noise3D( ); nB4 = noise3D( ); nB = cosine1D(cosine1D(nB1,nB2,vFrac.x),cosine1D(nB3,nB4,vFrac.x),vFrac.z); return(cosine1D(nA,nB,vFrac.y)); } // RANDOM _randomseed = 0; // n Seed randomseed: seed { _randomseed = seed; } random { n = (_randomseed * 214013 + 2531011) % 2^^24; _randomseed = n; n /= 2^^24; // 0..1 return(n); } // 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)))); } 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); } // WRAP wrap: min,max,n { n = n - floor((n - min) / (max - min)) * (max - min); if(n < 0) n = n + max - min; // error check return(n); }
All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs