Content-Transfer-Encoding: 8Bit Content-Disposition: attachment; filename="looping_clean.pov" #version unofficial Megapov 0.7 #include "colors.inc" #declare cr=1 #declare surface= union{ cylinder{<0,cr,-.5>,<0,cr,.5>,cr open hollow clipped_by{ box{<0,-1,0>,<2,cr,2> inverse} box{<0,-1,0>,<-2,cr,-2> inverse} box{<-2,cr,0>,<2,5,1> rotate y*14.036 translate <0,0,0.25> inverse} box{<-2,cr,0>,<2,5,-1> rotate y*14.036 translate <0,0,-0.25> inverse} } pigment{White} } plane{y,0 } pigment{Green} } camera{ location <2,1,-4> look_at <0,.8,0> angle 45 } light_source{<30,100,-40> color White} light_source{<2,.3,-1> color White} #declare slider_r=0.25; #declare slider_=sphere{0,slider_r translate <0,slider_r,0> pigment{Red}} #declare slider=cylinder{0,<0,0.5,0>,0.2 scale .4} #macro vec_out(vect) #debug "<" #debug str(vect.x,7,7) #debug "," #debug str(vect.y,7,7) #debug "," #debug str(vect.z,7,7) #debug ">\n" #end #declare Epsilon=.05; /////////////////////////////////////////// #macro calculate_move_on_surface(TouchPoint,N,Vel,dt) /* we should check first if the force is limited by the surface ! */ /* but we do not yet - I guess it is not neccessary any more */ /* project the Force <0,-g,0> into the plane and calc acceleration */ #local a=g*; /* calc new velocity */ #local vel=Vel+a*dt; #local P_new=TouchPoint+vel*dt; /* look for a point on the surface near the new location */ #local NormalRaw=<0,0,0>; #declare TouchPoint_New=trace(surface,P_new+Epsilon*N,-N,NormalRaw); #local tracelength=vlength(P_new+Epsilon*N-TouchPoint_New); /* check if the normal vector is pointing the wrong way do you know a better way to do this ? */ #if (vlength(N-NormalRaw)>1.41) #local NormalRaw=-NormalRaw; #end /* check if there was an intersection at all */ #if ( ((TouchPoint_New.x=0)&(TouchPoint_New.y=0)&(TouchPoint_New.z=0)& (NormalRaw.x=0)&(NormalRaw.y=0)&(NormalRaw.z=0)) | (tracelength>2*Epsilon) ) #debug "no intersection !" #declare TouchSurface_New=0; #declare TouchPoint_New=P_new; #declare Vel_New=vel; #declare az_New=0; #else /* calculate centrifugal force */ #if (vlength(vel)>0) #local Fzentr=pow(vlength(vel),2)*2* sqrt( (1-vdot(N,NormalRaw))/2 ) / vlength(TouchPoint_New-TouchPoint); #else #local Fzentr=0; #end #if (tracelength-)+N*Fzentr; /* correct velocity according to friction - well it is an unusual thing to do this here after the slider has already moved, but I need the old and new normal vector for this */ #declare dv=f_slide*vlength(Fn)/m*dt; #if (dv>vlength(vel)) #declare vel=<0,0,0>; #else #declare vel=vel*(vlength(vel)-dv)/vlength(vel); #end /* check if the normal force points away from the surface and the objects leaves it */ /* the commented out works always but can give many warnings; I need to do the check differently */ // #if (((N.x=0)|(Fn.x/N.x>0))&((N.y=0)|(Fn.y/N.y>0))&((N.z=0)|(Fn.z/N.z>0))) #if (N.y!=0) #if (Fn.y/N.y>0) vec_out(Fn) vec_out(N) #debug "leaving the surface!" #declare TouchSurface_New=0; #else #declare TouchSurface_New=1; #end #else #declare TouchSurface_New=1; #end /* #debug "Normale: " vec_out(NormalRaw)*/ // #debug " Fzentr: " // vec_out(Fn) /* #debug str(Fzentr,7,7) #debug "\nv: "*/ // vec_out(vel) /* #debug str(vlength(vel),15,15) #debug "\n"*/ /* #debug "dN/2: " #debug str(acos(vdot(N,NormalRaw)/vlength(N)/vlength(NormalRaw))/2,5,5)*/ /* we need to project the velocity into the normal plane in point N otherwise the object will move through the surface */ #declare N_New=NormalRaw; #local vel_new= ; #if (vlength(vel)=0) #declare Vel_New=<0,0,0>; #else #declare Vel_New=vel_new/vlength(vel_new)*vlength(vel); #end #end #end ///////// /* once it has left the surface the slider just does a free fall */ #macro calculate_move_off_surface(Place,Vel,dt) #local a=g*<0,-1,0>; #declare Vel_New=Vel+a*dt; #declare TouchPoint_New=Place+Vel_New*dt; #declare TouchSurface_New=0; #end //////////// #macro calculate_move(TouchPoint,N,Vel,dt) #if (TouchSurface=1) calculate_move_on_surface(TouchPoint,N,Vel,dt) #else calculate_move_off_surface(TouchPoint,Vel,dt) #end #end /////////////////////////// /* macro for placing the slider */ #macro position_at(objpos,location_to,Norm) #if ((Norm.x=0)&(Norm.z=0)) #declare ROT1=0; #declare ROT2=0; #declare ROT3=0; #else #if (Norm.y>0) #declare ROT1=y*atan2(Norm.z,Norm.x)/pi*180; #else #declare ROT1=-y*atan2(Norm.z,Norm.x)/pi*180; #end #declare ROT2=-z*atan2(sqrt(Norm.z*Norm.z+Norm.x*Norm.x),Norm.y)/pi*180; #declare ROT3= -y*atan2(Norm.z,Norm.x)/pi*180; #end object{objpos rotate ROT1 rotate ROT2 rotate ROT3 translate location_to } #end //////////////////////////// /* following macro is out of date, I just use it sometimes to place the object initially - not needed in the looping example */ #macro calc_move() #declare NormalRaw=<0,0,0>; #declare intersec=trace(surface,loc+<0,1,0>,<0,-1,0>,NormalRaw); #if ((intersec.x=0)&(intersec.y=0)&(intersec.z=0)& (NormalRaw.x=0)) #debug "kein Schnitt!!!" #end #declare N=vnormalize(NormalRaw); /* we need to project the velocity into the normal plane in point N otherwize the object will move through the surface we *should* not do that if the object moves away from the surface anyway */ #declare vel_new= ; #declare vel=vel_new/*/vlength(vel_new)*vlength(vel)*/; #declare a=g**dt/m; #declare vel=vel+a*dt; #declare loc=intersec+vel*dt; #declare time=time+dt; #end /////////////// /* gravity: */ #declare g=1; /* mass: */ #declare m=1; /* time steps - the lower the more accurate the moving */ #declare dt=0.01/2; /* friction coefficient */ #declare f_slide=0.2; #declare TouchSurface=1; /* initial velocity */ #declare vel=<-1,0,-1/12>*3.35; /* initial position */ #declare loc=<2,0,1/2>-vel/vel.x /* initial normal */ #declare N=<0,1,0> /* initial time */ #declare time=0; #declare az=0; #while (time*2.6; #declare loc=<2,0,1/2>-vel/vel.x #declare N=<0,1,0> #declare time=0; #declare az=0; #while (time*0.8; #declare loc=<2,0,1/2>-vel/vel.x #declare N=<0,1,0> #declare time=0; #declare az=0; #while (time*1.5 ; #declare loc=<2,0,1/2>-vel/vel.x #declare N=<0,1,0> #declare time=0; #declare az=0; #while (time