Feedback

Please leave feedback and comments. I am always interested to hear how people get on using these LScripts!

Monday 16 April 2012

LScript - Generic_LightColor


LScript (Layout) applies colour to selected lights between frame 0 and 1. It enables changing light colour during spinning light tricks and in old school techniques like faking spectrums. The values are repeated correctly each frame by timing them to the motion blur length.

Compatible with Newtek LightWave 9.6 and above.

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

/*  
    LScript Generic - LightColor

    Generic_LightColor.ls

*/

    // Title
    sTitle = "*LightColor";

    // Version
    sVersion = "v1.0";

    // Variable
    aColor;
    aIntensity;

    // Requester
    bRequesterUpdate = false; // Update

    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_c13,ctrl_c14;

generic
{

    // Item Select
    Items = Scene().getSelect();  

    bLight = false;

    for(i = 1; i <= Items.size(); i++)
      {
      if(Items[i].genus == LIGHT) bLight = true;
      }        

    if(!bLight)
      {
      info("Select a light to apply color to.");
      return;
      }        

    // Recall
    aColor[1] = recall("vColor1",<255.0,255.0,255.0>);
    aIntensity[1] = recall("nIntensity1",1.0);
    aColor[2] = recall("vColor2",<0.0,0.0,0.0>);
    aIntensity[2] = recall("nIntensity2",0.0);
    aColor[3] = recall("vColor3",<0.0,0.0,0.0>);
    aIntensity[3] = recall("nIntensity3",0.0);
    aColor[4] = recall("vColor4",<0.0,0.0,0.0>);
    aIntensity[4] = recall("nIntensity4",0.0);
    aColor[5] = recall("vColor5",<0.0,0.0,0.0>);
    aIntensity[5] = recall("nIntensity5",0.0);
    aColor[6] = recall("vColor6",<0.0,0.0,0.0>);
    aIntensity[6] = recall("nIntensity6",0.0);
    aColor[7] = recall("vColor7",<0.0,0.0,0.0>);
    aIntensity[7] = recall("nIntensity7",1.0);

    reqbegin(sTitle + " " + sVersion);

    // Reset
    ctrl_res0 = ctlbutton("Reset",50,"button_reset"); // Button Reset
    ctlsep();

    // Control
    ctrl_c0 = ctlpopup("Preset",1, @"Gradient",
                                    "RGB",
                                    "Spectrum"@);

    ctlsep();
    ctrl_c1 = ctlcolor("1",aColor[1]);
    ctrl_c2 = ctlpercent("Intensity",aIntensity[1]);
    ctrl_c3 = ctlcolor("2",aColor[2]);
    ctrl_c4 = ctlpercent("Intensity",aIntensity[2]);
    ctrl_c5 = ctlcolor("3",aColor[3]);
    ctrl_c6 = ctlpercent("Intensity",aIntensity[3]);
    ctrl_c7 = ctlcolor("4",aColor[4]);
    ctrl_c8 = ctlpercent("Intensity",aIntensity[4]);
    ctrl_c9 = ctlcolor("5",aColor[5]);
    ctrl_c10 = ctlpercent("Intensity",aIntensity[5]);
    ctrl_c11 = ctlcolor("6",aColor[6]);
    ctrl_c12 = ctlpercent("Intensity",aIntensity[6]);
    ctrl_c13 = ctlcolor("7",aColor[7]);
    ctrl_c14 = ctlpercent("Intensity",aIntensity[7]);

    interpolate();

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

    ctlrefresh(ctrl_c0,"refresh_preset"); // Preset
 
    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");
    ctlrefresh(ctrl_c13,"refresh");
    ctlrefresh(ctrl_c14,"refresh");

    return if !reqpost();

    aColor[1] = getvalue(ctrl_c1);
    aIntensity[1] = getvalue(ctrl_c2);
    aColor[2] = getvalue(ctrl_c3);
    aIntensity[2] = getvalue(ctrl_c4);
    aColor[3] = getvalue(ctrl_c5);
    aIntensity[3] = getvalue(ctrl_c6);
    aColor[4] = getvalue(ctrl_c7);
    aIntensity[4] = getvalue(ctrl_c8);
    aColor[5] = getvalue(ctrl_c9);
    aIntensity[5] = getvalue(ctrl_c10);
    aColor[6] = getvalue(ctrl_c11);
    aIntensity[6] = getvalue(ctrl_c12);
    aColor[7] = getvalue(ctrl_c13);
    aIntensity[7] = getvalue(ctrl_c14);

    // Store
    store("vColor1",aColor[1]);
    store("nIntensity1",aIntensity[1]);
    store("vColor2",aColor[2]);
    store("nIntensity2",aIntensity[2]);
    store("vColor3",aColor[3]);
    store("nIntensity3",aIntensity[3]);
    store("vColor4",aColor[4]);
    store("nIntensity4",aIntensity[4]);
    store("vColor5",aColor[5]);
    store("nIntensity5",aIntensity[5]);
    store("vColor6",aColor[6]);
    store("nIntensity6",aIntensity[6]);
    store("vColor7",aColor[7]);
    store("nIntensity7",aIntensity[7]);

    // Error
    bError = true;
    for(i = 1; i <= 7; i++)
      {
      if(aIntensity[i] > 0.0){bError = false;}
      }
    if(bError)
      {
      info("Intensity on atleast one color must be above 0.0%");
      return;
      }  

    // Camera Blur Length
    if(Camera().blurLength(0.0) < 1.0)
      {
      nCameraBlurLength = Camera().blurLength(0.0);
      }
    else
      {
      nCameraBlurLength = 1.0;
      }

    for(i = 1; i <= Items.size(); i++)
      {

      if(Items[i].genus == LIGHT)
        {

        Items[i].select();
      
    // Envelope

        AddEnvelope("Color");
        envRed = Envelope("Color.R",CHAN_PERCENT,Items[i].name);
        envGreen = Envelope("Color.G",CHAN_PERCENT,Items[i].name);
        envBlue = Envelope("Color.B",CHAN_PERCENT,Items[i].name);

        // Clear 
        while(envRed.keyCount >= 1)
          {
          envRed.deleteKey(envRed.keys[1]);       
          }
        while(envGreen.keyCount >= 1)
          {
          envGreen.deleteKey(envGreen.keys[1]);       
          }
        while(envBlue.keyCount >= 1)
          {
          envBlue.deleteKey(envBlue.keys[1]);       
          }

        if(aIntensity[1] > 0.0)
          {
          envRed.createKey(0.0,aColor[1].x * (1/255) * aIntensity[1]); 
          envRed.setKeyCurve(0.0,CHAN_LINEAR);        
          envGreen.createKey(0.0,aColor[1].y * (1/255) * aIntensity[1]); 
          envGreen.setKeyCurve(0.0,CHAN_LINEAR);        
          envBlue.createKey(0.0,aColor[1].z * (1/255) * aIntensity[1]); 
          envBlue.setKeyCurve(0.0,CHAN_LINEAR);        
          }
        else
          {
          iColor = 0;
          for(c = 1; c <= 7; c++)
            {
            if(aIntensity[c] > 0.0){iColor = c; break;}
            }
          envRed.createKey(0.0,aColor[iColor].x * (1/255) * aIntensity[iColor]); 
          envRed.setKeyCurve(0.0,CHAN_LINEAR);        
          envGreen.createKey(0.0,aColor[iColor].y * (1/255) * aIntensity[iColor]); 
          envGreen.setKeyCurve(0.0,CHAN_LINEAR);        
          envBlue.createKey(0.0,aColor[iColor].z * (1/255) * aIntensity[iColor]); 
          envBlue.setKeyCurve(0.0,CHAN_LINEAR);   
          }

        if(aIntensity[2] > 0.0)
          {           
          envRed.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 1),aColor[2].x * (1/255) * aIntensity[2]); 
          envRed.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 1),CHAN_LINEAR);        
          envGreen.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 1),aColor[2].y * (1/255) * aIntensity[2]); 
          envGreen.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 1),CHAN_LINEAR);        
          envBlue.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 1),aColor[2].z * (1/255) * aIntensity[2]); 
          envBlue.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 1),CHAN_LINEAR); 
          }

        if(aIntensity[3] > 0.0)
          {           
          envRed.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 2),aColor[3].x * (1/255) * aIntensity[3]); 
          envRed.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 2),CHAN_LINEAR);        
          envGreen.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 2),aColor[3].y * (1/255) * aIntensity[3]); 
          envGreen.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 2),CHAN_LINEAR);        
          envBlue.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 2),aColor[3].z * (1/255) * aIntensity[3]); 
          envBlue.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 2),CHAN_LINEAR); 
          }

        if(aIntensity[4] > 0.0)
          {           
          envRed.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 3),aColor[4].x * (1/255) * aIntensity[4]); 
          envRed.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 3),CHAN_LINEAR);        
          envGreen.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 3),aColor[4].y * (1/255) * aIntensity[4]); 
          envGreen.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 3),CHAN_LINEAR);        
          envBlue.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 3),aColor[4].z * (1/255) * aIntensity[4]); 
          envBlue.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 3),CHAN_LINEAR); 
          }

        if(aIntensity[5] > 0.0)
          {           
          envRed.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 4),aColor[5].x * (1/255) * aIntensity[5]); 
          envRed.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 4),CHAN_LINEAR);        
          envGreen.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 4),aColor[5].y * (1/255) * aIntensity[5]); 
          envGreen.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 4),CHAN_LINEAR);        
          envBlue.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 4),aColor[5].z * (1/255) * aIntensity[5]); 
          envBlue.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 4),CHAN_LINEAR); 
          }

        if(aIntensity[6] > 0.0)
          {           
          envRed.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 5),aColor[6].x * (1/255) * aIntensity[6]); 
          envRed.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 5),CHAN_LINEAR);        
          envGreen.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 5),aColor[6].y * (1/255) * aIntensity[6]); 
          envGreen.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 5),CHAN_LINEAR);        
          envBlue.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 5),aColor[6].z * (1/255) * aIntensity[6]); 
          envBlue.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 5),CHAN_LINEAR); 
          }

        if(aIntensity[7] > 0.0)
          {           
          envRed.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 6),aColor[7].x * (1/255) * aIntensity[7]); 
          envRed.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 6),CHAN_LINEAR);        
          envGreen.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 6),aColor[7].y * (1/255) * aIntensity[7]); 
          envGreen.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 6),CHAN_LINEAR);        
          envBlue.createKey((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 6),aColor[7].z * (1/255) * aIntensity[7]); 
          envBlue.setKeyCurve((1 / Scene().fps) * nCameraBlurLength * ((1 / 6) * 6),CHAN_LINEAR); 
          }

        if(aIntensity[7] <= 0.0 || nCameraBlurLength < 1.0)
          {
          iColor = 0;
          for(c = 7; c >= 1; c--)
            {
            if(aIntensity[c] > 0.0){iColor = c; break;}
            }
          envRed.createKey(1 / Scene().fps,aColor[iColor].x * (1/255) * aIntensity[iColor]); 
          envRed.setKeyCurve(1 / Scene().fps,CHAN_LINEAR);        
          envGreen.createKey(1 / Scene().fps,aColor[iColor].y * (1/255) * aIntensity[iColor]); 
          envGreen.setKeyCurve(1 / Scene().fps,CHAN_LINEAR);        
          envBlue.createKey(1 / Scene().fps,aColor[iColor].z * (1/255) * aIntensity[iColor]); 
          envBlue.setKeyCurve(1 / Scene().fps,CHAN_LINEAR);   
          }
            
          // Repeat
          envRed.preBehavior = CHAN_REPEAT;
          envRed.postBehavior = CHAN_REPEAT;
          envGreen.preBehavior = CHAN_REPEAT;
          envGreen.postBehavior = CHAN_REPEAT;
          envBlue.preBehavior = CHAN_REPEAT;
          envBlue.postBehavior = CHAN_REPEAT;

    //

        }

      }   

}

