Search Unity

Question Calculations off Camera.WorldToScreenSpace on Canvas

Discussion in 'UGUI & TextMesh Pro' started by AgelessFrost, Nov 28, 2021.

  1. AgelessFrost

    AgelessFrost

    Joined:
    Jan 26, 2019
    Posts:
    5
    I've got this method I've created which, honestly works well except for two kinks that I can't seem to work out. I've attached a few screenshots, named according to set up for explaining this.

    My canvas is set up to pull world points from the characters, and play a bark over their head. After a pile of digging and running tests I got this to work almost perfectly.

    There's one issue with scaling using the Canvas Scaler, it does not seem to update the values for width and height based on the canvas size, and so ends up clipping outside of the Canvas when not 1920x1080. I had found one solution online using some interesting conversion into Viewport space from world, then to canvas. But it produced results identical to this, so I cut that out. Even if there's an actual piece of information I could be pointed to for that, would be incredibly appreciated.

    My second issue, is perhaps related, but seemingly unrelated. When I attempt to loop through the existing Barks and check for overlapping barks to then offset, so that they aren't covering each other. I know right now the existing offset is not good enough for end case. I need it to be working well first, then I can play with the precise reposition based on overlap reposition.

    I've messed with this calculation check a lot, and it works sometimes when it should, but not other times. I can't crack why this is happening. Any insight into this would be incredibly useful!

    Code (CSharp):
    1.         private IEnumerator UpdateBarks()
    2.         {
    3.             bool playing = _ActiveBarks = true;
    4.  
    5.             // Update barks while coroutine is running
    6.             while (playing)
    7.             {
    8.                 bool isActive = false;
    9.                 List<BarkLayout> barks = new List<BarkLayout>();
    10.                 for (int i = _Barks.Count - 1; i >= 0; i--)
    11.                 {
    12.                     // keep tabs of active barks, if none are playing end the coroutine at the end
    13.                     isActive = isActive || _Barks[i].Playing;
    14.  
    15.                     // If this bark is not playing, we can skip all position calculations.
    16.                     if (!_Barks[i].Playing)
    17.                     {
    18.                         // Return deactivated bark to pool
    19.                         _InactiveBarksPool.Enqueue(_Barks[i]);
    20.                         _Barks.RemoveAt(i);
    21.                         continue;
    22.                     }
    23.  
    24.                     var mainCamera = Camera.main;
    25.  
    26.                     // Calculate re-used values
    27.                     float distance = Vector3.Distance(_Barks[i].DisplayPoint.position, mainCamera.transform.position);
    28.  
    29.                     // Used for scaling and alpha adjustment based on distance
    30.                     float distanceLerp = Mathf.InverseLerp(_MinMaxDistance.y, _MinMaxDistance.x, distance);
    31.  
    32.                     // Scale the bark based on the distance it is from the camera
    33.                     float fontSize = Mathf.Lerp(_MinMaxFontSize.x, _MinMaxFontSize.y, distanceLerp);
    34.                     _Barks[i].BarkText.fontSize = fontSize;
    35.  
    36.                     Vector3 displayPoint = mainCamera.WorldToScreenPoint(_Barks[i].DisplayPoint.position + new Vector3(0, .3f, 0));
    37.                     Vector2 size = _Barks[i].GetComponent<RectTransform>().rect.size;
    38.                     float halfXSize = size.x / 2;
    39.                     float leftPoint = displayPoint.x - halfXSize;
    40.                     float rightPoint = displayPoint.x + halfXSize;
    41.  
    42.                     // If bark is not already performing a fade operation, change alpha based on distance to camera
    43.                     if (!_Barks[i].Fading)
    44.                     {
    45.                         _Barks[i].CanvasGroup.alpha = Mathf.Lerp(_MinMaxAlpha.x, _MinMaxAlpha.y, distanceLerp);
    46.                     }
    47.  
    48.                     // Handle spherical interpolation (Edge of screen)
    49.                     if (Vector3.Dot(_Barks[i].DisplayPoint.position - mainCamera.transform.position, mainCamera.transform.forward) < 0)
    50.                     {
    51.                         if (displayPoint.x < Screen.width / 2)
    52.                             displayPoint.x = Screen.width - size.x / 2;
    53.                         else
    54.                             displayPoint.x = halfXSize;
    55.  
    56.                         if (displayPoint.y < Screen.height / 2)
    57.                             displayPoint.y = Screen.height - size.y;
    58.                         else
    59.                             displayPoint.y = 0;
    60.                     }
    61.  
    62.                     // Clamp position to be on screen (needs to be done with above step up due to the calculation of values from unity)
    63.                     displayPoint.x = Mathf.Clamp(displayPoint.x, 0 + size.x / 2, Screen.width - halfXSize);
    64.                     displayPoint.y = Mathf.Clamp(displayPoint.y, 0, Screen.height - size.y);
    65.  
    66.                     // Position bark dialogue box to the calculated position
    67.                     _Barks[i].transform.position = displayPoint;
    68.  
    69.                     // Add this index to the barks we check
    70.                     barks.Add(new BarkLayout(){LeftSide = leftPoint, RightSide = rightPoint, height = _Barks[i].transform.position.y});
    71.  
    72.                     // compare with the bark structs created from this loop of barks
    73.                     for (int j = 0; j < barks.Count - 1; j++)
    74.                     {
    75.                         // If heights aren't approximately the same, we don't need to offset in comparison.
    76.                         if(i >= barks.Count || j >= barks.Count || Math.Abs(barks[j].height - barks[i].height) < size.y / 2)
    77.                             continue;
    78.                         // If left side overlaps any right side, or right side overlaps any left side, adjust height.
    79.                         if (leftPoint < barks[j].RightSide || rightPoint > barks[j].LeftSide)
    80.                         {
    81.                             // If we are here and overlapping anything, we want to add an offset.
    82.                             var point = _Barks[i].transform.position;
    83.                             _Barks[i].transform.position = new Vector3(point.x, point.y + size.y, point.z);
    84.                             barks[i] = new BarkLayout()
    85.                             {
    86.                                 LeftSide = leftPoint,
    87.                                 RightSide = rightPoint,
    88.                                 height = _Barks[i].transform.position.y
    89.                             };
    90.                         }
    91.                     }
    92.                 }
    93.  
    94.                 // If playing is false, every bark is deactivated, and we can stop the loop check.
    95.                 playing = isActive;
    96.                 yield return new WaitForEndOfFrame();
    97.             }
    98.  
    99.             _ActiveBarks = false;
    100.             yield return null;
    101.         }
    Barks.PNG Barks1080p.PNG BarkshigherRes.PNG BarksLowerRes.PNG CanvasScaler.PNG