#include "colors.inc" #include "macros2.inc" #include "glass.inc" #include "metals.inc" // FacetTwist(r1,r2,r3,r4,thick,freq,ures,uoff,vres,voff,woff): // r1 = major radius // r2 = minor radius (center of torus to center of coil) // r3 = coil radius // r4 = radius of wire mesh // thick = thickness of glass panes // freq = frequency of coil // ures = number of facets about coil // uoff = offset of facets about coil (0-1) // vres = number of facets along coil, per period // voff = offset of facets along coil (0-1) // woff = rotation of entire coil about y axis, in periods // Defines: // FacetTwistWire // FacetTwistPanel #macro FacetTwist(r1,r2,r3,r4,thick,freq,ures,uoff,vres,voff,woff) #local steps = freq*vres; #local ustep = (2*pi)/vres; #local vstep = (2*pi)/steps; #local urot = ustep*voff; #local vrot = -2*pi*woff/freq; #local path = array[steps+1] #local vert = array[steps+1][ures] // ------------------------------------------------------------------------------------ // Here we calculate the central points, defining a path that goes directly through the // center of the coil // ------------------------------------------------------------------------------------ #local ctr = 0; #while (ctr < steps) #local path[ctr] = ; #local urot = urot + ustep; // urot is the rotation about the torus #local vrot = vrot + vstep; // vrot is the rotation along the torus #local ctr = ctr + 1; #end #local path[steps] = path[0]; // the end point is the starting point // ------------------------------------------------------------------------------------ // Here we calculate the vertices around the starting point as a reference // ------------------------------------------------------------------------------------ #local vec1 = path[1]-path[0]; #local vec2 = path[steps-1]-path[0]; // this vector will bisect the angle formed by the two vectors forming the joint: #local bisec = vec1+(vec2-vec1)*(vlength(vec1)/(vlength(vec1)+vlength(vec2))); // and this vector will be perpendicular to the plane that bisects said angle, // so we can use it as an axis of rotation: #local joint = vcross(vcross(vec1,vec2),bisec); // our reference point for creating the vertices: #local start = r3*vnormalize(vcross(vec1,vec2)); #local ctr = 0; #while (ctr < ures) #local vert[0][ctr] = vaxis_rotate(start,joint,(360/ures)*(ctr+voff)); // rotate the point along the axis of rotation #local vert[0][ctr] = vert[0][ctr] * 1/cos(pi/2-vangle(vert[0][ctr],vec1)); // and scale it according to its angle from the joint #local vert[0][ctr] = vert[0][ctr] + path[0]; // finally translate it from the origin to the point it helps encircle #local ctr = ctr + 1; #end // ------------------------------------------------------------------------------------ // Here we calculate the vertices around all other points // ------------------------------------------------------------------------------------ #local ctr = 1; #while (ctr < steps+1) #render concat("Generating wiremesh: ",str(ctr,-5,0),"/",str(steps,-5,0),"\r") #local vec1 = path[mod(ctr+1,steps)] - path[ctr]; #local vec2 = path[ctr-1] - path[ctr]; // this vector will bisect the angle formed by the two vectors forming the joint: #local bisec = vec1+(vec2-vec1)*(vlength(vec1)/(vlength(vec1)+vlength(vec2))); // and this vector will be perpendicular to the plane that bisects said angle: #local joint = vcross(vcross(vec1,vec2),bisec); // and these are the coefficients for said plane (Ax+By+Cz=D): #local _A = joint.x; #local _B = joint.y; #local _C = joint.z; #local _D = _A*path[ctr].x + _B*path[ctr].y + _C*path[ctr].z; #local ctr2 = 0; #while (ctr2 < ures) // Now we will extend a line which passes through a vertex of the previous // step along the coil and is parallel to the path of the coil from the // previous segement to the current segment, finding where it intersects the // bisection plane: #local _S = vert[ctr-1][ctr2]; // this is said previous vertex #local _t = (_D - _A*_S.x - _B*_S.y - _C*_S.z)/ (_A*(vec1.x) + _B*(vec1.y) + _C*(vec1.z)); // Here is where we solve the intersection // // Equation of a plane: Ax + By + Cz = D // // Equation of a line: x = x1 + (x2 - x1)t ( and are // y = y1 + (y2 - y1)t points on the line, t gets all // z = z1 + (z2 - z1)t real numbers) // // Solve for t to find the intersection: (D - Ax1 - By1 - Cz1) // t = ------------------------------------ // A(x2 - x1) + B(y2 - y1) + C(z2 - z1) // // Insert value for t into equation for line to get point of intersection #local vert[ctr][ctr2] = <_S.x-vec2.x*_t, _S.y-vec2.y*_t, _S.z-vec2.z*_t>; #local ctr2 = ctr2 + 1; #end #local ctr = ctr + 1; #end #render "\n" // ------------------------------------------------------------------------------------ // Here we connect the first and last segments of the coil // ------------------------------------------------------------------------------------ #local Len = array[ures] #local BestMatch = 0; #local ctr = 0; #while (ctr < ures) // Find the closest vertex among the starting vertices to the // calculated end vertex, we will snap the ending vertices to // the starting vertices. This creates one noncoplanar segment, // but you can hide it somewhere ;) #local Len[ctr] = vlength(vert[0][ctr]-vert[steps][0]); #if (Len[ctr] < Len[BestMatch]) #local BestMatch = ctr; #end #local ctr = ctr + 1; #end #local ctr = 0; #while (ctr < ures) #local vert[steps][ctr] = vert[0][mod(ctr+BestMatch,ures)]; #local ctr = ctr + 1; #end // ------------------------------------------------------------------------------------ // Here we define the wiremesh. Fairly simple. // ------------------------------------------------------------------------------------ #declare FacetTwistWire = union { #local ctr = 0; // steps along coil #while (ctr < steps) #local ctr2 = 0; #while (ctr2 < ures) // steps about coil cylinder { vert[ctr][ctr2],vert[ctr][mod(ctr2+1,ures)],r4 } cylinder { vert[ctr][ctr2],vert[ctr+1][ctr2],r4 } sphere { vert[ctr][ctr2],r4 } #local ctr2 = ctr2 + 1; #end #local ctr = ctr + 1; #end } // ------------------------------------------------------------------------------------ // Here we generate the paneling, a slow process of realignment // ------------------------------------------------------------------------------------ #declare FacetTwistPanel = union { #local ctr = 0; #while (ctr < steps) #local ctr2 = 0; #while (ctr2 < ures) #render concat("Generating panels: ",str(ctr*ures+ctr2+1,-6,0),"/", str(steps*ures,-6,0),"\r") // corners of quadrilateral after being translated to the origin: #local p1 = vert[ctr][mod(ctr2+1,ures)] - vert[ctr][ctr2]; #local p2 = vert[ctr+1][mod(ctr2+1,ures)] - vert[ctr][ctr2]; #local p3 = vert[ctr+1][ctr2] - vert[ctr][ctr2]; // realign the first corner so it lies on z: #local ax1 = p1; #local p1 = reposition2v(p1,ax1,z); #local p2 = reposition2v(p2,ax1,z); #local p3 = reposition2v(p3,ax1,z); // realign the other corners so the quadrilateral is coplanar with x-z: #local ax2 = p1; #local norm = vcross(p1,p3); // normal of quadrilateral #local perp = vcross(p1,norm); // vector perpendicular to normal and first edge #local hz = perp*<1,0,1>; // horizontal component of (perp) #local ang = vangle(perp,hz)*180/pi; // angle between (perp) and horizontal #local rot = 0; #while (ang > 0) // we loop in case the quadrilateral must be rotated >90 #local rot = rot + ang; // count the rotation so it can be undone #local p2 = vrotate(p2,ang*z); // rotate the corners #local p3 = vrotate(p3,ang*z); #local perp = vrotate(perp,ang*z); #local hz = perp*<1,0,1>; #local ang = vangle(perp,hz)*180/pi; // recalculate angle to horizontal #end prism { -thick/2,thick/2,5 <0,0>,,,,<0,0> rotate -rot*z reposition2(z,ax1) translate vert[ctr][ctr2] } #local ctr2 = ctr2 + 1; #end #local ctr = ctr + 1; #end } #render "\n" #end FacetTwist(2,.7,.5,.03,.04,7,6,0,10,0,0) object { FacetTwistWire pigment { color Gray90 } }// texture { T_Copper_5B } } object { FacetTwistPanel pigment { color Gray60 } }// texture { T_Ruby_Glass } interior { I_Glass } normal { wrinkles .1 scale .5 } } plane { y,-1.23 texture { checker texture { pigment { color Gray90 } finish { reflection .2 } } texture { pigment { color Gray20 } finish { reflection .5 } } } } global_settings { max_trace_level 10 } camera { location <0,3.7,-4.5> look_at <0,-.3,-.5> } light_source { <200,200,-250> White*1.4 } light_source { <-200,150,-200> White*.7 } light_source { <20,200,200> White*.8 }