button_reset
{
    bRequesterUpdate = true;

    setvalue(ctrl_c1,<1.0,1.0,1.0>); // Color 1
    setvalue(ctrl_c2,1.0); // Intensity 1
    setvalue(ctrl_c3,<0.0,0.0,0.0>); // Color 2
    setvalue(ctrl_c4,0.0); // Intensity 2
    setvalue(ctrl_c5,<0.0,0.0,0.0>); // Color 3
    setvalue(ctrl_c6,0.0); // Intensity 3
    setvalue(ctrl_c7,<0.0,0.0,0.0>); // Color 4
    setvalue(ctrl_c8,0.0); // Intensity 4
    setvalue(ctrl_c9,<0.0,0.0,0.0>); // Color 5
    setvalue(ctrl_c10,0.0); // Intensity 5
    setvalue(ctrl_c11,<0.0,0.0,0.0>); // Color 6
    setvalue(ctrl_c12,0.0); // Intensity 6
    setvalue(ctrl_c13,<0.0,0.0,0.0>); // Color 7
    setvalue(ctrl_c14,1.0); // Intensity 7

    // Update
    aColor[1] = getvalue(ctrl_c1);
    aIntensity[1] = getvalue(ctrl_c2);
    aColor[2] = getvalue(ctrl_c3);
    aIntensity[2] = getvalue(ctrl_c4);
    aColor[3] = getvalue(ctrl_c5);
    aIntensity[3] = getvalue(ctrl_c6);
    aColor[4] = getvalue(ctrl_c7);
    aIntensity[4] = getvalue(ctrl_c8);
    aColor[5] = getvalue(ctrl_c9);
    aIntensity[5] = getvalue(ctrl_c10);
    aColor[6] = getvalue(ctrl_c11);
    aIntensity[6] = getvalue(ctrl_c12);
    aColor[7] = getvalue(ctrl_c13);
    aIntensity[7] = getvalue(ctrl_c14); 

    bRequesterUpdate = false;

    interpolate();
}

