#macro FaceCamera (Object, CL) #local Min = min_extent (Object); #local Max = max_extent (Object); #local OL = Min + (Max-Min)/2; #declare CamL = CameraLocation; // wherever you're putting it #declare CamD = vnormalize (OL-CamL); // direction of camera view // One can alternately look at this as -Caml, translated to the object's // location by adding OL. -CamL+OL = (OL-CamL) #declare CamR = vnormalize (vcross(y,CamD)); // to the right // The vector cross product gives a vector that is perpendicular to the two // given vectors. If we're at the vertex (camera location) and we cross the // direction of view and the y-axis, we get a vector pointing out to the right // CamD and y are likely not perpendicular, so the resulting vcross is some // size != 1, so we normalize the size. #declare CamU = vnormalize (vcross(CamD,CamR)); // camera up // So now we have a view direction and a right vector, which are perpendicular // So we do another vector cross product, and get the new "up" vector // Which completes our new "frame of reference". // The tangent, normal, and binormal unit vectors, often called T, N, and B, // or collectively the Frenet–Serret frame (TNB frame or TNB basis) // So now when we take the old x, y, and z basis vectors or normal POV-space // and move them to align with the new TNB vectors, your object whose // orientation was based upon x, y, and z is now based upon the new // T, N, and B vectors. // Since default camera points at z, and default orientation of most objects // is in the xy plane, the object is now in the same relative orientation // to the camera in the new TNB frame, and so always faces the camera. #declare Object_Transform = transform { matrix < CamR.x, CamR.y, CamR.z, CamU.x, CamU.y, CamU.z, CamD.x, CamD.y, CamD.z, 0, 0, 0 > } object { Object transform {Object_Transform} } #end // end macro FaceCamera