Search Unity

Get deferred light Pos

Discussion in 'Shaders' started by Reanimate_L, Jan 25, 2016.

  1. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Anybody know how to get all the lightPos and Color in the scene from deferred light?
    especially for point and spot light.
     
  2. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    Color you get through LightColor.
    Positions, maybe you can get it from LightMatrix0 (World to light matrix) but i am sure you dont want to go with the hassle. Or you can approximately calculate it via the light direction.
    Easier way is to write a script to pass the positions of selected lights data via a render texture?
     
  3. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Ohh never heard of this, any small sample for this one?
     
  4. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    make a 1x8 texture

    for any light in scene(max 8 in this case) {
    if(light[any] in screen)
    setrendertexturepixel[any(1 to 8)] = light normalized relative pos to camera, alpha is approximation of some eyespace distance
    for unused pixels, set to black.
    }

    in shader;
    do something if pixel is not black {
    light pos = CameraPos + pixel color.rgb * pixel.alpha
    }
     
  5. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    I'm bit confused in this part
     
  6. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    because in the shader you will add this value to the camera position and the texture wont accept a value higher than 1, you will have to come up with a value that is relative to camera position and between 0 and 1 values on each channel.
    Good thing is, you can use the alpha channel to do approximation between farthest and closest light positions and interpolate other lights in between.
     
  7. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    On the second thought, assuming you wont have hundreds of lights, why dont you just pass an array of vector positions to your shader if the maximum light count is less than lets say 4-5?
     
  8. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Well i was planning to do it in deferred since there's a high chance to have more than 8 lights even thought that kinda overkill. But yeah that's my first plan.
     
  9. Nabbz0rz

    Nabbz0rz

    Joined:
    May 5, 2013
    Posts:
    8
    Reviving an old thread.

    Thanks for the suggestion aubergine, however scaling the relative position by the far plane to retrieve homogeneous values to insert into the texture for subsequent re-scaling results in lost/inaccurate light positions.

    In an effort to bypass this I tried using Aras' EncodeFloatRGBA and DecodeFloatRGBA (http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/) on each individual component of the position.

    This of course expands the texture size four-fold, but so long as we could get accurate results that is all that I am interested in.

    It may work well in CG, however when converted to use in C# it struggles to work. Oddly, the X and Z values are accurate, while Y is not.

    Component for texture generation:
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. [RequireComponent(typeof(Camera))]
    6. public class DeferredLightPositionsComponent : MonoBehaviour {
    7.     private Texture2D light_position_texture = null;
    8.     private int light_length;
    9.  
    10.     private Camera camera;
    11.  
    12.     void Awake () {
    13.         camera = GetComponent<Camera> ();
    14.     }
    15.  
    16.     private static Color EncodeFloatRGBA (float v) {
    17.         v = Mathf.Min(v, 0.99999f);
    18.  
    19.         Vector4 enc = new Vector4(1.0f, 255.0f, 65025.0f, 16581375.0f) * v;
    20.  
    21.         enc.x -= Mathf.Floor (enc.x);
    22.         enc.y -= Mathf.Floor (enc.y);
    23.         enc.z -= Mathf.Floor (enc.z);
    24.         enc.w -= Mathf.Floor (enc.w);
    25.  
    26.         enc.x -= enc.y * (1.0f / 255.0f);
    27.         enc.y -= enc.z * (1.0f / 255.0f);
    28.         enc.z -= enc.w * (1.0f / 255.0f);
    29.  
    30.         return new Color(enc.x, enc.y, enc.z, enc.w);
    31.     }
    32.  
    33.     private static float DecodeFloatRGBA (Color rgba) {
    34.         Vector4 enc = new Vector4 (rgba.r, rgba.g, rgba.b, rgba.a);
    35.  
    36.         return Vector4.Dot (enc, new Vector4 (1.0f, 1.0f / 255.0f, 1.0f / 65025.0f, 1.0f / 16581375.0f));
    37.     }
    38.  
    39.     void Update () {
    40.         Light[] lights = FindObjectsOfType(typeof(Light)) as Light[];
    41.        
    42.         if (light_position_texture == null) {
    43.             light_length = lights.Length;
    44.            
    45.             light_position_texture = new Texture2D (light_length * 4 + 1, 1);
    46.         } else if(light_length != lights.Length) {
    47.             light_length = lights.Length;
    48.            
    49.             light_position_texture.Resize(light_length * 4 + 1, 1);
    50.         }
    51.        
    52.         light_position_texture.SetPixel (0, 0, EncodeFloatRGBA((float)(light_length * 4 + 1) / camera.farClipPlane));
    53.  
    54.         for(int i = 0; i < lights.Length; i++) {
    55.             Vector3 light_position = lights[i].transform.position - camera.transform.position;
    56.            
    57.             float distance = light_position.magnitude / camera.farClipPlane;
    58.            
    59.             light_position.Normalize();
    60.  
    61.             light_position_texture.SetPixel(i * 4 + 1, 0, EncodeFloatRGBA(light_position.x));
    62.             light_position_texture.SetPixel(i * 4 + 2, 0, EncodeFloatRGBA(light_position.y));
    63.             light_position_texture.SetPixel(i * 4 + 3, 0, EncodeFloatRGBA(light_position.z));
    64.             light_position_texture.SetPixel(i * 4 + 4, 0, EncodeFloatRGBA(distance));
    65.  
    66.  
    67.             /* NOTE: Scaling to 0..1 results in loss of precision, this DOES NOT work with any amount of accuracy!
    68.              * light_position_texture.SetPixel(i + 1, 0, new Color(light_position.x, light_position.y, light_position.z, distance));
    69.              */
    70.         }
    71.  
    72.         light_position_texture.Apply ();
    73.        
    74.         Shader.SetGlobalTexture ("_LightPositionTexture", light_position_texture);
    75.     }
    76. }
    77.  
    Retrieving the info from the texture in CG:
    Code (CSharp):
    1.  
    2. sampler2D _LightPositionTexture;
    3.  
    4. float LightPositionsSize() {
    5.     return DecodeFloatRGBA(tex2D(_LightPositionTexture, float2(0.0, 0.0))) * _ProjectionParams.z;
    6. }
    7.  
    8. float3 LightPositionAt(int i) {
    9.     float size = LightPositionsSize();
    10.  
    11.     float xd = DecodeFloatRGBA(tex2D(_LightPositionTexture, float2((float)(i * 4 + 1) / size, 0.0)));
    12.     float yd = DecodeFloatRGBA(tex2D(_LightPositionTexture, float2((float)(i * 4 + 2) / size, 0.0)));
    13.     float zd = DecodeFloatRGBA(tex2D(_LightPositionTexture, float2((float)(i * 4 + 3) / size, 0.0)));
    14.     float wd = DecodeFloatRGBA(tex2D(_LightPositionTexture, float2((float)(i * 4 + 4) / size, 0.0)));
    15.    
    16.     return _WorldSpaceCameraPos + float3(xd, yd, zd) * wd * _ProjectionParams.z;
    17. }
    If someone could get this to work that would be great.
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Why not just use an RGBAHalf texture? Or if you're doing this for desktop you can use structured buffers.
     
  11. Nabbz0rz

    Nabbz0rz

    Joined:
    May 5, 2013
    Posts:
    8
    Compute buffers would make much more sense of this problem. I suppose that's an indication that I need a card newer than my rusty Radeon 5770.

    Thanks for the suggestions.