refresh:value
{
    if(!bRequesterUpdate)
      {
      aColor[1] = getvalue(ctrl_c1);
      aIntensity[1] = getvalue(ctrl_c2);
      aColor[2] = getvalue(ctrl_c3);
      aIntensity[2] = getvalue(ctrl_c4);
      aColor[3] = getvalue(ctrl_c5);
      aIntensity[3] = getvalue(ctrl_c6);
      aColor[4] = getvalue(ctrl_c7);
      aIntensity[4] = getvalue(ctrl_c8);
      aColor[5] = getvalue(ctrl_c9);
      aIntensity[5] = getvalue(ctrl_c10);
      aColor[6] = getvalue(ctrl_c11);
      aIntensity[6] = getvalue(ctrl_c12);
      aColor[7] = getvalue(ctrl_c13);
      aIntensity[7] = getvalue(ctrl_c14);

      interpolate();
      }
}

refresh_preset:value
{

    bRequesterUpdate = true;

    if(value == 1) // Gradient
      {
      setvalue(ctrl_c1,<1.0,1.0,1.0>); // Color 1
      setvalue(ctrl_c2,1.0); // Intensity 1
      setvalue(ctrl_c3,<0.0,0.0,0.0>); // Color 2
      setvalue(ctrl_c4,0.0); // Intensity 2
      setvalue(ctrl_c5,<0.0,0.0,0.0>); // Color 3
      setvalue(ctrl_c6,0.0); // Intensity 3
      setvalue(ctrl_c7,<0.0,0.0,0.0>); // Color 4
      setvalue(ctrl_c8,0.0); // Intensity 4
      setvalue(ctrl_c9,<0.0,0.0,0.0>); // Color 5
      setvalue(ctrl_c10,0.0); // Intensity 5
      setvalue(ctrl_c11,<0.0,0.0,0.0>); // Color 6
      setvalue(ctrl_c12,0.0); // Intensity 6
      setvalue(ctrl_c13,<0.0,0.0,0.0>); // Color 7
      setvalue(ctrl_c14,1.0); // Intensity 7
      }  

    if(value == 2) // RGB
      {
      setvalue(ctrl_c1,<1.0,0.0,0.0>); // Color 1
      setvalue(ctrl_c2,1.0); // Intensity 1
      setvalue(ctrl_c3,<0.0,0.0,0.0>); // Color 2
      setvalue(ctrl_c4,0.0); // Intensity 2
      setvalue(ctrl_c5,<0.0,0.0,0.0>); // Color 3
      setvalue(ctrl_c6,0.0); // Intensity 3
      setvalue(ctrl_c7,<0.0,1.0,0.0>); // Color 4
      setvalue(ctrl_c8,1.0); // Intensity 4
      setvalue(ctrl_c9,<0.0,0.0,0.0>); // Color 5
      setvalue(ctrl_c10,0.0); // Intensity 5
      setvalue(ctrl_c11,<0.0,0.0,0.0>); // Color 6
      setvalue(ctrl_c12,0.0); // Intensity 6
      setvalue(ctrl_c13,<0.0,0.0,1.0>); // Color 7
      setvalue(ctrl_c14,1.0); // Intensity 7
      } 

    if(value == 3) // Spectrum
      {
      setvalue(ctrl_c1,<1.0,0.0,0.0>); // Color 1
      setvalue(ctrl_c2,1.0); // Intensity 1
      setvalue(ctrl_c3,<1.0,0.5,0.0>); // Color 2
      setvalue(ctrl_c4,1.0); // Intensity 2
      setvalue(ctrl_c5,<1.0,1.0,0.0>); // Color 3
      setvalue(ctrl_c6,1.0); // Intensity 3
      setvalue(ctrl_c7,<0.0,1.0,0.0>); // Color 4
      setvalue(ctrl_c8,1.0); // Intensity 4
      setvalue(ctrl_c9,<0.0,1.0,1.0>); // Color 5
      setvalue(ctrl_c10,1.0); // Intensity 5
      setvalue(ctrl_c11,<0.0,0.0,0.6255>); // Color 6
      setvalue(ctrl_c12,1.0); // Intensity 6
      setvalue(ctrl_c13,<0.5,0.0,0.5>); // Color 7
      setvalue(ctrl_c14,1.0); // Intensity 7
      }


    // Update
    aColor[1] = getvalue(ctrl_c1);
    aIntensity[1] = getvalue(ctrl_c2);
    aColor[2] = getvalue(ctrl_c3);
    aIntensity[2] = getvalue(ctrl_c4);
    aColor[3] = getvalue(ctrl_c5);
    aIntensity[3] = getvalue(ctrl_c6);
    aColor[4] = getvalue(ctrl_c7);
    aIntensity[4] = getvalue(ctrl_c8);
    aColor[5] = getvalue(ctrl_c9);
    aIntensity[5] = getvalue(ctrl_c10);
    aColor[6] = getvalue(ctrl_c11);
    aIntensity[6] = getvalue(ctrl_c12);
    aColor[7] = getvalue(ctrl_c13);
    aIntensity[7] = getvalue(ctrl_c14); 

    bRequesterUpdate = false;

    interpolate();
}

