Search Unity

Looking for a way to pack 4 bytes of color data into a float in shader lab

Discussion in 'Shaders' started by powdered_swords, Jul 9, 2013.

  1. powdered_swords

    powdered_swords

    Joined:
    Mar 11, 2013
    Posts:
    28
    I'm attempting to transfer an array of float values to ShaderLab by packing them into a texture with each byte taking up one color channel. Four channels giving me exactly 32 bits, enough to store a single precision float.

    Here's my implementation of a float to color converter in C#;

    Code (csharp):
    1. float num;
    2. Byte[] b = System.BitConverter.GetBytes(num);
    3.  
    4. Color32 c = new Color(b[0], b[1], b[2], b[3]);
    The only problem is I have no idea how to repack this data in Shaderlab. Most methods I've found in other languages require some form of iteration, I know that's just not feasible in this language. So assuming I can use any Texture Sampler and I already have the correct UV coordinates available, is there any method available to cast this data back into a float?
     
  2. Dolkar

    Dolkar

    Joined:
    Jun 8, 2013
    Posts:
    576
    Use DecodeFloatRGBA in UnityCG.cginc
     
  3. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Here's the full code, along with the comment about limitations:
    Code (csharp):
    1. // Encoding/decoding [0..1) floats into 8 bit/channel RGBA. Note that 1.0 will not be encoded properly.
    2. inline float4 EncodeFloatRGBA( float v )
    3. {
    4.     float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 160581375.0);
    5.     float kEncodeBit = 1.0/255.0;
    6.     float4 enc = kEncodeMul * v;
    7.     enc = frac (enc);
    8.     enc -= enc.yzww * kEncodeBit;
    9.     return enc;
    10. }
    11. inline float DecodeFloatRGBA( float4 enc )
    12. {
    13.     float4 kDecodeDot = float4(1.0, 1/255.0, 1/65025.0, 1/160581375.0);
    14.     return dot( enc, kDecodeDot );
    15. }
     
  4. powdered_swords

    powdered_swords

    Joined:
    Mar 11, 2013
    Posts:
    28
    Thanks I had no idea that function existed!
     
  5. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    It's a very good idea to download the built-in shader source and look through the files you've probably been including. Although it's not very thoroughly documented, a lot of the functions have very clear purposes.
     
  6. powdered_swords

    powdered_swords

    Joined:
    Mar 11, 2013
    Posts:
    28
    Thanks, I had the default shader source but I wasn't aware all the cginc files were included.
     
  7. Marco-Sperling

    Marco-Sperling

    Joined:
    Mar 5, 2012
    Posts:
    620
    Can anyone explain why the fourth float in this line (and any other line where it appears) has a ZERO as its third digit?
    float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 160581375.0);
    255*255*255 should be 16581375, shouldn't it?
     
  8. samizzo

    samizzo

    Joined:
    Sep 7, 2011
    Posts:
    487
    That looks like a typo in the post. In the version of UnityCG.cginc in my version of Unity, there is no zero.
     
  9. TechnoCraft

    TechnoCraft

    Joined:
    Apr 6, 2012
    Posts:
    28
    See attached project (Unity 4.6.1 Free Edition). Not optimized but works as intended.

    Maximum 96 lights (directional, point) for each game object with tag "Dynamic". See script "Custom Shader" attached to "Main Camera". You can combine meshes (not that it makes any performance difference) into one with "Do Combine Meshes". Do Refresh Data Texture" refreshes the data texture and assigns a new material each frame. A simple "CustomShaderEditor" is included to enable display changes in editor. Click "Refresh" button or check "Refresh active" to enable constant update while changing game objects in editor.

    IEEE 754 32bit standard for encoding and decoding floating point values.
    http://www.h-schmidt.net/FloatConverter/IEEE754.html

    C# (CustomShader.cs)
    FloatToColor
    ColorToFloat

    Shader (shCustomBumpedSpecular.shader)
    Color2Float

    The shader function uses to many math instructions to decode a color so that makes it unusable for a game.
     

    Attached Files:

    loganlo4 likes this.
  10. TechnoCraft

    TechnoCraft

    Joined:
    Apr 6, 2012
    Posts:
    28
    See attached project (Unity 4.6.1 Free Edition).

    I optimized encoding and decoding floating points. Ranging from -500.00 to 500.00. Precision loss over performance gain. It is much faster then the original encoding by IEEE 754 standard.

    I noticed an unexpected fps slowdown when I move camera close to an object. It depends on how much of the camera viewport is filled with rendered objects. See attached images. Unity shader (like BumpedSpecular) does not have the same problem. Why does this happen? Can anyone explain?

    Added support for lightmaps and specular highlights when using backed lighting. View CustomShader.jpg for preview.
     

    Attached Files:

    Last edited: Jan 31, 2015
  11. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    What IS this sorcery?! :D

    AMAZING WORK! :) Works beautifully on my school lappy! :)
     
  12. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Also asking: this this actually deferred (i.e. my definition: rendering all lights at once?!)
     
  13. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Ok, confirmed: by looking at you guys source, it might as well be deferred! (well, except for the light limits! :D)

    Because... it appears you guys manage to apply 96 lights in ONE PASS!
     
  14. TechnoCraft

    TechnoCraft

    Joined:
    Apr 6, 2012
    Posts:
    28
    Yes, it does everything in one pass.

    There are limitations and things to consider:
    - Only point and directional lights.
    - You can do more lights by using a larger texture (but why would you want to). If all lights are being rendered the performance drops to about 80fps on my AMD Radeon HD 6800. This can be improved by including only the lights that are "needed" around the main camera. "Light occlusion".
    - Do not resize game objects. Use only 1:1:1 as this causes dynamic resizing and decreases framerate.
    - No dynamic shadows or light cookies. Baked lighting only.
    - No mirror reflections. Only CubeMaps are possible (simple to add them) but they look a bit strange so I don't use them.
    - Shader uses to many instructions. I was targeting 2.0 but it is not possible without the help of UnityPro features or shader engine.
    - probably more things but you get the basic idea ... can be beneficial if used as intended.

    Why performance drops (must be some editor events slowing it down):
    - 2 times slower When "Inspector" window is focused and visible. Compared to when "Lightmapping" window is focused and visible.

    The problem with performance slow down (camera close to game object) is due to active dynamic light calculations being made in the background by Unity. When light rendering is disabled, the framerate remains at expected values (under 0.2ms).

    The solution is to use baked lightmaps or to disable the lights (to stop them from "rendering" in the background):
    Render Mode = Not Important
    Culling Mask = Nothing
    Lightmapping = Baked only

    They will still be rendered dynamically by the custom shader.
     
    Last edited: Feb 7, 2015
  15. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Nice! :)

    Point being, it wouldn't be too hard to add support for shadows! (well, at least Directional light shadows!)

    But then one would be entering dynamic lighting territory... :D
     
  16. TechnoCraft

    TechnoCraft

    Joined:
    Apr 6, 2012
    Posts:
    28
    Added support for dynamic shadows. One directional light to be more precise. See attached project. CustomShaderModel.jpg
     

    Attached Files:

  17. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Mind if I try and improve the shadow filtering? :D Looking good, BTW
     
  18. TechnoCraft

    TechnoCraft

    Joined:
    Apr 6, 2012
    Posts:
    28
    I do not mind. Please do post your improvements here. I will look into soft shadows as they are not (really) enabled in Unity free (at least they do not work in my project). Should be able to soften them up a bit :).
     
  19. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    I have done soft shadows in free version before actually! :)

    Also, how do you sample the shadow map? This will help! :)
     
  20. TechnoCraft

    TechnoCraft

    Joined:
    Apr 6, 2012
    Posts:
    28
    I implemented blur by overlaying shadows by mgear example here. See attached project for more info. Not really what I want but it's a start.
    shadow_overlay.jpg
     

    Attached Files:

  21. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Well! It looks like mgear improved the filtering!

    Last time I saw those, I was the perpetrator, (No joke, I was the one who started that project!) and the lot of us were scratching our heads on how to sample the damn shadows in a custom shader... :D

    EDIT: also noting: I also worked out how to remove haloing in the dynamic soft shadow by not using screenPos and not using ForwardBase pass; it made the shadow projection on PC go completely messed with it on! (Strangely though, such a matrix works ok on mobile WITH ForwardBase on!)
     
    Last edited: Feb 24, 2015