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

Question Vertex Position Using RGB Texture

Discussion in 'Shaders' started by darkwingfart, Aug 24, 2021.

  1. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    I'm trying to remove SkinnedMeshRenderers in my game since I would like large crowds. I thought the best way to do this would be to use a shader to do my animations.

    So to set this up:
    I have animation data saved in an exr. The width of the texture is the vertex count, the height is the animation frame count. RGB = XYZ.
    Vertex index data is stored in UV1.

    I'm close. So close. But something is obviously wrong. I can see the animation but the rotation is wrong and most of the model is flat.


    Here are my texture settings.
    upload_2021-8-24_8-5-38.png

    My shader is very simple. I'm not great with shaders.

    Code (CSharp):
    1. Shader "Custom/VertexPosition" {
    2.     Properties{
    3.         _Frame("Current Frame", Int) = 0
    4.         _Width("Width", Int) = 0
    5.         _Height("Height", Int) = 0
    6.         _MainTex("Color (RGB)", 2D) = "white" {}
    7.         _VertTex("Position (RGB)", 2D) = "white" {}
    8.     }
    9.         SubShader{
    10.             Tags { "RenderType" = "Opaque" }
    11.             LOD 200
    12.  
    13.             CGPROGRAM
    14.             #pragma surface surf Lambert vertex:vert
    15.             uint _Frame;
    16.             uint _Width;
    17.             uint _Height;
    18.             sampler2D _MainTex;
    19.             sampler2D _VertTex;
    20.  
    21.             struct Input {
    22.                 float2 uv_MainTex : TEXCOORD0;
    23.             };
    24.  
    25.             void vert(inout appdata_full v) {
    26.                 float _x = 1 / (float)_Width * v.texcoord1.x;
    27.                 float _y = 1 / (float)_Height * _Frame;
    28.  
    29.                 float3 position = (float3)tex2Dlod(_VertTex, float4(_x, _y, 0, 0));
    30.                 #if UNITY_COLORSPACE_GAMMA
    31.                                 position = pow(position, float3(2.2, 2.2, 2.2));
    32.                 #endif
    33.  
    34.                 //center?
    35.                 position -= float3(0.5, 0.5, 0.5);
    36.  
    37.                 v.vertex.xyz = position;
    38.                 //v.vertex.xyz = UnityObjectToClipPos(v.vertex.xyz);
    39.             }
    40.  
    41.             void surf(Input IN, inout SurfaceOutput o) {
    42.  
    43.                 half4 c = tex2D(_MainTex, IN.uv_MainTex);
    44.                 o.Albedo = c.rgb;
    45.                 o.Alpha = c.a;
    46.             }
    47.  
    48.            
    49.             ENDCG
    50.         }
    51.         FallBack "Diffuse"
    52. }
     
  2. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    So I've found out that my texture is being clamped. The correct RGB values are written, but the values I've read are incorrect. No negative numbers are being read from the texture.
     
    Last edited: Aug 25, 2021
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    By chance is your project's color space set to Gamma? It's a long time issue with Unity they keep marking as working as intended. :(
     
    hippocoder and april_4_short like this.
  4. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    I'm correcting for gamma when I pull the data from the texture. It's definitely a problem with encoding to EXR. It throws away any negative value making them 0.
     
  5. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    By the way, thanks for all you do in this forum man. You're a F***ing saint with the amount of help you give people.
     
    Anhorse and april_4_short like this.
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Unity changes how it reads exr and hdr files when using a gamma color space protect. It clamps the values to >= 0.0 and applies a gamma curve, which is what you're trying to correct for. They do not have an option to disable this behavior. You have to change the project to linear space, or write your own exr file importer to store them as .asset files.
     
    AcidArrow and april_4_short like this.
  7. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    Does being in gamma color space change how the data is written or read or both?

    For example... could I create a separate project in linear color space where I make the animation textures and save them without truncation, and then use them in a gamma colorspace project?

    Edit: Answered this myself. Converted to linear color space. It works perfectly. Wrote the data to EXR and replayed the animation. Swapped back to gamma color space and the data it reads is truncated making my model flat. Swapped back again to linear and the animation plays properly again.
     
    Last edited: Aug 25, 2021
  8. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    Man switching to linear color space really does "just work".

    I just wonder what happens when I run this on a platform that doesn't support linear color space.

    I also don't want to switch over to a linear color space just for this. I suppose I'll look into saving it as an asset like you suggested.
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    And yes, you can create a project to import them into and save them as an asset from. You need a script to copy the imported Texture2D to a new Texture2D that you save as an .asset file for that to work. But once you do the data won’t be modified.
     
  10. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    Since I'm just storing data I've come up with a pretty damn simple idea. I'll just add a fixed number to my values that is > my smallest negative value.
    I can't imagine an animation having vertex coordinates > say 65535/2.
    Then I'll just subtract that same amount for the real vertex position.

    Edit: I guess you really are limited to 0-255 period without more work.
     
    Last edited: Aug 25, 2021
  11. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    Sooooo.... any examples of this saving as an asset thing? And how am I going to get my texture out of the asset to use with my shader? I'm guessing I have to just save some object with an array of vectors and build the image on play.
     
    Last edited: Aug 25, 2021
  12. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    Just create a new Texture2D and us ethe editor APIs to save it to an asset. You can then use it directly in your materials as a texture.
     
  13. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    Thats... very easy. Thanks alot LOL
     
  14. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Make sure the import settings for the texture you want to copy has “Read/Write Enabled” enabled.

    Then in a c# script, create a new
    Texture2D
    with the same size and format as that texture, no mipmaps, linear.

    https://docs.unity3d.com/ScriptReference/Texture2D-ctor.html


    Copy the contents of the first texture to the new one using
    Graphics.CopyTexture()
    .
    https://docs.unity3d.com/ScriptReference/Graphics.CopyTexture.html

    Then save the new texture to disk as a .asset with this function.
    https://docs.unity3d.com/ScriptReference/AssetDatabase.CreateAsset.html
     
  15. darkwingfart

    darkwingfart

    Joined:
    Oct 13, 2018
    Posts:
    78
    With the way Unity handles these EXRs I feel like this should be the default behavior or a checkbox at least. If they can't leave the data alone they should just import them as assets.
     
  16. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    The current behavior is to make HDR images, most commonly used for skyboxes, work properly in both gamma and linear color space. And that it does quite effectively.

    It’s not that the “create an asset” behavior should be an option, textures are already imported as assets. Unity just never included an option to not modify HDR images on import when using gamma color space. When using linear color space, the images are not modified on import at all.

    For non-hdr images, the data held inside them actually modified between linear and gamma color space. Instead what changes is how the GPU interprets the data. When using linear color space, the GPU can automatically covert the gamma space color data held inside to linear space when reading a texture in a shader. And when using gamma color space the textures are simply read as they are.

    On the other hand HDR textures are assumed to always be linear space data, which they usually are. However there’s also no equivalent hardware functionality for converting linear color data to gamma color space when reading the texture in a shader. Floating point textures used for HDR data are always read by the GPU unmodified. So Unity is directly modifying the data that’s stored in the texture to correct for the color space change.

    Many of us have been asking Unity to use the sRGB import flag to toggle this behavior. Currently it controls if a non-HDR texture gets the color space conversion applied or not by the GPU, which internally isn’t modifying the texture data, only setting a flag for the GPU to do the conversion. But it’d be nice if it also disabled the modification of HDR image data for cases like this.