interpolate
{

    bRequesterUpdate = true;

    for(i = 1; i <= 7; i++)
      {
      if(aIntensity[i] <= 0.0)
        {


        iColorA = 0;
        for(c = i; c >= 1; c--)
          {
          if(aIntensity[c] > 0.0){iColorA = c; break;}
          }

        iColorB = 0;
        for(c = i; c <= 7; c++)
          {
          if(aIntensity[c] > 0.0){iColorB = c; break;}
          }

        if(iColorA == 0)
          {aColor[i] = aColor[iColorB];}
        else if(iColorB == 0)
          {aColor[i] = aColor[iColorA];}
        else
          {
          aColor[i] = linear1D(aColor[iColorA],aColor[iColorB],maprange01(iColorA,iColorB,i)); 
          } 


        } 
      }

      if(aIntensity[1] <= 0.0){setvalue(ctrl_c1,(1/255) * aColor[1]);} // Color 1
      if(aIntensity[2] <= 0.0){setvalue(ctrl_c3,(1/255) * aColor[2]);} // Color 2
      if(aIntensity[3] <= 0.0){setvalue(ctrl_c5,(1/255) * aColor[3]);} // Color 3
      if(aIntensity[4] <= 0.0){setvalue(ctrl_c7,(1/255) * aColor[4]);} // Color 4
      if(aIntensity[5] <= 0.0){setvalue(ctrl_c9,(1/255) * aColor[5]);} // Color 5
      if(aIntensity[6] <= 0.0){setvalue(ctrl_c11,(1/255) * aColor[6]);} // Color 6
      if(aIntensity[7] <= 0.0){setvalue(ctrl_c13,(1/255) * aColor[7]);} // Color 7

    bRequesterUpdate = false;

}

