PositionAndRotation TargetPositionAndRotation(GameObject[] targets) { float halfVerticalFovRad = (_camera.fieldOfView * Mathf.Deg2Rad) / 2f; float halfHorizontalFovRad = Mathf.Atan(Mathf.Tan(halfVerticalFovRad) * _camera.aspect); var rotation = Quaternion.Euler(Pitch, Yaw, Roll); var inverseRotation = Quaternion.Inverse(rotation); var targetsRotatedToCameraIdentity = targets.Select(target => inverseRotation * target.transform.position).ToArray(); float furthestPointDistanceFromCamera = targetsRotatedToCameraIdentity.Max(target => target.z); float projectionPlaneZ = furthestPointDistanceFromCamera + 3f; ProjectionHits viewProjectionLeftAndRightEdgeHits = ViewProjectionEdgeHits(targetsRotatedToCameraIdentity, ProjectionEdgeHits.LEFT_RIGHT, projectionPlaneZ, halfHorizontalFovRad).AddPadding(PaddingRight, PaddingLeft); ProjectionHits viewProjectionTopAndBottomEdgeHits = ViewProjectionEdgeHits(targetsRotatedToCameraIdentity, ProjectionEdgeHits.TOP_BOTTOM, projectionPlaneZ, halfVerticalFovRad).AddPadding(PaddingUp, PaddingDown); var requiredCameraPerpedicularDistanceFromProjectionPlane = Mathf.Max( RequiredCameraPerpedicularDistanceFromProjectionPlane(viewProjectionTopAndBottomEdgeHits, halfVerticalFovRad), RequiredCameraPerpedicularDistanceFromProjectionPlane(viewProjectionLeftAndRightEdgeHits, halfHorizontalFovRad) ); Vector3 cameraPositionIdentity = new Vector3( (viewProjectionLeftAndRightEdgeHits.Max + viewProjectionLeftAndRightEdgeHits.Min) / 2f, (viewProjectionTopAndBottomEdgeHits.Max + viewProjectionTopAndBottomEdgeHits.Min) / 2f, projectionPlaneZ - requiredCameraPerpedicularDistanceFromProjectionPlane); return(new PositionAndRotation(rotation * cameraPositionIdentity, rotation)); }
private void DebugDrawProjectionRays(Vector3 cameraPositionIdentity, ProjectionHits viewProjectionLeftAndRightEdgeHits, ProjectionHits viewProjectionTopAndBottomEdgeHits, float requiredCameraPerpedicularDistanceFromProjectionPlane, IEnumerable <Vector3> targetsRotatedToCameraIdentity, float projectionPlaneZ, float halfHorizontalFovRad, float halfVerticalFovRad) { if (_debugProjection == DebugProjection.DISABLE) { return; } DebugDrawProjectionRay( cameraPositionIdentity, new Vector3((viewProjectionLeftAndRightEdgeHits.Max - viewProjectionLeftAndRightEdgeHits.Min) / 2f, (viewProjectionTopAndBottomEdgeHits.Max - viewProjectionTopAndBottomEdgeHits.Min) / 2f, requiredCameraPerpedicularDistanceFromProjectionPlane), new Color32(31, 119, 180, 255)); DebugDrawProjectionRay( cameraPositionIdentity, new Vector3((viewProjectionLeftAndRightEdgeHits.Max - viewProjectionLeftAndRightEdgeHits.Min) / 2f, -(viewProjectionTopAndBottomEdgeHits.Max - viewProjectionTopAndBottomEdgeHits.Min) / 2f, requiredCameraPerpedicularDistanceFromProjectionPlane), new Color32(31, 119, 180, 255)); DebugDrawProjectionRay( cameraPositionIdentity, new Vector3(-(viewProjectionLeftAndRightEdgeHits.Max - viewProjectionLeftAndRightEdgeHits.Min) / 2f, (viewProjectionTopAndBottomEdgeHits.Max - viewProjectionTopAndBottomEdgeHits.Min) / 2f, requiredCameraPerpedicularDistanceFromProjectionPlane), new Color32(31, 119, 180, 255)); DebugDrawProjectionRay( cameraPositionIdentity, new Vector3(-(viewProjectionLeftAndRightEdgeHits.Max - viewProjectionLeftAndRightEdgeHits.Min) / 2f, -(viewProjectionTopAndBottomEdgeHits.Max - viewProjectionTopAndBottomEdgeHits.Min) / 2f, requiredCameraPerpedicularDistanceFromProjectionPlane), new Color32(31, 119, 180, 255)); foreach (var target in targetsRotatedToCameraIdentity) { float distanceFromProjectionPlane = projectionPlaneZ - target.z; float halfHorizontalProjectionVolumeCircumcircleDiameter = Mathf.Sin(Mathf.PI - ((Mathf.PI / 2f) + halfHorizontalFovRad)) / (distanceFromProjectionPlane); float projectionHalfHorizontalSpan = Mathf.Sin(halfHorizontalFovRad) / halfHorizontalProjectionVolumeCircumcircleDiameter; float halfVerticalProjectionVolumeCircumcircleDiameter = Mathf.Sin(Mathf.PI - ((Mathf.PI / 2f) + halfVerticalFovRad)) / (distanceFromProjectionPlane); float projectionHalfVerticalSpan = Mathf.Sin(halfVerticalFovRad) / halfVerticalProjectionVolumeCircumcircleDiameter; DebugDrawProjectionRay(target, new Vector3(projectionHalfHorizontalSpan, 0f, distanceFromProjectionPlane), new Color32(214, 39, 40, 255)); DebugDrawProjectionRay(target, new Vector3(-projectionHalfHorizontalSpan, 0f, distanceFromProjectionPlane), new Color32(214, 39, 40, 255)); DebugDrawProjectionRay(target, new Vector3(0f, projectionHalfVerticalSpan, distanceFromProjectionPlane), new Color32(214, 39, 40, 255)); DebugDrawProjectionRay(target, new Vector3(0f, -projectionHalfVerticalSpan, distanceFromProjectionPlane), new Color32(214, 39, 40, 255)); } }
private static float RequiredCameraPerpedicularDistanceFromProjectionPlane(ProjectionHits viewProjectionEdgeHits, float halfFovRad) { float distanceBetweenEdgeProjectionHits = viewProjectionEdgeHits.Max - viewProjectionEdgeHits.Min; return((distanceBetweenEdgeProjectionHits / 2f) / Mathf.Tan(halfFovRad)); }