Hello everyone !
I would like to arrange multiple text labels around a 3D model to point out specific points of it. These labels should not fly over the model but stay around it, clamped on an “imaginary circle” which belongs to the plane normal to the vector Origin-Camera. Also, I would like to link these labels with the points of interest ( LineRenderer
is the appropriate tool I guess).
It could be “simple” if my model would stay unmoving, but unfortunately, it won’t.
Information known
- Size of the model (fixed at a value of 100) => diameter of my imaginary circle
- Position of the 3D model’s center (we will assume here it is the origin :
Vector3.zero
) - Position of the points of interest
- Position of my camera (
Camera.main.transform.position
) - Target of my camera (we will assume here it is the 3D model’s center :
Vector3.zero
)
You will better understand what I mean with an image I guess :
![1]
I will explain the two different ways I tried so as to achieve what I want to do, maybe, I have missed something … In both cases I worked with a Canvas
whith a Render Mode
fixed with Screen Space - Overlay
. The C# scripts below are attached to Text
prefabs (Unity 4.6 GUI) I instantiate dynamically from a database.
Working in 2D
Since I want to put labels on the screen, I will work in 2D as soon as possible.
void Update( )
{
// Get the position of the origin on the screen
Vector3 screenPointOrigin = Camera.main.WorldToScreenPoint( Vector3.zero );
// Get the position of the point of interest on the screen
Vector3 screenPointInterest = Camera.main.WorldToScreenPoint( pointOfInterestSphere.transform.position );
// Get the radius of the imaginary circle :
// Get the point on the top of it and compute the distance from the center of the circle
// 100 = model's size
float circleRadius = ( Camera.main.WorldToScreenPoint( Camera.main.transform.up * 100 ) - screenPointOrigin).magnitude;
// Arrange the label around the model
transform.GetComponent<RectTransform>().anchoredPosition = new Vector2(
( screenPointInterest - screenPointOrigin ).normalized.x * circleRadius,
( screenPointInterest - screenPointOrigin ).normalized.y * circleRadius
);
}
Here, the script arrange the labels around the imaginary circle, but the circle is centered on the middle of my screen and not on the center of my model (Note that I don’t move my camera in any of my scripts and the center of the model is (0, 0, 0) ).
Another problem is the Line Renderer which is nearly impossible to do since my labels are on my screen. When I tried to draw the Line Renderer, it hits the screen and makes a disgusting aspect.
Working in 3D
In 3D, the script is different since I work with the position of my labels in the 3D space. But before my explanation, I invite you to read this page about the projection of a vector onto a plane.
void Update( )
{
// Get the projection vector onto the plane normal to the vector Origin-Camera
transform.position = pointOfInterest.transform.position - Camera.main.transform.position * Vector3.Dot( pointOfInterest.transform.position, Camera.main.transform.position ) / Camera.main.transform.position.sqrMagnitude ;
// Clamp the label on the imaginary circle and readjust the position at the center of the canvas
// 100 = model's size
transform.position = transform.position.normalized * 100 ;
transform.position = transform.position + GameObject.Find("SculptureCanvas").transform.position ;
}
Here, same problem, the labels are not centered around the model and they don’t gravitate well around the model (I know I have to consider the distance model-camera). Moreover, the Line Renderer is nearly impossible to do… With a Render Mode
fixed to Screen Space - Camera
, the script is nearly the same, and the LineRenderer
is perfect, but the labels are not quite arranged.
Thank you in advance ! I hope my explanation is quite clear !
PS : Sorry for bad english !