// MAP RANGE

maprange01: n1,n2,i
{    
    if(n2-n1 == 0.0){return(0.0);}
  else
    {return((1/(n2-n1)) * (i-n1));}
}

// INTERPOLATION

linear1D: n1,n2,i // i = interpolation point (0-1)
{
    return(n1 * (1 - i) + n2 * i);     
}


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

Saturday 24 March 2012

LScript - Modeler_Jitter


LScript (Modeler) to offsets vertices based on chosen parameters such as noise and Brownian motion.

Changes

  • Seeded noise
  • Seeded fractal Brownian motion
  • 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 - Jitter

    Modeler_Jitter.ls

*/

@version 2.2
@warnings
@script modeler
@name *Jitter

    // Title
    sTitle = "*Jitter";

    // Version
    sVersion = "v2.0";
 
    bDone = false; // Done
    bChange = false; // Change
    bPreview; // Preview
    iType;
    bAxisX;
    bAxisY;
    bAxisZ;
    nAmplitude;
    iOctaves;
    nPersistence;
    vScale;
    iSeed;
    iInterpolation;
   
    ctrl_c0,ctrl_c1,ctrl_c2,ctrl_c3,ctrl_c4,ctrl_c5,ctrl_c6,ctrl_c7,ctrl_c8,ctrl_c9;
    ctrl_res0;
    ctrl_prev0;

