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