Hi,
With the following code :
private void DrawTargets()
{
foreach (Pawn pawn in m_Targets)
{
Vector3 pos = camera.WorldToScreenPoint(pawn.transform.position);
float size = Mathf.Clamp(10000 / (pos.z + 1), 4, 32);
Texture2D tex = targetsTex;
if (size <= 16) tex = targetsTex2;
Rect rect;
if (pos.z < 0)
{
return;
}
else
{
if (pos.x <= 0) tex = pawn.m_TargetLeft;
else if (pos.x >= camera.pixelWidth) tex = pawn.m_TargetRight;
else if (pos.y <= 0) tex = pawn.m_TargetDown;
else if (pos.y >= camera.pixelHeight) tex = pawn.m_TargetUp;
}
rect = new Rect(pos.x - size / 2, camera.pixelHeight - (pos.y + size / 2), size, size);
GUI.DrawTexture(rect, tex);
}
}
Everything happens like if z < 0, but the objects are not behind the camera.
The expected result first, and the result after :
The doc page is a bit misleading here. The Z coordinate returned by WorldToScreenPoint is not the distance of the screen pixel from the camera but rather the distance from the camera to the XY plane at that pixel position. You can test if an object is in front of the camera or behind by taking the dot product of the object’s heading with the camera’s transform.forward vector:-
var heading = target.transform.position - camera.transform.position;
if (Vector3.Dot(camera.transform.forward, heading > 0) {
// Object is in front.
}
2 Likes
Thank you.
This is my new code. It works as expected :
private void DrawTargets()
{
Vector3 pos, campos;
Texture2D tex;
float size;
Rect rect = new Rect(0,0,0,0);
foreach (Pawn pawn in m_Targets)
{
pos = camera.WorldToScreenPoint(pawn.transform.position);
campos = pawn.transform.position - camera.transform.position;
size = Mathf.Clamp(10000 / (pos.z + 1), 8, 32);
tex = targetsTex;
if (size <= 16) tex = targetsTex2;
if (Vector3.Dot(camera.transform.TransformDirection(Vector3.forward), campos) > 0)
{
if (pos.x <= 0) tex = pawn.m_TargetLeft;
else if (pos.x >= camera.pixelWidth) tex = pawn.m_TargetRight;
else if (pos.y <= 0) tex = pawn.m_TargetDown;
else if (pos.y >= camera.pixelHeight) tex = pawn.m_TargetUp;
rect.x = Mathf.Clamp(pos.x, 0, camera.pixelWidth) - size / 2;
rect.y = camera.pixelHeight - (Mathf.Clamp(pos.y, 0, camera.pixelHeight) + size / 2);
}
else
{
if (pos.x <= camera.pixelWidth / 2)
{
tex = pawn.m_TargetLeft;
rect.x = 0;
rect.y = camera.pixelHeight - (Mathf.Clamp(pos.y, 0, camera.pixelHeight) + size / 2);
}
else
{
tex = pawn.m_TargetRight;
rect.x = 1;
rect.y = camera.pixelHeight - (Mathf.Clamp(pos.y, 0, camera.pixelHeight) + size / 2);
}
if (pos.y <= camera.pixelHeight / 2)
{
tex = pawn.m_TargetDown;
rect.y = 0;
rect.x = Mathf.Clamp(pos.x, 0, camera.pixelWidth) - size / 2;
}
else
{
tex = pawn.m_TargetUp;
rect.y = 1;
rect.x = Mathf.Clamp(pos.x, 0, camera.pixelWidth) - size / 2;
}
}
rect.width = rect.height = size;
GUI.DrawTexture(rect, tex);
}
}
andeeeee:
The doc page is a bit misleading here. The Z coordinate returned by WorldToScreenPoint is not the distance of the screen pixel from the camera but rather the distance from the camera to the XY plane at that pixel position. You can test if an object is in front of the camera or behind by taking the dot product of the object’s heading with the camera’s transform.forward vector:-
var heading = target.transform.position - camera.transform.position;
if (Vector3.Dot(camera.transform.forward, heading > 0) {
// Object is in front.
}
Thank you. This is still helping people I used “Z” initially and it didn’t solve the problem. I hope Unity will update the doc or explain better how to use that value.