main
{

    // Recall
    bPreview = recall("bPreview",true);
    iType = recall("iType",2);
    bAxisX = recall("bAxisX",true);
    bAxisY = recall("bAxisY",true);
    bAxisZ = recall("bAxisZ",true);
    nAmplitude = recall("nAmplitude",0.1);
    iOctaves = recall("iOctaves",3);
    nPersistence = recall("nPersistence",0.25);
    vScale = recall("vScale",<1.0,1.0,1.0>);
    iSeed = recall("iSeed",1);
    iInterpolation = recall("iInterpolation",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 = ctlchoice("Type",iType,@"Noise","fBm"@); // Type
    ctrl_c1 = ctlcheckbox("X",bAxisX); // X
    ctrl_c2 = ctlcheckbox("Y",bAxisY); // Y
    ctrl_c3 = ctlcheckbox("Z",bAxisZ); // Z
    ctrl_c4 = ctldistance("Amplitude",nAmplitude); // Amplitude
    ctrl_c5 = ctlslider("Octaves",iOctaves,1,64); // Octaves
    ctrl_c6 = ctlnumber("Persistence",nPersistence); // Persistence
    ctrl_c7 = ctlvector("Scale",vScale); // Scale
    ctrl_c8 = ctlinteger("Seed",iSeed); // Seed
    ctrl_c9 = ctlchoice("Interpolation",iInterpolation,@"None","Linear","Cosine"@); // Interpolation

    // 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");

    if (!reqpost())
    {
        // Cancel

        if(bDone){undo();} // Undo

        return;
    }
    else
    {
        // Ok

        if(!bDone || bChange) // Process
        {
        values(); // Values
        process(); // Process
        }

        // Store
        store("bPreview",bPreview);
        store("iType",iType);
        store("bAxisX",bAxisX);
        store("bAxisY",bAxisY);
        store("bAxisZ",bAxisZ);
        store("nAmplitude",nAmplitude);
        store("iOctaves",iOctaves);
        store("nPersistence",nPersistence);
        store("vScale",vScale);
        store("iSeed",iSeed);
        store("iInterpoltation",iInterpolation);
    }

    reqend();
}

refresh:value
{
    bChange = true; // Change
    values(); // Values
    if(bPreview){process();} // Process
}

values
{
    bPreview = getvalue(ctrl_prev0); // Preview
    iType = getvalue(ctrl_c0); // Type
    bAxisX = getvalue(ctrl_c1); // X
    bAxisY = getvalue(ctrl_c2); // Y
    bAxisZ = getvalue(ctrl_c3); // Z
    nAmplitude = getvalue(ctrl_c4); // Amplitude
    iOctaves = getvalue(ctrl_c5); // Octaves
    nPersistence = getvalue(ctrl_c6); // Persistence
    vScale = getvalue(ctrl_c7); // Scale
    iSeed = getvalue(ctrl_c8); // Seed 
    iInterpolation = getvalue(ctrl_c9); // Interpolation
}

button_reset
{
    setvalue(ctrl_c0,2); // Type
    setvalue(ctrl_c1,true); // X
    setvalue(ctrl_c2,true); // Y
    setvalue(ctrl_c3,true); // Z
    setvalue(ctrl_c4,0.1); // Amplitude
    setvalue(ctrl_c5,3); // Octaves
    setvalue(ctrl_c6,0.25); // Persistence
    setvalue(ctrl_c7,<1.0,1.0,1.0>); // Scale
    setvalue(ctrl_c8,1); // Seed
    setvalue(ctrl_c9,3); // Interpolation
}

process
{
    // Undo
    if(bDone){undo();}
    undogroupbegin();

    // Process

    // Selection - Point (DIRECT)
    selmode(DIRECT);
    iPointCount = pointcount();
    if(iPointCount < 1) error("No points selected.");

    noiseseed(iSeed); // Noise Seed

    for(iO = 1; iO <= 3; iO++)
      {
      aOffset[iO] = ;
      }

    editbegin();

        if((iType == "1") && (iInterpolation == 1)) // Noise
          {
          moninit(iPointCount,"Processing...");  // Progress Monitor
          for(iCurrentPoint = 1; iCurrentPoint <= iPointCount; iCurrentPoint++)
            {
            vOffset = <0.0,0.0,0.0>;
            vPoint = pointinfo(points[iCurrentPoint]) * vScale;
            if(bAxisX){vOffset.x = noise3D(vPoint + aOffset[1]);}
            if(bAxisY){vOffset.y = noise3D(vPoint + aOffset[2]);}
            if(bAxisZ){vOffset.z = noise3D(vPoint + aOffset[3]);}
            pointmove(points[iCurrentPoint],pointinfo(points[iCurrentPoint]) + (vOffset * nAmplitude)); // Move point  
            monstep(); // Progress Monitor
            }
          monend(); // Progress Monitor
          } 

        else if((iType == "1") && (iInterpolation == 2)) // Linear Noise
          {
          moninit(iPointCount,"Processing...");  // Progress Monitor
          for(iCurrentPoint = 1; iCurrentPoint <= iPointCount; iCurrentPoint++)
            {
            vOffset = <0.0,0.0,0.0>;
            vPoint = pointinfo(points[iCurrentPoint]) * vScale;
            if(bAxisX){vOffset.x = linearnoise3D(vPoint + aOffset[1]);}
            if(bAxisY){vOffset.y = linearnoise3D(vPoint + aOffset[2]);}
            if(bAxisZ){vOffset.z = linearnoise3D(vPoint + aOffset[3]);}
            pointmove(points[iCurrentPoint],pointinfo(points[iCurrentPoint]) + (vOffset * nAmplitude)); // Move point  
            monstep(); // Progress Monitor
            }
          monend(); // Progress Monitor
          }

        else if((iType == "1") && (iInterpolation == 3)) // Cosine Noise
          {
          moninit(iPointCount,"Processing...");  // Progress Monitor
          for(iCurrentPoint = 1; iCurrentPoint <= iPointCount; iCurrentPoint++)
            {
            vOffset = <0.0,0.0,0.0>;
            vPoint = pointinfo(points[iCurrentPoint]) * vScale;
            if(bAxisX){vOffset.x = cosinenoise3D(vPoint + aOffset[1]);}
            if(bAxisY){vOffset.y = cosinenoise3D(vPoint + aOffset[2]);}
            if(bAxisZ){vOffset.z = cosinenoise3D(vPoint + aOffset[3]);}
            pointmove(points[iCurrentPoint],pointinfo(points[iCurrentPoint]) + (vOffset * nAmplitude)); // Move point  
            monstep(); // Progress Monitor
            }
          monend(); // Progress Monitor
          }  

        else if((iType == "2") && (iInterpolation == 1)) // fBm Noise
          {
          moninit(iPointCount,"Processing...");  // Progress Monitor
          for(iCurrentPoint = 1; iCurrentPoint <= iPointCount; iCurrentPoint++)
            {
            vOffset = <0.0,0.0,0.0>;
            vPoint = pointinfo(points[iCurrentPoint]) * vScale;
            if(bAxisX){vOffset.x = fBmnoise3D(vPoint + aOffset[1],iOctaves,nPersistence);}
            if(bAxisY){vOffset.y = fBmnoise3D(vPoint + aOffset[2],iOctaves,nPersistence);}
            if(bAxisZ){vOffset.z = fBmnoise3D(vPoint + aOffset[3],iOctaves,nPersistence);}
            pointmove(points[iCurrentPoint],pointinfo(points[iCurrentPoint]) + (vOffset * nAmplitude)); // Move point  
            monstep(); // Progress Monitor
            }
          monend(); // Progress Monitor
          }  

        else if((iType == "2") && (iInterpolation == 2)) // Linear fBm Noise
          {
          moninit(iPointCount,"Processing...");  // Progress Monitor
          for(iCurrentPoint = 1; iCurrentPoint <= iPointCount; iCurrentPoint++)
            {
            vOffset = <0.0,0.0,0.0>;
            vPoint = pointinfo(points[iCurrentPoint]) * vScale;
            if(bAxisX){vOffset.x = linearfBmnoise3D(vPoint + aOffset[1],iOctaves,nPersistence);}
            if(bAxisY){vOffset.y = linearfBmnoise3D(vPoint + aOffset[2],iOctaves,nPersistence);}
            if(bAxisZ){vOffset.z = linearfBmnoise3D(vPoint + aOffset[3],iOctaves,nPersistence);}
            pointmove(points[iCurrentPoint],pointinfo(points[iCurrentPoint]) + (vOffset * nAmplitude)); // Move point  
            monstep(); // Progress Monitor
            }
          monend(); // Progress Monitor
          }

        else if((iType == "2") && (iInterpolation == 3)) // Cosine fBm Noise
          {
          moninit(iPointCount,"Processing...");  // Progress Monitor
          for(iCurrentPoint = 1; iCurrentPoint <= iPointCount; iCurrentPoint++)
            {
            vOffset = <0.0,0.0,0.0>;
            vPoint = pointinfo(points[iCurrentPoint]) * vScale;
            if(bAxisX){vOffset.x = cosinefBmnoise3D(vPoint + aOffset[1],iOctaves,nPersistence);}
            if(bAxisY){vOffset.y = cosinefBmnoise3D(vPoint + aOffset[2],iOctaves,nPersistence);}
            if(bAxisZ){vOffset.z = cosinefBmnoise3D(vPoint + aOffset[3],iOctaves,nPersistence);}
            pointmove(points[iCurrentPoint],pointinfo(points[iCurrentPoint]) + (vOffset * nAmplitude)); // Move point  
            monstep(); // Progress Monitor
            }
          monend(); // Progress Monitor
          }

    editend();

    // Undo
    undogroupend();

    bChange = false; // Change

    // Done
    bDone = true;
}

// INTERPOLATION

linear1D: n1,n2,i // i = interpolation point (0-1)
{
    return(n1 * (1 - i) + n2 * i);     
}

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;
_noiseoffset = 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));
      }

    for(iO = 1; iO <= 64; iO++)
      {
      _noiseoffset[iO] = ;
      }
}

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)]);
}

