This rhino script allows the user to create highly varied, yet controllable, low polygon count “hairs”. This script operates based on the world coordinate system, growing upwards from a user-selected series of points.
Version 2 allows for the selection of a surface which will be randomly populated with grass blades perpendicular to the surface (about the surface normal) The user is given the option to specify the range of lengths (min-max), the range of bending per segment, and the base and tip radius. The user can control the number of segments the blade will have, the more segments, the smoother the bend, the greater the polygons. In addition as part of the interest in polygon optimization, the user can specify the number of sides on each blade, a 2 sided blade is flat, 3 sided become three dimensional (triangular), 4 rectangular, etc. the higher the number the rounder it is, the higher the polygon count.
Rhino Script
Option Explicit 'Script written by <David Mans> 'Script copyrighted by <Neoarchaic Studio> 'Script version Sunday, July 05, 2009 9:42:52 PM Call Main() Sub Main() Dim strSurface, arrInputs strSurface = Rhino.GetObject("Select Surface", 8) If isNull(strSurface) Then Exit Sub Call reparameterize(strSurface) arrInputs = Rhino.PropertyListBox(array("Count", "Min Length", "Max Length", "Min Hair Bend", "Max Hair Bend", "Base Radius", "Tip Radius", "Segments", "Sides"), array(1000, 4, 12, 10, 45, 0.1, 0.01, 5, 2)) If isNull(arrInputs) Then Exit Sub Dim i, stem(), blades(), sides If CInt(arrInputs(7)) < 2 Then sides = 2 Else sides = CInt(arrInputs(7)) End If Dim arrPlanes Call Rhino.EnableRedraw(False) arrPlanes = randomPtsSrf(strSurface, CInt(arrInputs(0))) ReDim stem(uBound(arrPlanes)), blades(uBound(arrPlanes)) For i = 0 To uBound(arrPlanes) Step 1 stem(i) = segmentedStem(arrPlanes(i), random(CDbl(arrInputs(1)), CDbl(arrInputs(2))), CInt(arrInputs(7)), random(CDbl(arrInputs(3)), CDbl(arrInputs(4)))) blades(i) = bladesFlat(stem(i), CDbl(arrInputs(5)), CDbl(arrInputs(6)), sides) Next Call Rhino.EnableRedraw(True) End Sub Function randomPtsSrf(strSurface, intCount) randomPtsSrf = Null Dim i, uDom, vDom, arrOutput() ReDim arrOutput(intCount-1) uDom = Rhino.SurfaceDomain(strSurface, 0) vDom = Rhino.SurfaceDomain(strSurface, 1) For i = 0 To intCount - 1 Step 1 arrOutput(i) = Rhino.SurfaceFrame(strSurface, array(random(uDom(0), uDom(1)), random(vDom(0), vDom(1)))) Next randomPtsSrf = arrOutput End Function Function bladesFlat(arrPlanes, radB, radT, intSteps) bladesFlat = Null Dim i, j, k, r, arrOutput Dim radStep, rotStep Dim arrPoints(),arrFaces(), arrMesh() ReDim arrMesh(intSteps-1) If radB > radT Then radStep = -(radB - radT) / uBound(arrPlanes) Else radStep = (radT - radB) / uBound(arrPlanes) End If rotStep = 360 / intSteps For k = 0 To intSteps - 1 Step 1 r = 0 For i = 0 To uBound(arrPlanes) Step 1 ReDim Preserve arrPoints(r) arrPoints(r) = Rhino.PointAdd(arrPlanes(i)(0), Rhino.VectorScale(Rhino.VectorUnitize(Rhino.RotatePlane(arrPlanes(i), k * rotStep, arrPlanes(i)(3))(1)), radB + i * radStep)) r = r + 1 ReDim Preserve arrPoints(r) arrPoints(r) = Rhino.PointAdd(arrPlanes(i)(0), Rhino.VectorScale(Rhino.VectorUnitize(Rhino.RotatePlane(arrPlanes(i), (k + 1) * rotStep, arrPlanes(i)(3))(1)), radB + i * radStep)) r = r + 1 Next r = 0 ReDim arrFaces(uBound(arrPoints)-2) For i = 0 To uBound(arrPoints) - 2 Step 2 arrFaces(r) = array(i, i + 1, i + 3, i + 3) r = r + 1 arrFaces(r) = array(i, i + 3, i + 2, i + 2) r = r + 1 Next If intSteps = 2 Then If k = 1 Then arrOutput = Rhino.addmesh(arrPoints, arrFaces) End If Else arrMesh(k) = Rhino.addmesh(arrPoints, arrFaces) End If Next If intSteps >< 2 Then arrOutput = Rhino.MeshBooleanUnion(arrMesh) End If bladesFlat = arrOutput End Function Function segmentedStem(arrPlane, dblHeight, dblSegments, maxRotation) segmentedStem = Null Dim i, count count = dblSegments - 1 Dim dblStep, tempLen, dblLen() Dim mPlane(), tmpAngle(1), blnWavy ReDim dblLen(count), mPlane(count+1) mPlane(0) = Rhino.RotatePlane(arrPlane, random(0, 360), arrPlane(3)) blnWavy = random(-1, 1) dblStep = dblHeight / dblSegments For i = 0 To count Step 1 If i = 0 Then tempLen = random(0.5, 1) * dblStep dblLen(i) = dblStep - tempLen ElseIf i = count Then tempLen = dblStep + dblLen(i - 1) Else tempLen = random(0.5, 1) * (dblStep + dblLen(i - 1)) dblLen(i) = dblStep + dblLen(i - 1) - tempLen End If If blnWavy >= 0 Then tmpAngle(0) = random(0, maxRotation) tmpAngle(1) = random(0, maxRotation) Else tmpAngle(0) = random(-maxRotation, 0) tmpAngle(1) = random(-maxRotation, 0) End If mPlane(i + 1) = Rhino.RotatePlane(Rhino.RotatePlane(Rhino.moveplane(mPlane(i), Rhino.PointAdd(mPlane(i)(0), Rhino.VectorScale(Rhino.VectorUnitize(mPlane(i)(3)), tempLen))), tmpAngle(0), mPlane(i)(1)), tmpAngle(1), mPlane(i)(2)) Next segmentedStem = mPlane End Function Function reparameterize(strObjectID) If Rhino.IsCurve(strObjectID) = True Then Call rhino.SelectObject(strObjectID) Call rhino.Command("reparameterize 0 1", False) Call rhino.UnselectAllObjects() End If If Rhino.IsSurface(strObjectID) = True Then Call rhino.SelectObject(strObjectID) Call rhino.Command("reparameterize 0 1 0 1", False) Call rhino.UnselectAllObjects() End If End Function Function random(min, max) random = Null Dim dblValue: dblValue = min + (max - min) * rnd() random = dblValue End Function