Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Camera Linecasting Multiple Object Transparency

Discussion in 'Scripting' started by unitrix, Apr 20, 2010.

  1. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    When linecasting from your camera to your character how can you make it so that when an object is in between you can turn it transparent and then when its no longer in between it goes back to regular shader?
    I can change one object to transparent and back but I cant change multiple objects.
    Any help is greatly appreciated thanks!
     
  2. Peter G

    Peter G

    Joined:
    Nov 21, 2009
    Posts:
    610
    You have to use the hitInfo. The scripting reference describes how it works. Here's a quick idea.

    Code (csharp):
    1.  
    2. private var shader1 = Shader.Find( "Diffuse" );
    3. private var shader2 = Shader.Find( "Transparent/Diffuse" );
    4.  
    5. private var player : Transform; // For performance reasons.  Using GameObject.Find every frame is not a great idea.
    6. private var cam : Camera;
    7.  
    8. function Start () {
    9.      player : GameObject.FindWithTag("Player");
    10.      camera = Camera.main;
    11. }
    12.  
    13. function Update() {
    14.  
    15.      var hit : RaycastHit;
    16.    if (Physics.Linecast (cam.transform.position, player.position, hit)){
    17.         hit.transform.renderer.material.shader = shader2;
    18.    //to change it back you will have to do some more calculating if stuff was hit and if it still is being hit.
    19.    }
    20. }
    21.  
     
  3. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    Few Questions:
    Can hit hold multiple objects?
    One thing I notice is changeing the transparency doesnt work for trees? Is there a way to make it work?
    Also how can I make it work so that the objects in hit will only go transparent if they are on the specified layers?
    To change it back to full transparency you mention I will have to check if it is still being hit. Im not too sure how to do this, the only thing that comes to my mind is put the hit in a temporary value and then check if its the same the next frame and if it isnt then change the temp back to regular shader.
    Does that sound about right?

    Btw thanks for the quick reply and the tips on the GameObject.Find I didnt know that it wasnt good to use it all the time and I have it everywhere in my code
     
  4. Peter G

    Peter G

    Joined:
    Nov 21, 2009
    Posts:
    610
    1. I don't know for sure, but I know with Raycast all, you can collect an array of hit objects. I think Linecast only returns the first object between the start point and endpoint, but I cannot guarantee that. The reference page suggests it only returns one object.

    2. See bitmasks for selectively ignoring layers.

    3. Your idea is as good as anything I can think of at the moment. Go for it. :D
     
  5. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    Ok I am trying the method I described but what I cant figure out is how to assign the object or value in hit to another variable, I keep getting errors.
    Here is something similar to what I tried:
    Code (csharp):
    1.  
    2. private var shader1 = Shader.Find( "Diffuse" );
    3. private var shader2 = Shader.Find( "Transparent/Diffuse" );
    4. var hit2 : RaycastHit;
    5.  
    6. function Update () {
    7.  
    8.     var hit : RaycastHit;
    9.     //raycast
    10.     if (Physics.Linecast (GameObject.Find("Main Camera").transform.position, GameObject.Find("Castto").transform.position,hit)){
    11.     hit.transform.renderer.material.shader = shader2;
    12.     print ("Hit something");
    13.     }
    14.  
    15.     if (hit != hit2){
    16.         hit2.transform.renderer.material.shader = shader1;
    17.         }
    18.     hit = hit2;
    19. }
    20.  
    I get an error: Object instance not set to an instance of an object pointing to the line hit2.transform.renderer.material.shader = shader1;
    I also tried
    var hit2 : Transform;
    I really not sure what to do or how to do it

    Also dont mind my sloppy codeing havnt applied any of the tricks you showed me earlier.
     
  6. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    I still cant get this to work, I can make the object go transparent but when its no longer in the rayline how can I check that and turn the objects back to normal?
     
  7. Peter G

    Peter G

    Joined:
    Nov 21, 2009
    Posts:
    610
    Ok. Sorry I forgot to check this tread recently.

    change

    hit = hit2;

    to

    hit2 = hit;

    Most programming languages read left to right so var i = var t assigns the value of t to the variable i. this is different from var t = var i which assigns the value of i to t.
     
  8. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    My bad, I did the switch and I get an error:
    Object Reference not set to an instance of an object
    that points to the line:
    hit2.transform.renderer.material.shader = shader1;
    Any ideas?
     
  9. Peter G

    Peter G

    Joined:
    Nov 21, 2009
    Posts:
    610
    How often is it logging the error. If it is logging it one time, then that is probably on the first frame, before hit2 has a value besides null.

    So the only way I can think of changing this would be to say
    Code (csharp):
    1. if(hit != hit2  hit2) {
    That should compare that they are different and that hit2 is something other than null. Otherwise, keep me posted and I will try to help the best I can. :D
     
  10. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    I tried that and it basically says raycast cannot be used in a boolean context, basically I can just type something like this:
    if (hit)
    Anyway it happens every frame that I get that error I mentioned in the above post.
    Anyway ill post my entire code again maybe I am doing something silly wrong:
    Code (csharp):
    1.  
    2. var hit2 : RaycastHit;
    3.  
    4. function Update () {
    5.  
    6.     var hit : RaycastHit;
    7.    
    8.     if (Physics.Linecast (GameObject.Find("Main Camera").transform.position, GameObject.Find("Castto").transform.position,hit)){
    9.     hit.transform.renderer.material.shader = shader2;
    10.     }
    11.     if (hit != hit2){
    12.         hit2.transform.renderer.material.shader = shader1;
    13.     }
    14.     hit2 = hit;
    15. }
    16.  
     
  11. Peter G

    Peter G

    Joined:
    Nov 21, 2009
    Posts:
    610
    Ok. I think this fix should be final.

    Code (csharp):
    1.  
    2. private var shader1 = Shader.Find( "Diffuse" );
    3. private var shader2 = Shader.Find( "Transparent/Diffuse" );
    4.  
    5. var hit : RaycastHit;
    6. var hitObj : Transform;
    7.  
    8. function Update () {
    9.  
    10.     if (Physics.Linecast (GameObject.Find("Main Camera").transform.position, transform.position,hit)){
    11.         hit.transform.renderer.material.shader = shader2;
    12.         print ("Hit something");
    13.     }
    14.  
    15.     if (hitObj != hit.transform  hitObj){
    16.         hitObj.renderer.material.shader = shader1;
    17.     }
    18.    
    19.     hitObj = hit.transform;
    20. }
    21.  
    I can't tell you for sure why it works without errors, but I think Unity deletes the data inside hitInfo every frame so it is always empty before you assign something to it. So I decided to check the transform instead and well it seems to work. :D
     
  12. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    Awesome Peter that works, thanks!
    One slight problem though, it only works for one object infront of the camera at a time, I guess in order to make it work for multiple I will have to use a combination of your code and RaycastAll.
    Im going to give it a try ill let you know how I fare.
     
  13. Peter G

    Peter G

    Joined:
    Nov 21, 2009
    Posts:
    610
    Yeah, line cast only returns the first object hit. You are right to use RaycastAll to get a collection of all the objects.

    Edit: Can't wait to hear how it turns out. :D
     
  14. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    So ive been playing around with this for a few days now and I cant get it to work properly if its not one error its another.
    This is what I have so far:
    Code (csharp):
    1.  
    2. var hitObjs : Transform[];
    3. function Update () {
    4.     var hits : RaycastHit[];
    5.     hits = Physics.RaycastAll (GameObject.Find("Main Camera").transform.position, GameObject.Find("Main Camera").transform.forward, 100.0);
    6.  
    7.     for (var i=0;i<hits.length;i++)
    8.     {
    9.         hits[i].transform.renderer.material.shader = shader2;
    10.         if (hitObjs[i] != hits[i].transform  hitObjs[i]){
    11.             hitObjs[i].renderer.material.shader = shader1;
    12.         }
    13.     }
    14.    
    15.     var hitObjs : Transform[];
    16.     for (var j=0;i<hits.length;j++)
    17.     {
    18.     hitObjs[j] = hits[j].transform;
    19.     }
    20. }
    21.  
    It turns the stuff transparent but it doesnt turn it back, I think it has an error array index out of range. One error I keep getting is that the terrain doesnt have that shader, not sure how I can make it so that it only check certain tags so that I only turn stuff transparent that I want.
    One other problem with this is that the linecast had the line from my camera to a place in space that I want. With this I cant get that, it does a strait line out of the camera witch I dont want. It also has a distance but im not sure how to set the distance from my camera to a certain point in 3d space.
    Any suggestions anyone?
     
  15. pretender

    pretender

    Joined:
    Mar 6, 2010
    Posts:
    862
    did you solve this, i am doing the same thing... and i have the same problem with this, let me know if you got any further...
     
  16. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    No I didnt get any further I am still stuck on this, I cant change multiple objects to transparent and then change them back when they are no longer inbetween the character.
    I think its a problem with storeing multiple objects witht he raycast.
    Can anyone offer any help with this it would be greatly appreciated!
     
  17. unitrix

    unitrix

    Joined:
    Mar 19, 2010
    Posts:
    279
    Just a thought on the madder, if I had say 5 walls that were all intersecting the camera and the player, the first ray grabs the first wall, could I then ignore all other objects on that ray and just test to see if it is no longer in view and then have a if statement that basically states if a ray has something in it cast another ray and ignore the first rays target and apply the same rule for this and have it keep going so that you can ignore several walls at once?
    It was just something that came accross my mind while lying in bed. Thought I ask if it was concievable to do it like this before I spend tons of time on attempting this theory.
     
  18. Loard

    Loard

    Joined:
    Oct 5, 2010
    Posts:
    14
    Im im the same problem, unitrix i been working in your script and i cant figure out how to fix it, someone have already made it???
     
  19. anderson.ramos

    anderson.ramos

    Joined:
    Nov 17, 2010
    Posts:
    4
    Someone made this work?
    I tried to write my own code, but it didn't work.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4.  
    5. public class LineOfSightDetector : MonoBehaviour
    6. {
    7.     public float distanceToMakeTransparent;
    8.     public LayerMask mask;
    9.  
    10. //  private struct RenderXAlpha
    11. //  {
    12. //      public Renderer renderer;
    13. //      public float alpha;
    14. //     
    15. //      public RenderXAlpha(Renderer rend, float aph)
    16. //      {
    17. //          renderer = rend;
    18. //          alpha = aph;
    19. //      }
    20. //  }
    21. // 
    22. //  private List<RenderXAlpha> list;
    23.  
    24.     private Transform lastTransform;   
    25.  
    26.     bool MakeThingsHappen(Camera cam, string shaderName)
    27.     {
    28.         bool ret = false;
    29.         RaycastHit hit;
    30.  
    31.         //Debug.DrawLine(cam.transform.position, cam.transform.position + cam.transform.rotation * Vector3.forward * distanceToMakeTransparent);
    32.  
    33.         if (Physics.Linecast(cam.transform.position, cam.transform.position + cam.transform.rotation * Vector3.forward * distanceToMakeTransparent,
    34.             out hit, mask.value))
    35.         {
    36.             if (hit.transform != null)
    37.             {
    38.                 if (hit.transform.renderer != null)
    39.                 {
    40.                     print(hit.transform.renderer.sharedMaterial.shader.name);
    41.  
    42.                     if (hit.transform.renderer.sharedMaterial.shader.name == shaderName)
    43.                     {
    44.                         Color c = hit.transform.renderer.sharedMaterial.GetColor("_MainColor");
    45.                         c.a *= 0.1f;
    46.                         hit.transform.renderer.sharedMaterial.SetColor("_MainColor", c);
    47.                         lastTransform = hit.transform;
    48.                         ret = true;
    49.                     }
    50.                 }
    51.                 else if (hit.transform.gameObject.GetComponent<SkinnedMeshRenderer>() != null
    52.  hit.transform.gameObject.GetComponent<SkinnedMeshRenderer>().sharedMaterial.shader.name == shaderName)
    53.                 {
    54.                     Color c = hit.transform.gameObject.GetComponent<SkinnedMeshRenderer>().sharedMaterial.GetColor("_MainColor");
    55.                     c.a *= 0.1f;
    56.                 hit.transform.gameObject.GetComponent<SkinnedMeshRenderer>().sharedMaterial.SetColor("_MainColor", c);
    57.                     lastTransform = hit.transform;
    58.                     ret = true;
    59.                 }
    60.             }
    61.         }
    62.  
    63.         if (lastTransform != null  (hit.transform   == null || hit.transform != lastTransform))
    64.         {
    65.             if (lastTransform.renderer != null  
    66.                 lastTransform.renderer.sharedMaterial.shader.name == shaderName)
    67.             {
    68.                 Color c = lastTransform.renderer.sharedMaterial.GetColor("_MainColor");
    69.                 c.a *= 10;
    70.                 lastTransform.renderer.sharedMaterial.SetColor("_MainColor", c);
    71.                 lastTransform = null;
    72.             }
    73.             else if (lastTransform.gameObject.GetComponent<SkinnedMeshRenderer>() != null            lastTransform.gameObject.GetComponent<SkinnedMeshRenderer>().sharedMaterial.shader.name == shaderName)
    74.             {
    75.                 Color c = lastTransform.gameObject.GetComponent<SkinnedMeshRenderer>().sharedMaterial.GetColor("_MainColor");
    76.                 c.a *= 10;
    77.                 lastTransform.gameObject.GetComponent<SkinnedMeshRenderer>().sharedMaterial.SetColor("_MainColor", c);
    78.                 lastTransform = null;
    79.             }
    80.         }
    81.  
    82.         return ret;
    83.     }
    84.  
    85.     void Update ()
    86.     {
    87.         Camera cam = null;
    88.  
    89.         if (CameraSwitcher.IsCamsFollowActivated)
    90.         {
    91.             cam = CameraSwitcher.FollowCams[CameraSwitcher.ActualFollowCam].camera;
    92.         }
    93.         else if (!CameraSwitcher.IsCamsFollowActivated)
    94.         {
    95.             cam = CameraSwitcher.CinematicCams[CameraSwitcher.ActualCinematicCam].camera;
    96.         }
    97.         else cam = CameraSwitcher.MainCamera;
    98.  
    99.         if (!MakeThingsHappen(cam, "Transparent/Diffuse"))
    100.             if (!MakeThingsHappen(cam, "Particles/Additive"))
    101.                 MakeThingsHappen(cam, "Transparent/Cutout/Diffuse");
    102.     }
    103. }
    104.  
    Please, if someone could help me or pointing where my code is wrong, I would be grateful.