linearnoise3D: v // n
{
    v = wrap(1,_noiseresolution,v); 
    vFrac = frac(v);
    vInt = v - vFrac;
    nA1 = noise3D();
    nA2 = noise3D();
    nA3 = noise3D();
    nA4 = noise3D();
    nA = linear1D(linear1D(nA1,nA2,vFrac.x),linear1D(nA3,nA4,vFrac.x),vFrac.z);
    nB1 = noise3D();
    nB2 = noise3D();
    nB3 = noise3D();
    nB4 = noise3D();
    nB = linear1D(linear1D(nB1,nB2,vFrac.x),linear1D(nB3,nB4,vFrac.x),vFrac.z);
    return(linear1D(nA,nB,vFrac.y));
}

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));
}

fBmnoise3D: v,octaves,persistence // octaves = i | persistence = n (0.25) // n
{
// !    if(_noiseoffset == nil){noiseinit();} // Init
    nNoise = 0.0;
    for(iO = 1; iO <= octaves; iO++)
      {
      nNoise += noise3D(<(v.x + _noiseoffset[iO].x) * (2 * iO),(v.y + _noiseoffset[iO].y) * (2 * iO),(v.z + _noiseoffset[iO].z) * (2 * iO)>) * (persistence / iO);
      }
    return(nNoise);
}

linearfBmnoise3D: v,octaves,persistence // octaves = i | persistence = n (0.25) // n
{
// !    if(_noiseoffset == nil){noiseinit();} // Init
    nNoise = 0.0;
    for(iO = 1; iO <= octaves; iO++)
      {
      nNoise += linearnoise3D(<(v.x + _noiseoffset[iO].x) * (2 * iO),(v.y + _noiseoffset[iO].y) * (2 * iO),(v.z + _noiseoffset[iO].z) * (2 * iO)>) * (persistence / iO);
      }
    return(nNoise);
}

cosinefBmnoise3D: v,octaves,persistence // octaves = i | persistence = n (0.25) // n
{
// !    if(_noiseoffset == nil){noiseinit();} // Init
    nNoise = 0.0;
    for(iO = 1; iO <= octaves; iO++)
      {
      nNoise += cosinenoise3D(<(v.x + _noiseoffset[iO].x) * (2 * iO),(v.y + _noiseoffset[iO].y) * (2 * iO),(v.z + _noiseoffset[iO].z) * (2 * iO)>) * (persistence / iO);
      }
    return(nNoise);
}

