x


Make object transparent when between camera and player

In certain games, there is a function involved where if there is an object between the camera's view and the player, the object will either become transparent, or the player's silhouette is visible on the object. Would I need some sort of custom diffuse shader, or is there a function that will allow me to change the visibility of an object.

Also, how would I do a raycast/vector check to determine if the object is between the player and camera.

Would I need Pro for the transparency part?

more ▼

asked Jan 27 '11 at 05:48 AM

SirVictory gravatar image

SirVictory
1.9k 73 83 109

Oh i forgot: you don't need Pro for enything like that ;) have fun

Jan 27 '11 at 08:22 AM Bunny83
(comments are locked)
10|3000 characters needed characters left

6 answers: sort voted first

Just do it like Jean said. The Unity script reference on RaycastAll gives you an example for exact your case except it does not revert the transparency. A list would be a solution, but it gets tricky to determine what renderers have to be reverted, which ones should stay transparent and which ones have to set transparent.

I would write a little script that you can attach dynamically to those renderes which should be transparent. In that script you can implement some kind of falloff and when it'sno longer needed it removes itself.

C#:

Here's an example script that gets dynamically attached to the renderer and the script that do the raycast.

using UnityEngine;
using System.Collections;

public class AutoTransparent : MonoBehaviour
{
    private Shader m_OldShader = null;
    private Color m_OldColor = Color.black;
    private float m_Transparency = 0.3f;
    private const float m_TargetTransparancy = 0.3f;
    private const float m_FallOff = 0.1f; // returns to 100% in 0.1 sec

    public void BeTransparent()
    {
        // reset the transparency;
        m_Transparency = m_TargetTransparancy;
        if (m_OldShader == null)
        {
            // Save the current shader
            m_OldShader = renderer.material.shader;
            m_OldColor  = renderer.material.color;
            renderer.material.shader = Shader.Find("Transparent/Diffuse");
        }
    }
    void Update()
    {
        if (m_Transparency < 1.0f)
        {
            Color C = renderer.material.color;
            C.a = m_Transparency;
            renderer.material.color = C;
        }
        else
        {
            // Reset the shader
            renderer.material.shader = m_OldShader;
            renderer.material.color = m_OldColor;
            // And remove this script
            Destroy(this);
        }
        m_Transparency += ((1.0f-m_TargetTransparancy)*Time.deltaTime) / m_FallOff;
    }
}

//And here the script for the camera to cast the ray / capsule ;

using UnityEngine;
using System.Collections;

public class ClearSight : MonoBehaviour
{
    public float DistanceToPlayer = 5.0f;
    void Update()
    {
        RaycastHit[] hits;
        // you can also use CapsuleCastAll()
        // TODO: setup your layermask it improve performance and filter your hits.
        hits = Physics.RaycastAll(transform.position, transform.forward, DistanceToPlayer);
        foreach(RaycastHit hit in hits)
        {
            Renderer R = hit.collider.renderer;
            if (R == null)
                continue; // no renderer attached? go to next hit
            // TODO: maybe implement here a check for GOs that should not be affected like the player

            AutoTransparent AT = R.GetComponent<AutoTransparent>();
            if (AT == null) // if no script is attached, attach one
            {
                AT = R.gameObject.AddComponent<AutoTransparent>();
            }
            AT.BeTransparent(); // get called every frame to reset the falloff
        }
    }
}

The two script files need to be named like the class names (AutoTransparent and ClearSight).
To ignore your player select your player and change the layer on top of the inspector. Just set the layer to "IgnoreRaycast".


edit I guess your camera script is also on the camera like my ClearSight script.

JS:

var myDistanceZoomed : float;

GetComponent.<ClearSight>().DistanceToPlayer = myDistanceZoomed;

But don't forget: you need the distance in units. If you have the distance already, great, just pass it to my script ;)

more ▼

answered Jan 27 '11 at 08:21 AM

Bunny83 gravatar image

Bunny83
66.9k 22 68 268

initially i just want to write a small example script but i ended up with a full example :D. But: it's not testet yet. Syntax should be right (at least Visual C# Express can't find errors)

Jan 27 '11 at 08:25 AM Bunny83

Cool, thanks! I will try this when I get to my work desk!

Jan 27 '11 at 07:35 PM SirVictory

Okay, so I attached this script to the object I wanted to become transparent. When you run the game, the object's alpha gradually changes (without the camera even viewing the object) then the object's shader becomes null.

Jan 27 '11 at 10:04 PM SirVictory

or am I suppose to do something additional in conjunction with this script?

Jan 27 '11 at 10:06 PM SirVictory

That's funny, in our hack and slash game i also created a avoid-collision-camera by zooming in. Now that i wrote that little script for you i will implement that on top because at some places where little object are in the way the camera zooms in and out all the time. I imagine such a function long ago, but there was no need for, until now ;)

Jan 28 '11 at 04:09 AM Bunny83
(comments are locked)
10|3000 characters needed characters left

Hi SirVictory,

Raycasting would be a start, that is, you raycast from the player position and whatever is hit before the player should be send a message or dealt in some way to become semi transparent. you would need to maintain a list so that you can toggle semi transparent models back when not anymore in front of the player,

Else, you could actually have a box collider starting from the player and pointing at the camera where its size emcopass the player bounds, then anything that collides to that are also in the way.

Otherwise, Physics.CapsuleCast could be also an alternative to building a collider, but very similar in principle, tho the start point would need to be sligtly tweacked and not start right where the player is but slightly closer to the camera to not hit the ground or things to close to the player.

