//A POV-Ray script illustrating an algorithm //to find the location of the camera giving the //"best fit" of a box inside the view //Probably sub-optimal in many respects... /***************/ /* Scene Setup */ /***************/ #declare D = vnormalize(-z-y-x);//The direction of the camera #declare Vup = vnormalize(+2*y-z-x);//The up vector #declare Fov = 50;//Field of View #declare Ratio = 4/3;//Aspect Ratio #declare Target = box{-1 1 pigment{rgb 1} scale<1,1.5,2>} //The box #declare Vright = vcross(Vup,D); //The right vector #declare Figure = true; //Are we drawing a figure or the view from the camera ? /***********************************************/ /* Algorithm determining the camera's location */ /***********************************************/ //Those are the normals of the 4 planes bounding the viewing volume. //They are entirely determined by the camera's settings. #declare Normals = array[4]; //Horizontal planes (that is, left/right of the camera) #declare Normals[0] = vaxis_rotate(Vright, Vup, -Fov/2);//left #declare Normals[1] = vaxis_rotate(-Vright, Vup, Fov/2);//right //Vertical planes (up/down) #declare FovV = degrees(atan(1/Ratio*tan(radians(Fov/2)))); #declare Normals[2] = vaxis_rotate(Vup, Vright, FovV);//down #declare Normals[3] = vaxis_rotate(-Vup, Vright, -FovV);//up //We store the bounding box, its center. //In fact later we use the position relatives to the center. #declare C1 = min_extent(Target); #declare C2 = max_extent(Target); #declare TargetCenter = (C1 + C2)/2; #declare Corners = array[8]; #declare Corners[0] = -TargetCenter; #declare Corners[1] = -TargetCenter; #declare Corners[2] = -TargetCenter; #declare Corners[3] = -TargetCenter; #declare Corners[4] = -TargetCenter; #declare Corners[5] = -TargetCenter; #declare Corners[6] = -TargetCenter; #declare Corners[7] = -TargetCenter; //Until now, we have merely the normals of the bounding planes. //We need to know the points of the box through which each of them pass. #declare Origs = array[4]; #declare i = 0; #while(i<4) //The procedure here is to run through all the box's corner, //choosing the one giving the greatest constraint for a given plane. #declare j = 0; #declare jmin = 0; #declare Min = 0; #while(j<8) #declare Dot = vdot(Normals[i], Corners[j]); #if(Dot, <0,0,0>};//Directions #declare LinesStart = array[2]{<0,0,0>, <0,0,0>};//Starting points //A simple procedure to find the intersection. //norm(1|2) : normals of the planes //orig(1|2) : origins of the planes //Dir : the direction of the intersection (unit vector) //Start : A point lying on the intersection #macro Intersect(norm1, orig1, norm2, orig2, Dir, Start) #declare Dir = vnormalize(vcross(norm1, norm2)); #local K = vcross(Dir, norm1); #local xx = vdot((orig2-orig1),norm2)/vdot(K,norm2); #declare Start = orig1+xx*K; #end //Intersection of horizontal planes Intersect(Normals[0], Origs[0], Normals[1], Origs[1], LinesDir[0], LinesStart[0]) //Intersection of vertical planes Intersect(Normals[2], Origs[2], Normals[3], Origs[3], LinesDir[1], LinesStart[1]) //Now we have to choose our location //1) It must be on the furthest line from the target //2) Arbitrarily, let's take it as close as possible to the other line //The whole thing amounts to computing the distance between our two lines. //Again, we can take advantage of the fact that the lines are not random : //for example, both are orthogonal to D. This simplifies the computation... #declare Length = vdot(LinesStart[0] - LinesStart[1] , D); //distance between the lines, signed //if negative it means that the point on the first line is our location #declare PossibleLoc = array[2] //The possible locations of the camera //(in fact, the two closest points on each line) { vdot(LinesStart[1] - LinesStart[0], LinesDir[0])*LinesDir[0] + LinesStart[0], vdot(LinesStart[0] - LinesStart[1], LinesDir[1])*LinesDir[1] + LinesStart[1] }; //choosing the location according to Length #if(Length<0) #declare Vloc = PossibleLoc[0]; #else #declare Vloc = PossibleLoc[1]; #end /******************************************/ /* Drawing the figure with planes, etc... */ /******************************************/ #if(Figure) #declare SemiTrans = pigment{rgbt<0,1,1,0.5>}//a semi transparent pigment union //making a union here, so as to make it shadowless { intersection //Intersection of all the bounding planes (the camera must be outside) {#declare i = 0; #while(i<4) plane{-Normals[i], 0 translate Origs[i]} #declare i = i+1; #end plane{D, 0.5*vlength(C2-C1) translate TargetCenter}//A rear plane to make things clearer pigment{SemiTrans} } #declare i = 0; #while(i<2)//drawing of the intersections of vertical and horizontal planes cylinder{-100*LinesDir[i], 100*LinesDir[i] ,0.02 pigment{rgb y+x} translate LinesStart[i] } #declare i = i+1; #end //Draw the possible locations to see if the code goes wrong ;-) cylinder{PossibleLoc[0], PossibleLoc[1], 0.02 pigment{rgb x+y} no_shadow} //Draw the camera : up, right, direction vectors sphere{Vloc, 0.1 pigment{rgb 1}} union{ cylinder{0, Vup, 0.03 pigment{rgb y}} cylinder{0, Vright, 0.03 pigment{rgb x}} cylinder{0, D, 0.03 pigment{rgb z}} translate Vloc no_shadow } //draw markers where corners of the box consraint the viewing volume #declare i = 0; #while(i<4) sphere{Origs[i], 0.1 pigment{rgb x}} #declare i = i+1; #end no_shadow } #end /*************/ /* The scene */ /*************/ global_settings{max_trace_level 5} #if(!Figure) //Here is the camera... finally camera{location Vloc up Vup right Ratio*Vright direction D angle Fov} #else camera{location <1,0.4,0>*6+Vloc look_at (TargetCenter+Vloc)/2} //The camera for the figure #end light_source{1000*<3,2,1> color rgb 1} object{Target}