/** * Support method to initialize a vector with the distances between the camera and the character associated with each Shot type. * Called during initialization. * Prevents heavy computations at runtime. **/ private void _initializeDistances() { for (int i = 0; i < System.Enum.GetNames(typeof(Shot)).Length; i++) { Shot shot = (Shot)System.Enum.ToObject(typeof(Shot), i); CameraFramingInfo framingInfo = _newFramingInfo(shot); //cam_frame_calc(shot, true, ref targetCameraPosition, ref currentCameraAngle); //calculating the initial camera distance: //the conditions: //1. We keep height of the camera to the height of the right eye //2. For each shot we set the height of the lowest and highest point of the camera frame in the plane of the character //3. Now knowing the camera FOV, we can calculate the distance of camera and its angle for each frame // //the parameters are as follows. It is a matter of solving two triangles to have the position and orientation of the camera: // h1: distance between top of the frame point and the eye // h2: distance between the bottom of the frame and the eye // bCoeeficient & bCoeeficient: coefficients of the quadratic equation // // // // top of the frame on the char's plane // * . // * . // * . // * h1 // * . // * )alpha2 . //Camera..............d......height of the char's right eye // * )alpha1 . // * . // * . // * . // * h2 // * . // * . // * . // * . // * . // bottom of of the frame on the char's plane // // alpha1 + alpha2 = FOV //tg(alpha1 + alpha2) = (h1/d + h2/d) / (a + (h1*h2/d^2) = tg(FOV) //d^2 - [(h1 + h2) / tg(FOV) * d] + [h1 * h2] = 0 float frameTop = (framingInfo.Top_body.y + framingInfo.top_margin * framingInfo.heightCoefficient); float camera_height_ = _targetBoneObjects[(int)TargetBonesEnum.eye_R].transform.position.y; float h1 = frameTop - camera_height_; float frameBottom = (framingInfo.Bottom_body.y + framingInfo.bottom_margin * framingInfo.heightCoefficient); float h2 = camera_height_ - frameBottom; float bCoeeficient = -1 * (h1 + h2) / (Mathf.Tan(Camera.main.fieldOfView * Mathf.PI / 180)); float cCoefficient = h1 * h2; _initialCameraDistances[(int)shot] = (float)(-0.5 * (-bCoeeficient + Mathf.Sqrt(bCoeeficient * bCoeeficient - 4 * cCoefficient))); } }
/** * Given the shot type, this method computes the desired camera position and inclination. * It reads on-the-fly the position of the reference bones. Hence, for the same shot, the results will be different if the character is moved or animated. **/ private void _computeCameraParams(Shot current_shot, ref Vector3 newTargetPosition, ref float newAngle) { CameraFramingInfo framing_info = _newFramingInfo(current_shot); // // Compute the camera position, according to the current position of the eye float cameraZ = ((framing_info.Top_body.z + framing_info.Bottom_body.z) / 2 + _initialCameraDistances [(int)current_shot]) * (1 + distanceFineTune / 100); // set height of camera to right eye's height float camera_height = _targetBoneObjects [(int)TargetBonesEnum.eye_R].transform.position.y; newTargetPosition = new Vector3(framing_info.camera_x, camera_height, cameraZ); // // Calculating the inclination of the camera (rotation around the x-axis) float target_frame_top = (framing_info.Top_body.y + framing_info.top_margin * framing_info.heightCoefficient); //expected highest point that you can see in the frame on the vertical surface passing the character newAngle = (float)((Mathf.Atan(((target_frame_top - transform.position.y) / (transform.position.z - _targetBoneObjects[(int)TargetBonesEnum.eye_R].transform.position.z))) * 180 / Mathf.PI) + (Camera.main.fieldOfView / 2)); }
/** * Instantiate a new CameraFramingInfo according to the current position of the bones. * Uses the cached _targetBoneObjects. **/ private CameraFramingInfo _newFramingInfo(Shot current_shot) { CameraFramingInfo outInfo; Vector3 head_top = _targetBoneObjects[(int)TargetBonesEnum.head_top].transform.position; switch (current_shot) { case Shot.FULL_SHOT: outInfo = new CameraFramingInfo(1f / 12f, 1f / 12f, _targetBoneObjects[(int)TargetBonesEnum.toes_R].transform.position, head_top, _targetBoneObjects[(int)TargetBonesEnum.root].transform.position.x); break; case Shot.MEDIUM_SHOT: Vector3 lowBody = (_targetBoneObjects[(int)TargetBonesEnum.calf_R].transform.position + _targetBoneObjects[(int)TargetBonesEnum.spine01].transform.position) / 2; outInfo = new CameraFramingInfo(0, 1f / 12f, lowBody, head_top, _targetBoneObjects[(int)TargetBonesEnum.spine01].transform.position.x); break; case Shot.MEDIUM_CLOSE_UP: lowBody = _targetBoneObjects[(int)TargetBonesEnum.breast_R].transform.position; Vector3 offset = new Vector3(0, 0.05f, 0); outInfo = new CameraFramingInfo(0, 1f / 12f, lowBody + offset, head_top + offset / 2, _targetBoneObjects[(int)TargetBonesEnum.spine01].transform.position.x); break; case Shot.FULL_CLOSE_UP: lowBody = _targetBoneObjects[(int)TargetBonesEnum.neck].transform.position; outInfo = new CameraFramingInfo(0, 1f / 12f, lowBody, head_top, _targetBoneObjects[(int)TargetBonesEnum.neck].transform.position.x); break; case Shot.EXTREME_CLOSE_UP: Vector3 dist = _targetBoneObjects[(int)TargetBonesEnum.head_top].transform.position - _targetBoneObjects[(int)TargetBonesEnum.eye_R].transform.position; outInfo = new CameraFramingInfo(0, 0, _targetBoneObjects[(int)TargetBonesEnum.eye_R].transform.position - dist / 4, _targetBoneObjects[(int)TargetBonesEnum.eye_R].transform.position + dist / 4, _targetBoneObjects[(int)TargetBonesEnum.eye_R].transform.position.x); break; default: outInfo = new CameraFramingInfo(1f / 12f, 1f / 12f, _targetBoneObjects[(int)TargetBonesEnum.toes_R].transform.position, head_top, 0); Debug.LogError("Invalid value for camera shot: " + current_shot); break; } return(outInfo); }