Hair From Points

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. 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 arrPts, arrInputs 
	arrPts = Rhino.GetObjects("Select Points", 1) 
	If isNull(arrPts) Then Exit Sub 
	arrInputs = Rhino.PropertyListBox(array("Min Length", "Max Length", "Min Hair Bend", "Max Hair Bend", "Base Radius", "Tip Radius", "Segments", "Sides"), array(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 
	ReDim stem(uBound(arrPts)), blades(uBound(arrPts)) 
	Call Rhino.EnableRedraw(False) 
	For i = 0 To uBound(arrPts) Step 1 
		stem(i) = segmentedStem(Rhino.PointCoordinates(arrPts(i)), random(CDbl(arrInputs(0)), CDbl(arrInputs(1))), CInt(arrInputs(6)), random(CDbl(arrInputs(2)), CDbl(arrInputs(3)))) blades(i) = bladesFlat(stem(i), CDbl(arrInputs(4)), CDbl(arrInputs(5)), sides) 
	Next 
	Call Rhino.EnableRedraw(True) 
End Sub 
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(arrPoint, 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.MovePlane(Rhino.RotatePlane(Rhino.WorldXYPlane(), random(0, 360), Rhino.WorldXYPlane()(3)), arrPoint) 
	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 random(min, max) 
	random = Null 
	Dim dblValue: dblValue = min + (max - min) * rnd() 
	random = dblValue 
End Function