// Persistence of Vision Ray Tracer Scene Description File
// File: Bezier.inc
// Vers: 3.1
// Desc: Bezier Spline Macro Include File
// Date: 11-11-99 First made into .inc file
// 11-15-99 Started the smooth triangle connection bewtween two splines
// 11-15-99 Started the Radius Change feature
// 11-17-99 Managed to fix problems with ConnectSmooth, so all the
// Triangles should show up now
// 12-28-99 Made DrawStrand Macro
// 01-17-00 Made ConnectStrandToSpline Macro
// 01-19-00 Deleted ConnectStrandToSpline Macro due to memory issues
// 02-11-00 Added MoveSpline, ReverseSpline, RotateSpline, and ScaleSpline
// Auth: Josh English
#declare HelloBezier = true;
// Set Defaults
#declare ShowTangents = false;
#declare FullCurve = true;
#declare NumberofPoints = 20;
#declare AccelerationDegree = 1;
#declare BezTex = texture { pigment { red 1 } finish { phong 1 } }
#declare BezRad = 0.1;
#declare BezThing = sphere { <0,0,0> BezRad texture { BezTex } }
#declare NoShadow = true;
#declare CapSpline = false;
// Autopoint takes a point and it's contol, and creates a new control point
// in the opposite direction, the lenght is scaled by a factor of d
#macro Autopoint(a,b,d)
#local newpoint = a - d*(b - a);
newpoint;
#end
// Square creates two triangles that connect four points
#macro Square(A,B,C,D)
union {
triangle { A, B, C }
triangle { D, C, A } texture { BezTex } }
#end
// CheckDefaults will fill out anything not specified by the user
#macro CheckDefaults()
#ifndef (ShowTangents)
#declare ShowTangents = false;
#end
#ifndef (FullCurve)
#declare FullCurve = false;
#end
#ifndef (NumberofPoints)
#declare NumberofPoints = 20;
#end
#ifndef (AccelerationDegree)
#declare AccelerationDegree = 1;
#end
#ifndef (BezTex)
#declare BezTex = texture { pigment { red 1 } finish { phong 1 } }
#end
#ifndef (BezRad)
#declare BezRad = 0.1;
#end
#ifndef (BezThing)
#declare BezThing = sphere { <0,0,0> BezRad texture { BezTex } }
#end
#ifndef (NoShadow) #declare NoShadow = true; #end
#end
// Also need a method of taking a spline and a normalized number and return
// a place on the spline
#macro ReturnPosition(id,num)
// CheckDefaults()
#local d = pow(num,AccelerationDegree);
#local m = 1 - d;
#local this = id[0]*pow(m,3) +
id[1]*d*3*pow(m,2) +
id[2]*3*pow(d,2)*m +
id[3]*pow(d,3);
this
#end
// DrawSpline takes an array identifier and
#macro DrawSpline(id)
#declare BezThing = sphere { <0,0,0> BezRad texture { BezTex } }
#local c = 0;
#while ( c < 1 )
#local temp = ReturnPosition(id,c);
// Find the Next Point on the spline
#local next = ReturnPosition(id,(c+1/NumberofPoints));
#if (FullCurve)
#if ( c < 1 ) cylinder { temp, next BezRad texture { BezTex }
#if(NoShadow) no_shadow #end } #end
#end
// Find the proper transformation for the thing
#local nx = vnormalize(next - temp);
#local nz = vnormalize(vcross(nx,y));
#local ny = vcross(nz,nx);
#local nz = vnormalize(vcross(nx,ny));
object{ BezThing
#if(NoShadow) no_shadow #end
matrix <nx.x,nx.y,nx.z,ny.x,ny.y,ny.z,nz.x,nz.y,nz.z,temp.x,temp.y,temp.z>
texture { BezTex }}
#declare c = c + (1/NumberofPoints);
#end
#if (ShowTangents)
cylinder { id[0],id[1] BezRad*0.75 pigment { rgb 1 } no_shadow}
cylinder { id[2],id[3] BezRad*0.75 pigment { rgb 1 } no_shadow}
#end
#if (CapSpline)
object { BezThing texture { BezTex } translate id[3] }
#end
#end
// DrawPartialSpline takes an array identifier and
#macro DrawPartialSpline(id,lim)
CheckDefaults()
#local c = 0;
#while ( c < lim )
#local temp = ReturnPosition(id,c);
// Find the Next Point on the spline
#local next = ReturnPosition(id,(c+1/NumberofPoints));
#if (FullCurve)
#if ( c < 1 ) cylinder { temp, next BezRad texture { BezTex }
#if(NoShadow) no_shadow #end } #end
#end
// Find the proper transformation for the thing
// Thing should be oriented towards +x
#local nx = vnormalize(next - temp);
#local nz = vnormalize(vcross(nx,y));
#local ny = vcross(nz,nx);
#local nz = vnormalize(vcross(nx,ny));
object{ BezThing
#if(NoShadow) no_shadow #end
matrix <nx.x,nx.y,nx.z,ny.x,ny.y,ny.z,nz.x,nz.y,nz.z,temp.x,temp.y,temp.z> }
#declare c = c + (1/NumberofPoints);
#end
#if (ShowTangents)
cylinder { id[0],id[1] BezRad*0.75 pigment { rgb 1 } no_shadow}
cylinder { id[2],id[3] BezRad*0.75 pigment { rgb 1 } no_shadow}
#end
#end
// SplineLength returns a rough estimate of the length of the spline
#macro SplineLength(id)
#local c = 0;
#declare len = 0;
#while ( c < 1 )
#local temp = ReturnPosition(id,c);
#local next = ReturnPosition(id,(c + 0.05));
#declare len = len + vlength(next-temp);
#declare c = c + 0.05;
#end
len
#end
// BridgeSpline takes an array identifier and
#macro BridgeSplines(id1,id2)
CheckDefaults()
#local c = 0;
#while ( c < 1 )
#local t1 = ReturnPosition(id1,c);
#local t2 = ReturnPosition(id2,c);
// Find the Next Point on the spline
#local n1 = ReturnPosition(id1,(c+1/NumberofPoints));
#local n2 = ReturnPosition(id2,(c+1/NumberofPoints));
#if (FullCurve)
#if ( (c+1/NumberofPoints) < 1 )
cylinder { t1, n1 BezRad texture { BezTex } #if(NoShadow) no_shadow #end }
cylinder { t2, n2 BezRad texture { BezTex } #if(NoShadow) no_shadow #end }
#end
#end
// Find the proper transformation for the thing
#local nx = vnormalize(next - temp);
#local nz = vnormalize(vcross(nx,y));
#local ny = vcross(nz,nx);
object{ BezThing
#if(NoShadow) no_shadow #end
matrix <nx.x,nx.y,nx.z,ny.x,ny.y,ny.z,nz.x,nz.y,nz.z,temp.x,temp.y,temp.z> }
cylinder ( t1,t2 BezRad*0.75 texture { BezTex ) no_shadow }
#declare c = c + (1/NumberofPoints);
#end
#if (ShowTangents)
cylinder { id[0],id[1] BezRad pigment { rgb 1 } no_shadow}
cylinder { id[2],id[3] BezRad pigment { rgb 1 } no_shadow}
#end
#end
#macro Connect(SP,SR,EP,ER)
#local D=vlength(EP-SP);
#local Rd=SR-ER;
#local D2=sqrt(abs(D*D-Rd*Rd));
cone { SP+(EP-SP)/D*Rd*(SR)/D,(SR)*D2/D,EP+(EP-SP)/D*Rd*(ER)/D,(ER)*D2/D }
#end
// DrawTail deals with a start radius and an end radius
#macro DrawTail(id)
CheckDefaults()
#ifndef (StartRadius) #declare StartRadius = 1; #end
#ifndef (EndRadius) #declare EndRadius = 0.1; #end
#local c = 0;
#while ( c < 1 )
#local temp = ReturnPosition(id,c);
#local t_rad = StartRadius + (c * (EndRadius - StartRadius));
// Find the Next Point on the spline
#local next = ReturnPosition(id,(c+1/NumberofPoints));
#local n_rad = StartRadius + ((c+1/NumberofPoints) * (EndRadius - StartRadius));
#if (FullCurve)
#if ( (c+1/NumberofPoints) < 1 )
object { Connect(temp,t_rad,next,n_rad)
texture { BezTex } }
#end
#end
// Find the proper transformation for the thing
#local nx = vnormalize(next - temp);
#local nz = vnormalize(vcross(nx,y));
#local ny = vcross(nz,nx);
sphere { 0,1
scale t_rad
texture { BezTex }
matrix <nx.x,nx.y,nx.z,ny.x,ny.y,ny.z,nz.x,nz.y,nz.z,temp.x,temp.y,temp.z> }
#declare c = c + (1/NumberofPoints);
#end
#if (ShowTangents)
cylinder { id[0],id[1] BezRad pigment { rgb 1 } no_shadow}
cylinder { id[2],id[3] BezRad pigment { rgb 1 } no_shadow}
#end
#end
// Need a way to automatically crate a new spline from an old one with
// a smooth connection
// new[0] = old[3]
// new[1] = autopoint(old[3],old[2],1)
// new[2] and new[3] are customizable
// Method for connecting two splines with triangles, kind of a bicubic patch
// Thing without the control points
#macro ConnectSplines(id1,id2)
CheckDefaults()
mesh {
#local c = 0;
#while ( c < 1 )
#local p1 = ReturnPosition(id1,c);
#local p2 = ReturnPosition(id1,(c+1/NumberofPoints));
#local p3 = ReturnPosition(id2,c);
#local p4 = ReturnPosition(id2,(c+1/NumberofPoints));
//Square (p1,p2,p4,p3)
triangle { p1,p2,p3 }
triangle { p2,p4,p3 }
#declare c = c + (1/NumberofPoints);
#end
texture { BezTex }
} // end mesh
#end
//#include "MyMacs.inc"
#macro ConnectSmooth(id1,id2)
CheckDefaults()
mesh {
#local c = 0;
#while (c < 1)
// Get Positions for First Spline
#local ac = ReturnPosition(id1,c);
#local an = ReturnPosition(id1,(c+(1/NumberofPoints)));
#local aq = ReturnPosition(id1,(c+(2/NumberofPoints)));
#local ap = ReturnPosition(id1,(c-(1/NumberofPoints)));
// Get Position for Second Spline
#local bc = ReturnPosition(id2,c);
#local bn = ReturnPosition(id2,(c+(1/NumberofPoints)));
#local bq = ReturnPosition(id2,(c+(2/NumberofPoints)));
#local bp = ReturnPosition(id2,(c-(1/NumberofPoints)));
// Find six normals
#declare n1 = vnormalize(vcross((bc-bp),(ap-bp)));
#declare n2 = vnormalize(vcross((bn-bc),(ac-bc)));
#declare n3 = vnormalize(vcross((ac-an),(bn-an)));
#declare n4 = vnormalize(vcross((ac-an),(bn-an)));
#declare n5 = vnormalize(vcross((bq-bn),(an-bn)));
#declare n6 = vnormalize(vcross((an-aq),(bq-aq)));
// Now find the four local normals that are the average of three
// triangle normals each
#declare acn = vnormalize((n2 + n3 + n4)/3);
#declare ann = vnormalize((n4 + n5 + n6)/3);
#declare bcn = vnormalize((n1 + n2 + n3)/3);
#declare bnn = vnormalize((n3 + n4 + n5)/3);
// Draw the two smooth triangles
smooth_triangle { ac acn bc bcn bn bnn }
smooth_triangle { ac acn an ann bn bnn }
#declare c = c + (1/NumberofPoints);
#end
texture { BezTex }
}
#end
#macro CheckStrandDefaults()
#ifndef (NumberCorrection) #declare NumberCorrection = 2; #end
#ifndef (NoRotations) #declare NoRotations = 1; #end
#ifndef (OutRadius) #declare OutRadius = 0.5; #end
#ifndef (RotationOffset) #declare RotationOffset = 0; #end
#ifndef (RadMin) #declare RadMin = 0; #end
#ifndef (RadMax) #declare RadMax = 1; #end
#ifndef (RadialMethod) #declare RadialMethod = 0; #end
#end
// Drawstrand
#macro DrawStrand(id)
CheckDefaults()
CheckStrandDefaults()
#declare NumberofPoints = int(NumberofPoints * NumberCorrection);
#local c = 0;
#while ( c < 1 )
#local c1 = c + 1/NumberofPoints;
// Find the Current Point and the Next Point
#local temp = ReturnPosition(id,c);
#local next = ReturnPosition(id,c1);
// Find the rotation around the spline of the current and next points
#local currentRotation = (360*c*NoRotations) + RotationOffset;
#local nextRotation = (360*c1*NoRotations) + RotationOffset;
// Find the current radius and next radius based on the Method
#switch(RadialMethod)
#case(1) // Linear Method
#local RadRange = RadMax - RadMin;
#local currentRadius = RadMin + (c*RadRange);
#local nextRadius = RadMin + (c1*RadRange);
#break;
#case(2) // Sine Method
#local RadRange = RadMax - RadMin;
#local currentRadius = ( sin(c * pi)*RadRange) + RadMin;
#local nextRadius = ( sin(c1 * pi)*RadRange) + RadMin;
#break;
#else // constant method
#local currentRadius = OutRadius;
#local nextRadius = OutRadius;
#end
#local FirstPos = vrotate(<0,0,currentRadius>,<currentRotation,0,0>);
#local SecondPos = vrotate(<vlength(next-temp),0,nextRadius>,<nextRotation,0,0>);
// Find the proper transformation for the thing
#local nx = vnormalize(next - temp);
#local nz = vnormalize(vcross(nx,y));
#local ny = vcross(nz,nx);
object{ merge { sphere { FirstPos, BezRad }
cylinder { FirstPos, SecondPos, BezRad }
texture { BezTex } }
#if(NoShadow) no_shadow #end
matrix <nx.x,nx.y,nx.z,ny.x,ny.y,ny.z,nz.x,nz.y,nz.z,temp.x,temp.y,temp.z> }
#declare c = c1;
#end
#end
// Added 2-11-2000
#macro MoveSpline(Spl,vct)
array [4] {
Spl[0] + vct,
Spl[1] + vct,
Spl[2] + vct,
Spl[3] + vct }
#end
#macro ReverseSpline(Spl)
array [4] { Spl[3] Spl[2] Spl[1] Spl[0] }
#end
#macro RotateSpline (Spl,vct)
array [4] {
vrotate(Spl[0],vct),
vrotate(Spl[1],vct),
vrotate(Spl[2],vct),
vrotate(Spl[3],vct) }
#end
#macro ScaleSpline(Spl,vct)
array [4] {
Spl[0]*vct,
Spl[1]*vct,
Spl[2]*vct,
Spl[3]*vct }
#end
// 2-14-2000
#macro BezPatch(S1,C1,C2,S2)
#declare cnt = 0;
#declare stp = 0.05;
#declare NumberofPoints = 20;
#while(cnt < 1 )
#local nxt = cnt + 1/NumberofPoints;
#local t0 = ReturnPosition(S1,cnt);
#local t1 = ReturnPosition(C1,cnt);
#local t2 = ReturnPosition(C2,cnt);
#local t3 = ReturnPosition(S2,cnt);
#local n0 = ReturnPosition(S1,nxt);
#local n1 = ReturnPosition(C1,nxt);
#local n2 = ReturnPosition(C2,nxt);
#local n3 = ReturnPosition(S2,nxt);
#declare Temp = array [4] { t0, t1, t2, t3 }
#declare Next = array [4] { n0, n1, n2, n3 }
ConnectSmooth(Temp,Next)
#declare cnt = nxt;
#end
#end
#macro BezFrame(S1,C1,C2,S2)
#local tempCurve = FullCurve;
#local FullCurve = true;
DrawSpline(S1)
// DrawSpline(C1)
// DrawSpline(C2)
DrawSpline(S2)
#declare cnt = 0;
#declare stp = 0.05;
#while(cnt <= 1 )
#local nxt = cnt + 0.333;
#local t0 = ReturnPosition(S1,cnt);
#local t1 = ReturnPosition(C1,cnt);
#local t2 = ReturnPosition(C2,cnt);
#local t3 = ReturnPosition(S2,cnt);
#declare Temp = array [4] { t0, t1, t2, t3 }
DrawSpline(Temp)
#declare cnt = nxt;
#end
#local FullCurve = tempCurve;
#end
// 02-21-2000
#macro BezPatch2(S1,C1,C2,S2)
bicubic_patch { type 1
flatness 0.1
u_steps 3 // # of triangles to subdivide (1-5)
v_steps 3 // # of triangles to subdivide (1-5)
ReturnPosition(S1,0) ReturnPosition(S1,0.333) ReturnPosition(S1,0.6667) ReturnPosition(S1,1)
ReturnPosition(C1,0) ReturnPosition(C1,0.333) ReturnPosition(C1,0.6667) ReturnPosition(C1,1)
ReturnPosition(C2,0) ReturnPosition(C2,0.333) ReturnPosition(C2,0.6667) ReturnPosition(C2,1)
ReturnPosition(S2,0) ReturnPosition(S2,0.333) ReturnPosition(S2,0.6667) ReturnPosition(S2,1)
texture { BezTex }
}
#end