Changing visibility of GUIText object

Hi all

  • I have an anatomy demo (here) using GUIText to label anatomical points.

  • Currently the GUIText displays at all times

  • each GUIText is the child of a red sphere which is what’s delineating the anatomy

  • I’m trying to make it so that a GUIText component appears and disappears depending on whether or not the object it is a child of is visible to the camera.

  • I have only one camera in my game.

  • the script at the end of this message is the script attached to the GUIText object

So far the functions Renderer.isVisible and OnBecameVisible have not produced any results in my hands.

I’ve found another thread here but as a beginning C#er I don’t have the wider understanding to know which avenue to pursue. Any pointers greatly appreciated.

Here are some screenshots

using UnityEngine;
using System.Collections;

public class deltoid_tuberosity : MonoBehaviour {

    public Transform target;  // Object that this label should follow
    public Vector3 offset = Vector3.up;    // Units in world space to offset; 1 unit above object by default
    public bool clampToScreen = false;  // If true, label will be visible even if object is off screen
    public float clampBorderSize = 0.05f;  // How much viewport space to leave at the borders when a label is being clamped
    public bool useMainCamera = true;   // Use the camera tagged MainCamera
    public Camera cameraToUse ;   // Only use this if useMainCamera is false
    Camera cam ;
    Transform thisTransform;
    Transform camTransform;
    public GUISkin mySkin; //apply GUIskin
    private GUIText thisGui;
   
    void OnGUI () {
        // Assign the skin to be the one currently used.
        GUI.skin = mySkin;
    }
   
   
   
    void Start ()
    {
        thisGui = GetComponent <GUIText>();
        thisTransform = transform;
        if (useMainCamera)
            cam = Camera.main;
        else
            cam = cameraToUse;
        camTransform = cam.transform;
    }

    void OnBecameVisible () {

        Debug.Log ("OnBecameVisible");
        enabled = true;
    }

    void OnBecameInvisible () {

        Debug.Log ("OnBecameInvisible");
        enabled = false;
    }



    void Update()
    {

   

       
        if (clampToScreen)
        {
            Vector3 relativePosition = camTransform.InverseTransformPoint(target.position);
            relativePosition.z =  Mathf.Max(relativePosition.z, 1.0f);
            thisTransform.position = cam.WorldToViewportPoint(camTransform.TransformPoint(relativePosition + offset));
            thisTransform.position = new Vector3(Mathf.Clamp(thisTransform.position.x, clampBorderSize, 1.0f - clampBorderSize),
                                                 Mathf.Clamp(thisTransform.position.y, clampBorderSize, 1.0f - clampBorderSize),
                                                 thisTransform.position.z);
           
        }
        else
        {
            thisTransform.position = cam.WorldToViewportPoint(target.position + offset);
        }
    }

I believe the reason that OnBecameInvisible isn’t firing is because the red dot is still within the camera’s frustum. It is being occluded by other objects, but it is still “visible”.

I guess one solution would be to use a ray cast to determine whether that dot is being blocked by other geometry:

Thanks numberkruncher

I’ve been playing around with Raycast code snippets but I’ve not had any luck so far.

One of the main problems is most of the C# code I’ve found so far relates to the object falling under the mouse cursor.

 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

I’m interested in whether or not the camera can see the object at all.

I currently am practicing with a scene with just a cube within it. Can you help me modify the code above so that when the cube comes into view the Debug.Log returns “the cube is in sight”. From there I (hope! I) can workout how to add a handle to a component on the cube and modify it.

You could also test with linecast (easy to set start & end positions),
but the problem is, if the red dot is exactly on the surface or even a bit inside,
then it would report a linecast hit and hide the sphere, so they might need small offset from the surface…

if (Physics.Linecast(Camera.main.position,reddot[i].position))
{
// not visible
}else{
// visible
}

Thanks mgear. Having the sphere touching the anatomy is quite important I think, so that solution isn’t going to work so well for me. Would it do the same thing with raycast as well do you think or is that a function of linecast?

I was just thinking, is it better to have whatever function is looking at whether the red sphere & camera can see each other or not scripted into the sphere, or better to have it all scripted onto the camera. I’m thinking having on the sphere might be less complicated although I’m not sure this can be done…

Are those spheres placed there manually?
If yes, could then place another empty gameobject there to mark the raycast target (so that its not inside the bone…)

Linecast does the same as raycast.

Other idea could be: (no idea if it would actually work)

  • Have a 2nd camera
  • With that, render only back faces from mesh
  • Using rendertexture from that view, check with GetPixel() if sphere position has color (it means mesh back face is blocking the view…)
  • Could check with 5 GetPixels (sphere center and corners) to make it notice partly visible sphere…

The spheres are indeed placed there manually.
So you mean

  1. place the empty so that it’s near but not touching the sphere/ anatomical area.
  2. child the sphere & GUIText to the empty gameobject
  3. use the raycast/ linecast function to look for the empty gameobject and then use that to get a handle on the GUIText object to disable it?

Sounds good!

The second method is way beyond me at this time =(

EDIT: was just thinking, an empty gameobject won’t have a collider as it doesn’t have a mesh so will the raycast/linecast be able to interact with it?