A Simple Button Macro

If your animations include a lot of science fiction work, or other instances where a push button is part of the scene, this short macro will do a bit of the work for you.
#macro RoundButton(pB, pT, rB, rE, dD, fM)
  #local hB = vlength(pT - pB);
  #local vY = vnormalize(pT - pB);
  #local vX = vnormalize(vcross(vY, <vY.y,vY.z,-vY.x>));
  #local vZ = vnormalize(vcross(vX, vY));
  #if (fM)
    merge
  #else
    union
  #end
  {
  #if (dD < 0)
  #local rD = (2 * rB * rE - rB * rB - rE * rE - dD * dD) / 2 / dD - rE;
    difference {
      lathe { 5, <0,0>, <rB,0>, <rB, hB - rE>, <rB - rE, hB - rE>, <0, hB + rD + dD> }
      sphere { y * (hB + rD + dD), rD }
      bounded_by { cylinder { 0, y * hB, rB } }
    }
  #elseif (dD > 0)
    #local hB = hB - dD;
    #local rD = (rB * rB + rE * rE + dD * dD - 2 * rB * rE) / 2 / dD + rE;
    intersection {
      lathe { 6, <0,0>, <rB,0>, <rB, hB - rE>, <rB - rE, hB - rE>,
        <rB - rE, hB - rE> + 2 * <rB - rE, rD - rE - dD> * rE / (rD - rE),
        <0, rD + rE> }
      sphere { y * (hB + dD - rD), rD }
      bounded_by { cylinder { 0, y * (hB + dD), rB } }
    }
  #else
    cylinder { 0, y * (hB - rE), rB }
    cylinder { y * (hB - 2 * rE), y * hB, (rB - rE) }
  #end
  torus { rB - rE, rE translate y * (hB - rE) }
  matrix <vX.x,vX.y,vX.z, vY.x,vY.y,vY.z, vZ.x,vZ.y,vZ.z, pB.x,pB.y,pB.z>
  }
#end
The button it creates is round, with a rounded edge, and you can make the face flat, dimpled, or protruding. The parameters have the following meaning:
  • pB is a vector that specifies the bottom of the button.
  • pT is a vector that specifies the top of the button.
  • rB is a scalar that specifies the radius of the button.
  • rE is a scalar that specifies the radius of the top edge of the button.
  • dD is a scalar that specifies whether the button is dimpled (for a negative value), flat (a value of zero), or bulging (a positive value).
  • fM specifies whether the pieces of the button will be held in a merge object or a union object. Set this to 1 (or some other non-zero value) if the button's texture will have some transparency, otherwise set it to 0.
  • The resulting button will fit entirely in the cylinder running from pB to pT with a radius of rB.
    To use the macro, place the call to the macro in an object and apply any desired texturing and transformations in that:
    object {
      RoundButton(<0, 0, 0>, <0, .25, 0>, .75, .03, -.02, 0)
      texture { pigment { red 1 } finish { ambient .1 diffuse .9 } }
      translate { ButtonTransform }
    }
    
    This will produce a red button that is 1.5 units across, .25 units tall, with a slightly-rounded edge and a shallow dimple on the face. ButtonTransform will need to be defined in the preceding scripting so that the button can be placed however you need it.
    The chief value of this macro comes from the edge radius and bulge/dimple parameters, because they provide fire-and-forget support for the small but important details. We could use a simple cylinder object to model the button, but real-life push buttons don't have the infinitely-sharp edges that idealized cylinders do, and they often don't have perfectly flat faces, either. Modeling the most common details, and getting everything right so that there are no visible seams between the parts that make up the whole, takes a bit of math that can be easily automated in code.

    Comments

    Popular posts from this blog

    Transition Macros

    Titling Made Simple

    Star Field Generator