// Virus tentacular animado // Last edited on 2020-11-28 08:33:56 by jstolfi // Baseado no trabalho de ra217638 em MC937-2020-2. background{ color rgb < 0.75, 0.80, 0.85 > } #macro texture_plastic(rgbv) #local tx = texture{ pigment{ color rgb rgbv } finish{ diffuse 0.8 ambient 0.1 specular 0.5 roughness 0.005 } }; tx #end #macro texture_matte(rgbv) #local tx = texture{ pigment{ color rgb rgbv } finish{ diffuse 0.9 ambient 0.1 } }; tx #end #macro texture_virus(rgbv) #local tx = texture{ pigment{ color rgb rgbv } finish{ diffuse 0.9 ambient 0.1 } }; tx #end #include "interpolation.inc" #macro find_interval(tt, NQ,TQ) // Finds a {k0} such that {tt} is between {TT[k0]} and {TT[k0+1]}. // The array {TT} must have {NQ} elements in increasing order. #local k0 = 0; // Por via das duvidas. #local kq = 0; #while (kq < NQ-1) #if ((TQ[kq] <= tt) & (tt <= TQ[kq+1])) #local k0 = kq; #end #local kq = kq + 1; #end k0 #end #macro ranvec(rgen) // Random vector of {\RR^3} with unit length. #local len = 99; #while ((len < 0.1) | (len > 1.0)) #local vv = < 2*rand(rgen)-1, 2*rand(rgen)-1, 2*rand(rgen)-1 >; #local len = vlength(vv); #end (vv/len) #end #macro tentacle_segment(N, P0,P1,P2,P3, R0,R3, rgb0,rgb3) // {N} = Number of balls. // {P0,P1,P2,P3} = Bezier control point of tentacle axis. // {R0,R3} = initial and final radii. // {rgb0,rgb3} = initial and final RGB color tuples. union { #local i = 0; #while (i <= N) #local tt = i/N; #local P = interpolate3_bezier(tt,0,1,P0,P1,P2,P3); #local R = interpolate1(tt,0,1,R0,R3); #local rgbtt = interpolate1(tt,0,1,rgb0,rgb3); #local tx = texture_virus(rgbtt) sphere {P, R texture{ tx } } #local i = i+1; #end } #end #macro tentacle(N, A0,A1,A2,B1,B2,C1,C2,C3, RA0,RC3, rgbA0,rgbC3) #local A3 = (A2 + B1)/2; #local RA3 = interpolate1(1/3,0,1,RA0,RC3); #local rgbA3 = interpolate1(1/3,0,1,rgbA0,rgbC3); #local B0 = A3; #local RB0 = RA3; #local rgbB0 = rgbA3; #local B3 = (B2 + C1)/2; #local RB3 = interpolate1(2/3,0,1,RA0,RC3); #local rgbB3 = interpolate1(2/3,0,1,rgbA0,rgbC3); #local C0 = B3; #local RC0 = RB3; #local rgbC0 = rgbB3; object{ tentacle_segment(N, A0,A1,A2,A3, RA0,RA3, rgbA0,rgbA3) } object{ tentacle_segment(N, B0,B1,B2,B3, RB0,RB3, rgbB0,rgbB3) } object{ tentacle_segment(N, C0,C1,C2,C3, RC0,RC3, rgbC0,rgbC3) } #end #macro tentacle_hermite(N, tt,t0,t1, A0, A1H,A2H,B1H,B2H,C1H,C2H,C3H, RA0,RC3, rgbA0,rgbC3) union { #local A1 = interpolate3_hermite(tt, t0, t1, A1H[0], A1H[1], A1H[2], A1H[3]); #local A2 = interpolate3_hermite(tt, t0, t1, A2H[0], A2H[1], A2H[2], A2H[3]); #local B1 = interpolate3_hermite(tt, t0, t1, B1H[0], B1H[1], B1H[2], B1H[3]); #local B2 = interpolate3_hermite(tt, t0, t1, B2H[0], B2H[1], B2H[2], B2H[3]); #local C1 = interpolate3_hermite(tt, t0, t1, C1H[0], C1H[1], C1H[2], C1H[3]); #local C2 = interpolate3_hermite(tt, t0, t1, C2H[0], C2H[1], C2H[2], C2H[3]); #local C3 = interpolate3_hermite(tt, t0, t1, C3H[0], C3H[1], C3H[2], C3H[3]); tentacle(N, A0,A1,A2,B1,B2,C1,C2,C3, RA0,RC3, rgbA0,rgbC3) } #end #macro tentacle_anim(N,tt, A0,NQ,TQ, PA1,DA1, PA2,DA2, PB1,DB1, PB2,DB2, PC1,DC1, PC2,DC2, PC3,DC3, RA0,RC3, rgbA0,rgbC3) // Find key frame indices k0,k1 to interpolate and their times t0,t1: #local k0 = find_interval(tt, NQ, TQ); #local k1 = k0 + 1; #local t0 = TQ[k0]; #local t1 = TQ[k1]; // Get positions and velocities of control points in those two key frames: #local A1H = array[4]; #local A1H[0] = PA1[k0]; #local A1H[1] = DA1[k0]; #local A1H[2] = DA1[k1]; #local A1H[3] = PA1[k1]; #local A2H = array[4]; #local A2H[0] = PA2[k0]; #local A2H[1] = DA2[k0]; #local A2H[2] = DA2[k1]; #local A2H[3] = PA2[k1]; #local B1H = array[4]; #local B1H[0] = PB1[k0]; #local B1H[1] = DB1[k0]; #local B1H[2] = DB1[k1]; #local B1H[3] = PB1[k1]; #local B2H = array[4]; #local B2H[0] = PB2[k0]; #local B2H[1] = DB2[k0]; #local B2H[2] = DB2[k1]; #local B2H[3] = PB2[k1]; #local C1H = array[4]; #local C1H[0] = PC1[k0]; #local C1H[1] = DC1[k0]; #local C1H[2] = DC1[k1]; #local C1H[3] = PC1[k1]; #local C2H = array[4]; #local C2H[0] = PC2[k0]; #local C2H[1] = DC2[k0]; #local C2H[2] = DC2[k1]; #local C2H[3] = PC2[k1]; #local C3H = array[4]; #local C3H[0] = PC3[k0]; #local C3H[1] = DC3[k0]; #local C3H[2] = DC3[k1]; #local C3H[3] = PC3[k1]; // Generate the tentacle at the time {tt}: object{ tentacle_hermite(N, tt,t0,t1, A0, A1H,A2H,B1H,B2H,C1H,C2H,C3H, RA0,RC3, rgbA0,rgbC3) } #end #macro tentacle_random_anim(N,tt,it, A0,Z3, RA0,RC3, rgbA0,rgbC3r,rgbC3g) #local rgen = seed(4615 + 417*it); // Randon generator for this tentacle. #local NQ = 7; // Total key frames, including the final one (equal to the intial one). #local TQ = array[NQ]; // Clock values for key frames. // {rgbA0} = RGB color at base of tentacle. // {rgbC3r} = RGB color at tip of random tentacle. // {rgbC3g} = RGB color at tip of grasping tentacle. // rgbet the frame times equally spaced from 0.0000 to 1.0000: #local kq = 0; #while (kq < NQ) #local TQ[kq] = kq/(NQ-1); #local kq = kq + 1; // #end // Generate random positions and velocities for the Bezier control points in key frames: #local mP = 0.5*vlength(Z3 - A0); // Max point perturbation. #local mV = 4.0*vlength(Z3 - A0); // Max speed. #if (it = 7) // Grasping tentacle: #local PA1 = tentacle_grasping_key_bezier_point_positions(NQ,TQ, 1, A0,Z3, mP, rgen) #local PA2 = tentacle_grasping_key_bezier_point_positions(NQ,TQ, 2, A0,Z3, mP, rgen) #local PB1 = tentacle_grasping_key_bezier_point_positions(NQ,TQ, 4, A0,Z3, mP, rgen) #local PB2 = tentacle_grasping_key_bezier_point_positions(NQ,TQ, 5, A0,Z3, mP, rgen) #local PC1 = tentacle_grasping_key_bezier_point_positions(NQ,TQ, 7, A0,Z3, mP, rgen) #local PC2 = tentacle_grasping_key_bezier_point_positions(NQ,TQ, 8, A0,Z3, mP, rgen) #local PC3 = tentacle_grasping_key_bezier_point_positions(NQ,TQ, 9, A0,Z3, mP, rgen) // Blend colors #local rS = 0.5*(1 - cos(2*pi*tt)); #local sS = 1 - rS; #local rgbC3t = sS*rgbC3r + rS*rgbC3g; #else // Random moving tentacle: #local PA1 = tentacle_random_key_bezier_point_positions(NQ, 1, A0,Z3, mP, rgen) #local PA2 = tentacle_random_key_bezier_point_positions(NQ, 2, A0,Z3, mP, rgen) #local PB1 = tentacle_random_key_bezier_point_positions(NQ, 4, A0,Z3, mP, rgen) #local PB2 = tentacle_random_key_bezier_point_positions(NQ, 5, A0,Z3, mP, rgen) #local PC1 = tentacle_random_key_bezier_point_positions(NQ, 7, A0,Z3, mP, rgen) #local PC2 = tentacle_random_key_bezier_point_positions(NQ, 8, A0,Z3, mP, rgen) #local PC3 = tentacle_random_key_bezier_point_positions(NQ, 9, A0,Z3, mP, rgen) #local rgbC3t = rgbC3r; #end // Estimate velocities from positions: #local DA1 = estimate_velocities(NQ, PA1) #local DA2 = estimate_velocities(NQ, PA2) #local DB1 = estimate_velocities(NQ, PB1) #local DB2 = estimate_velocities(NQ, PB2) #local DC1 = estimate_velocities(NQ, PC1) #local DC2 = estimate_velocities(NQ, PC2) #local DC3 = estimate_velocities(NQ, PC3) object{ tentacle_anim( N,tt, A0, NQ,TQ, PA1,DA1, PA2,DA2, PB1,DB1, PB2,DB2, PC1,DC1, PC2,DC2, PC3,DC3, RA0,RC3, rgbA0,rgbC3t ) } #end #macro estimate_velocities(NQ, P) // Given an array {P} of positioons for {NQ} key frames, // estimates the velocities at those points. Assumes // equally spaced key frame clocks between 0 and 1 inclusive, // and values that are periodic possibly with a shift // (e.g. for turning angles). #local D = array[NQ]; #local S = P[NQ-1] - P[0]; // Shift of {P} per cycle. #local dt = 1/(NQ-1); // Clock interval between frames. #local kq = 0; #while (kq < NQ) #if (kq = 0) #local Pm = P[NQ-2] - S; #else #local Pm = P[kq-1]; #end #if (kq = NQ-1) #local Pp = P[1] + S; #else #local Pp = P[kq+1]; #end #local D[kq] = (Pp - Pm)/(2*dt); #local kq = kq + 1; #end D #end #include "tentacle_random.inc" #include "tentacle_grasping.inc" #macro tentacle_hermite_teste(tt) // Tests {tentacle_hermite}: just tip of tentacle moves in a "C"-like curve. #local N = 100; #local A0 = < 0, 0, 0 >; #local A1H = hermite_still(< 1, 0, 0 >); #local A2H = hermite_still(< 2, 0, 0 >); #local B1H = hermite_still(< 4, 0, 0 >); #local B2H = hermite_still(< 5, 0, 0 >); #local C1H = hermite_still(< 7, 0, 0 >); #local C2H = hermite_still(< 8, 0, 0 >); #local C3H = array[4]; #local C3H[0] = < 9, 0, -1 >; #local C3H[1] = < 0, +10, 0 >; #local C3H[2] = < 0, -10, 0 >; #local C3H[3] = < 9, 0, +1 >; #local RA0 = 0.2; #local RC3 = 0.02; object{ tentacle_hermite(N, tt,0,1, A0, A1H,A2H,B1H,B2H,C1H,C2H,C3H, RA0,RC3) } #end #macro hermite_still(P) // Hermite parameters for a constant function with value {P}. #local PH = array[4]; #local PH[0] = P; #local PH[1] = < 0, 0, 0 >; #local PH[2] = < 0, 0, 0 >; #local PH[3] = P; PH #end #include "eixos.inc" #macro virus_anim(tt, Rv) union{ object{ eixos(Rv, 0.05*Rv) } #local rgbA0 = < 0.750, 0.200, 0.980 >; #local rgbC3r = < 0.350, 0.350, 0.980 >; #local rgbC3g = < 1.000, 0.850, 0.050 >; // Blinking spike color: #local rgbS0 = < 1.000, 0.880, 0.350 >; #local rgbS1 = < 1.000, 0.200, 0.050 >; #local rS = 0.5*(1 + cos(6*pi*tt)); #local rS = rS*rS; #local rgbS = (1-rS)*rgbS0 + rS*rgbS1; // Virus body: #local tx0 = texture_virus(rgbA0) sphere{ <0, 0, 0>, Rv texture { tx0 } } #local it = 0; #local phi = (sqrt(5) - 1)/2; // Golden ratio. #local sa = -1; #while (sa < 2) #local sb = -1; #while (sb < 2) object{ virus_tentacle(tt, it, Rv, < sa*1, sb*phi, 0 >, rgbA0,rgbC3r,rgbC3g) } #local it = it + 1; object{ virus_tentacle(tt, it, Rv, < 0, sa*1, sb*phi >, rgbA0,rgbC3r,rgbC3g) } #local it = it + 1; object{ virus_tentacle(tt, it, Rv, < sb*phi, 0, sa*1 >, rgbA0,rgbC3r,rgbC3g) } #local it = it + 1; object{ virus_spike(tt, Rv, < sa, sb*(1+phi), 0 >, rgbS) } object{ virus_spike(tt, Rv, < 0, sa, sb*(1+phi) >, rgbS) } object{ virus_spike(tt, Rv, < sb*(1+phi), 0, sa >, rgbS) } #local sc = -1; #while (sc < 2) object{ virus_tentacle(tt, it, Rv, < sa, sb, sc >, rgbA0,rgbC3r,rgbC3g) } #local it = it + 1; #local sc = sc + 2; #end #local sb = sb + 2; #end #local sa = sa + 2; #end } #end #macro virus_tentacle(tt, it, Rv, dir, rgbA0,rgbC3r,rgbC3g) // Tentacle for virus of radius {Rv} starting in the direction of vector {dir}. #local dir1 = dir/vlength(dir); #local A0 = Rv * dir1; #local C3 = 3.5 * Rv * dir1; #local RA0 = 0.07*Rv; #local RC3 = 0.03*Rv; object{ tentacle_random_anim(150, tt, it, A0,C3, RA0,RC3, rgbA0,rgbC3r,rgbC3g) } #end #macro virus_spike(tt, Rv, dir, rgbS) // Spike for virus of radius {Rv} starting in the direction of vector {dir}. #local dir1 = dir/vlength(dir); #local PS = Rv * dir1; #local RS = 0.14*Rv; #local txS = texture_virus(rgbS) sphere{ PS, RS texture{ txS } } #end object{ virus_anim(clock, 5.0) } #include "camlight.inc" #declare centro_cena = < 0.00, 0.00, -5.00 >; #declare raio_cena = 42.0; #declare dir_camera = < 1.00, 1.00, 1.00 > + 0.5*< cos(2*pi*clock), sin(2*pi*clock),0 >; #declare dist_camera = (5 - cos(2*pi*clock))*raio_cena; #declare intens_luz = 1.20; camlight(centro_cena, raio_cena, dir_camera, dist_camera , z, intens_luz)