As for the shader, I would replace it with a specific simple one while in front, you might want to have front and backface material for object very close to the camera.

Hope it helps,

Jean

more ▼

answered Jan 27 '11 at 06:14 AM

Jean Fabre gravatar image

Jean Fabre
3.5k 70 79 110

(comments are locked)
10|3000 characters needed characters left

I've implemented the same script posted by Bunny83. Mine is in JavaScript and it changes the transparency gradually.

class AutoTransparent extends MonoBehaviour
{
    private var m_OldShader : Shader = null;
    private var m_OldColor : Color;
    private var m_Transparency : float = 0.3;

    private var m_TargetTransparancy : float = 0.3;
    private var m_FallOff : float = 0.5; // returns to 100% in 0.5 sec

    private var shouldBeTransparent : boolean = true;

    function BeTransparent()
    {
        shouldBeTransparent = true;
    }

    function Start()
    {
        if (renderer.material)
        {   
            // Save the current shader
            m_OldShader = renderer.material.shader;
            renderer.material.shader = Shader.Find("Transparent/Diffuse");

            if (renderer.material.HasProperty("_Color") )
            {
                m_OldColor  = renderer.material.color;
                m_Transparency = m_OldColor.a;
            } else
            {
                m_OldColor = Color.white;
                m_Transparency = 1.0;
            }
        } else
        {
            m_Transparency = 1.0;
        }
    }

    function OnDestroy()
    {
        if (!m_OldShader) return;
        // Reset the shader
        renderer.material.shader = m_OldShader;
        renderer.material.color = m_OldColor;
    }

    function Update()
    {
        //Shoud AutoTransparent component be removed?
        if (!shouldBeTransparent && m_Transparency >= 1.0)
        {
            Destroy(this);
        }

        //Are we fading in our out?
        if (shouldBeTransparent)
        {
            //Fading out
            if (m_Transparency > m_TargetTransparancy)
                m_Transparency -= ( (1.0 - m_TargetTransparancy) * Time.deltaTime) / m_FallOff;
        } else
        {
            //Fading in
            m_Transparency += ( (1.0 - m_TargetTransparancy) * Time.deltaTime) / m_FallOff;
        }

        renderer.material.color.a = m_Transparency;

        //The object will start to become visible again if BeTransparent() is not called
        shouldBeTransparent = false;
    }
}

Here's how you can use it:

var currentRenderer = hit.transform.gameObject.renderer;

//Make transparent
if (currentRenderer)
{
    var autoTransparent : AutoTransparent = currentRenderer.GetComponent("AutoTransparent");

    if (autoTransparent == null)
    {
        currentRenderer.gameObject.AddComponent(AutoTransparent);   
    }

    currentRenderer.SendMessage("BeTransparent");                       
}

Hope somebody finds this useful.

more ▼

answered Apr 03 '11 at 08:17 PM

Ilya gravatar image

Ilya
134 9 10 17

Thank you. This script worked perfect right out of the box. It's exactly what I was looking for. I really look forward to deconstructing your code.

I use this code to call the transparent class and it seems perfect for what i'm needing.

var hit : RaycastHit;

if (Physics.Linecast(target.position, transform.position, hit)) { var currentRenderer = hit.transform.gameObject.renderer;

//Make transparent if (currentRenderer) { var autoTransparent : AutoTransparent = currentRenderer.GetComponent("AutoTransparent");

if (autoTransparent == null) {
currentRenderer.gameObject.AddComponent(AutoTransparent);   
}

currentRenderer.SendMessage("BeTransparent"); 
}

}

Jul 23 '11 at 02:49 AM Cymrix
(comments are locked)
10|3000 characters needed characters left

For reference, here's another implementation. This uses a gameObject attached to the camera with a box collider (as a trigger), a rigid body, and this script:

public class OcclusionFader : MonoBehaviour
{
    public float Alpha = 0.5f;

    Shader TransparencyShader;
    Dictionary<GameObject, Material> mOldMaterials = new Dictionary<GameObject, Material>(8);

    void Awake()
    {
       TransparencyShader = Shader.Find("Transparent/Diffuse");
    }

    void OnTriggerEnter(Collider other)
    {
       GameObject obj = other.gameObject;
       mOldMaterials[obj] = obj.renderer.sharedMaterial;
       obj.renderer.material.shader = TransparencyShader;
       Color c = obj.renderer.material.color;
       c.a = Alpha;
       obj.renderer.material.color = c;
    }

    void OnTriggerExit(Collider other)
    {
       GameObject obj = other.gameObject;
       obj.renderer.material = mOldMaterials[obj];
       mOldMaterials.Remove(obj);
    }
}

Use the layer collision matrix to determine which objects set the trigger off.

more ▼

answered Sep 07 '13 at 02:15 PM

_MGB_ gravatar image

_MGB_
857 4 9 19

(comments are locked)
10|3000 characters needed characters left

Silly question.
Just how do you assign the scripts? I get errors for hit and stuff. Does one goto the main camera and the other the main object? Player Main Camera Capsule

more ▼

answered May 03 '12 at 10:28 PM

urawhat gravatar image

urawhat
26 1 1 2

(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x4297
x3660
x1178
x364
x190

asked: Jan 27 '11 at 05:48 AM

Seen: 13223 times

Last Updated: Sep 09 '13 at 08:34 AM