// 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);
}

gaussianrandom
{
    n1 = random();
    n2 = random();
    if(n1 == 0.0){n1 = 0.01;}
    return(sqrt(-2.0 * log(n1)) * cos(2.0 * 3.1415926535 * n2));
}

// 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

Wednesday 14 March 2012

LScript - Motion_SpotlightTrick


LScript (Layout) to anti-aliase shadow maps used on Spotlights. It works by implementing an old school technique of spinning (Spinning Light Trick) a light across a frame time inorder to offset sample positions. It helps reduce glitches and improves overall image quality. Apply it to a Spotlight in its Motion Options, enable motion blur and see what happens when you render.

Changes

  • Must have motionblur enabled with more than 1 pass
  • Attach to a spotlight
  • Enable shadow maps

Compatible with Newtek LightWave 9.6 and above.

// LScript Item Animation - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/*  
    LScript Item Animation - SpotlightTrick

    Motion_SpotlightTrick.ls

*/

@version 2.2
@warnings
@script motion
@name *Spotlight Trick

    // Title
    sTitle = "*Spotlight Trick";

    // Version
    sVersion = "v1.1";

    // Item
    Item = nil;

    // Variable
    bH = false;
    bP = false;
    bB = true;
    nAmount = 360.0;
    nSoftEdge = 0.0;   

create : id
{
    // Description
    setdesc(sTitle);
 
    // Info
    info("*Spotlight Trick - Motion blur must be enabled.");

    // Item
    Item = id; // Item
}

destroy
{
}

process: ma, frame, time
{     
    // Variables
    vPosition = ma.get(POSITION,time);
    vRotation = ma.get(ROTATION,time);
    vnForward = normalize3D(Item.getForward(time));

    if(Camera().blurLength(time) <> 0.0)
      {
      // Map Range
      n01 = maprange01(frame * (1 / Scene().fps),(frame + 1) * (1 / Scene().fps),time);

      // Position
      if(nSoftEdge <> 0.0){vPosition -= vnForward * ((10 / Camera().blurLength(time)) * nSoftEdge * n01);} 

      // Rotation
      nDegree = linear1D(0.0,(1 / Camera().blurLength(time)) * nAmount.0,n01);
      if(bH){vRotation.x += nDegree;} // H
      if(bP){vRotation.y += nDegree;} // P
      if(bB){vRotation.z += nDegree;} // B  
      } 

// ma

  ma.set(POSITION,vPosition);
  ma.set(ROTATION,vRotation);

}

// INTERPOLATION

linear1D: n1,n2,i // i = interpolation point (0-1)
{
    return(n1 * (1 - i) + n2 * i);     
}

// MAP RANGE

maprange01: n1,n2,i

{    
    if(n2-n1 == 0.0){return(0.0);}
  else
    {return((1/(n2-n1)) * (i-n1));}
}

// VECTOR 3D

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);
}

load: what,io
{
    if(what == SCENEMODE)   // processing an ASCII scene file
    {
        if(io.read().asStr() == sTitle + " " + sVersion)
            {
            bH = io.read().asInt(); // H
            bP = io.read().asInt(); // P
            bB = io.read().asInt(); // B
            nAmount = io.read().asNum(); // Amount           
            nSoftEdge = io.read().asNum(); // Soft Edge           
            }
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        // Header
        io.writeln(sTitle + " " + sVersion);

        io.writeln(bH); // H
        io.writeln(bP); // P
        io.writeln(bB); // B
        io.writeln(nAmount); // Amount
        io.writeln(nSoftEdge); // Soft Edge
    }
}

options
{
    if(reqisopen())
        {
        reqend();
        return;
        }

    reqbegin(sTitle + " " + sVersion);

    ctrl_c0 = ctlcheckbox("Spin H", bH);
    ctrl_c1 = ctlcheckbox("Spin P", bP);
    ctrl_c2 = ctlcheckbox("Spin B (Antialiase Shadow Map)", bB);
    ctrl_c3 = ctlangle("Amount",nAmount);   
    ctlsep();
    ctrl_c4 = ctlpercent("Soft Edge",nSoftEdge);   

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

    // Refresh
    ctlrefresh(ctrl_c0,"refresh_c0"); // H
    ctlrefresh(ctrl_c1,"refresh_c1"); // P
    ctlrefresh(ctrl_c2,"refresh_c2"); // B
    ctlrefresh(ctrl_c3,"refresh_c3"); // Amount
    ctlrefresh(ctrl_c4,"refresh_c4"); // Soft Edge

    reqopen();
}

refresh_c0:value // H
{
    bH = value;
}

refresh_c1:value // P
{
    bP = value;
}

refresh_c2:value // B
{
    bB = value;
}

refresh_c3:value // Amount
{
    nAmount = value;
}

refresh_c4:value // Soft Edge
{
    nSoftEdge = value;
}


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

Friday 10 February 2012

LScript - Modeler_Cable


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