Search Unity

3D Textures from Compute Shader

Discussion in 'General Graphics' started by themdubs, Jun 20, 2017.

  1. themdubs

    themdubs

    Joined:
    Jan 12, 2014
    Posts:
    26
    I'm trying to do an implementation of Worley noise for a volumetric cloud renderer, I've tried to generate the noise textures through a script however it doesn't quite live up to expectations. As seen below
    3D Worley - 3D Texture Implementation:

    2D Worley - 2D Texture Implementation:


    I have very little experience in noise generation so I based my code off of this wonderful github repo https://github.com/Erkaman/glsl-worley As a result my code may just be completely wrong. Anybody have any clue as to what may be the missing part or does it just need to be calculated and rendered out in a shader instead.

    Code (CSharp):
    1. public class NoiseGenerator : MonoBehaviour {
    2.     public Texture3D Tex1_3D;
    3.     public Texture3D Tex2_3D;
    4.     public Texture2D Tex3_2D;
    5.  
    6.     public float noiseScale = 5f;
    7.     public float jitterScale = 1f;
    8.     public bool manhattanDistance = false;
    9.  
    10.  
    11.     public int tex1Res = 128;
    12.     public int tex2Res = 32;
    13.     public int tex3Res = 128;
    14.  
    15.     public void GenTex1()
    16.     {
    17.         Tex1_3D = new Texture3D(tex1Res, tex1Res, tex1Res, TextureFormat.ARGB32, true);
    18.         var cols = new Color[tex1Res * tex1Res * tex1Res];
    19.         Color c = Color.white;
    20.         int index = 0;
    21.         for(int k=0; k<tex1Res; k++) //w
    22.         {
    23.             for(int j=0; j < tex1Res; j++) //v
    24.             {
    25.                 for(int i=0; i < tex1Res; index++, i++)//u
    26.                 {
    27.                     Vector3 pos = new Vector3(i, j, k) * noiseScale;
    28.                     Vector2 worley = Worley3D(pos, jitterScale, manhattanDistance);
    29.                     float worl = worley.y - worley.x;
    30.                     c.r = worl; c.g = worl; c.b = worl;
    31.                     cols[index] = c;
    32.                 }
    33.             }
    34.         }
    35.         Tex1_3D.SetPixels(cols);
    36.         Tex1_3D.Apply();
    37.         //GetComponent<Renderer>().sharedMaterial.SetTexture("_MainTex", Tex1_3D);
    38.     }
    39.  
    40.     public void GenTex2()
    41.     {
    42.         for (int k = 0; k < tex2Res; k++) //w
    43.         {
    44.             for (int j = 0; j < tex2Res; j++) //v
    45.             {
    46.                 for (int i = 0; i < tex1Res; i++)//u
    47.                 {
    48.  
    49.                 }
    50.             }
    51.         }
    52.     }
    53.     public void GenTex3()
    54.     {
    55.         Tex3_2D = new Texture2D(tex3Res, tex3Res, TextureFormat.ARGB32, true);
    56.         var cols = new Color[tex3Res * tex3Res];
    57.         int index = 0;
    58.         Color c = Color.white;
    59.         for (int j = 0; j < tex3Res; j++) //v
    60.         {
    61.             for (int i = 0; i < tex3Res; index++, i++) //u
    62.             {
    63.                 Vector2 pos = new Vector2(i, j) * noiseScale;
    64.                 Vector2 worley = Worley(pos, jitterScale, manhattanDistance);
    65.                 float worl = worley.y - worley.x;
    66.                 //worl = 1f - worl; //invert the range
    67.                 c.r = worl; c.g = worl; c.b = worl;
    68.                 cols[index] = c;
    69.             }
    70.         }
    71.         Tex3_2D.SetPixels(cols);
    72.         Tex3_2D.Apply();
    73.         GetComponent<Renderer>().sharedMaterial.SetTexture("_MainTex", Tex3_2D);
    74.     }
    75.  
    76.     Vector3 v3SubF(Vector3 v, float val)
    77.     {
    78.         return v - new Vector3(val, val, val);
    79.     }
    80.  
    81.     Vector3 v3AddF(Vector3 v, float val)
    82.     {
    83.         return v + new Vector3(val, val, val);
    84.     }
    85.  
    86.     Vector3 v3MultV3(Vector3 v, Vector3 w)
    87.     {
    88.         return new Vector3(v.x * w.x, v.y * w.y, v.z * w.z);
    89.     }
    90.  
    91.     Vector3 v3Mod(Vector3 v, float val)
    92.     {
    93.         return new Vector3(v.x % val, v.y % val, v.z % val);
    94.     }
    95.  
    96.     Vector3 v3Floor(Vector3 v)
    97.     {
    98.         return new Vector3(Mathf.Floor(v.x), Mathf.Floor(v.y), Mathf.Floor(v.z));
    99.     }
    100.    
    101.     Vector3 v3Abs(Vector3 v)
    102.     {
    103.         return new Vector3(Mathf.Abs(v.x), Mathf.Abs(v.y), Mathf.Abs(v.z));
    104.     }
    105.  
    106.     Vector3 v3Fract(Vector3 v)
    107.     {
    108.         return new Vector3(v.x - Mathf.Floor(v.x), v.y - Mathf.Floor(v.y), v.y - Mathf.Floor(v.y));
    109.     }
    110.  
    111.     Vector3 v3Perm(Vector3 v)
    112.     {
    113.         return v3Mod(v3MultV3(v3AddF(34f * v, 1f),v), 289f);
    114.     }
    115.  
    116.     Vector3 dist(Vector3 x, Vector3 y, Vector3 z, bool manhattanDistance)
    117.     {
    118.         return manhattanDistance ? v3Abs(x) + v3Abs(y) + v3Abs(z) : (v3MultV3(x, x) + v3MultV3(y,y) + v3MultV3(z, z));
    119.     }
    120.  
    121.     Vector3 dist(Vector3 x, Vector3 y, bool manhattanDistance)
    122.     {
    123.         return manhattanDistance ? v3Abs(x) + v3Abs(y) : (v3MultV3(x, x) + v3MultV3(y, y));
    124.     }
    125.  
    126.  
    127.     Vector2 Worley3D(Vector3 P, float jitter, bool manhattanDistance)
    128.     {
    129.         float K = 0.142857142857f; // 1/7
    130.         float Ko = 0.428571428571f; // 1/2-K/2
    131.         float K2 = 0.020408163265306f; // 1/(7*7)
    132.         float Kz = 0.166666666667f; // 1/6
    133.         float Kzo = 0.416666666667f; // 1/2-1/6*2
    134.  
    135.         Vector3 Pi = v3Mod(v3Floor(P), 289f);
    136.         Vector3 Pf = v3SubF(v3Fract(P), 0.5f);
    137.  
    138.         Vector3 Pfx = v3AddF(new Vector3(1f, 0f, -1f), Pf.x);
    139.         Vector3 Pfy = v3AddF(new Vector3(1f, 0f, -1f), Pf.y);
    140.         Vector3 Pfz = v3AddF(new Vector3(1f, 0f, -1f), Pf.z);
    141.  
    142.         Vector3 p = v3Perm(v3AddF(new Vector3(-1f, 0f, 1f), Pi.x));
    143.         Vector3 p1 = v3Perm(v3AddF(p, Pi.y - 1f));
    144.         Vector3 p2 = v3Perm(v3AddF(p, Pi.y));
    145.         Vector3 p3 = v3Perm(v3AddF(p, Pi.y + 1f));
    146.  
    147.         Vector3 p11 = v3Perm(v3AddF(p1, Pi.z - 1f));
    148.         Vector3 p12 = v3Perm(v3AddF(p1, Pi.z));
    149.         Vector3 p13 = v3Perm(v3AddF(p1, Pi.z + 1f));
    150.  
    151.         Vector3 p21 = v3Perm(v3AddF(p2, Pi.z - 1f));
    152.         Vector3 p22 = v3Perm(v3AddF(p2, Pi.z));
    153.         Vector3 p23 = v3Perm(v3AddF(p2, Pi.z + 1f));
    154.  
    155.         Vector3 p31 = v3Perm(v3AddF(p3, Pi.z - 1f));
    156.         Vector3 p32 = v3Perm(v3AddF(p3, Pi.z));
    157.         Vector3 p33 = v3Perm(v3AddF(p3, Pi.z + 1f));
    158.  
    159.         Vector3 ox11 = v3SubF(v3Fract(p11 * K), Ko);
    160.         Vector3 oy11 = v3SubF(v3Mod(v3Floor(p11 * K), 7f) * K, Ko);
    161.         Vector3 oz11 = v3SubF(v3Floor(p11 * K2) * Kz, Kzo);
    162.  
    163.         Vector3 ox12 = v3SubF(v3Fract(p12 * K), Ko);
    164.         Vector3 oy12 = v3SubF(v3Mod(v3Floor(p12 * K), 7f) * K, Ko);
    165.         Vector3 oz12 = v3SubF(v3Floor(p12 * K2) * Kz, Kzo);
    166.  
    167.         Vector3 ox13 = v3SubF(v3Fract(p13 * K), Ko);
    168.         Vector3 oy13 = v3SubF(v3Mod(v3Floor(p13 * K), 7f) * K, Ko);
    169.         Vector3 oz13 = v3SubF(v3Floor(p13 * K2) * Kz, Kzo);
    170.  
    171.         Vector3 ox21 = v3SubF(v3Fract(p21 * K), Ko);
    172.         Vector3 oy21 = v3SubF(v3Mod(v3Floor(p21 * K), 7f) * K, Ko);
    173.         Vector3 oz21 = v3SubF(v3Floor(p21 * K2) * Kz, Kzo);
    174.  
    175.         Vector3 ox22 = v3SubF(v3Fract(p22 * K), Ko);
    176.         Vector3 oy22 = v3SubF(v3Mod(v3Floor(p22 * K), 7f) * K, Ko);
    177.         Vector3 oz22 = v3SubF(v3Floor(p22 * K2) * Kz, Kzo);
    178.  
    179.         Vector3 ox23 = v3SubF(v3Fract(p23 * K), Ko);
    180.         Vector3 oy23 = v3SubF(v3Mod(v3Floor(p23 * K), 7f) * K, Ko);
    181.         Vector3 oz23 = v3SubF(v3Floor(p23 * K2) * Kz, Kzo);
    182.  
    183.         Vector3 ox31 = v3SubF(v3Fract(p31 * K), Ko);
    184.         Vector3 oy31 = v3SubF(v3Mod(v3Floor(p31 * K), 7f) * K, Ko);
    185.         Vector3 oz31 = v3SubF(v3Floor(p31 * K2) * Kz, Kzo);
    186.  
    187.         Vector3 ox32 = v3SubF(v3Fract(p32 * K), Ko);
    188.         Vector3 oy32 = v3SubF(v3Mod(v3Floor(p32 * K), 7f) * K, Ko);
    189.         Vector3 oz32 = v3SubF(v3Floor(p32 * K2) * Kz, Kzo);
    190.  
    191.         Vector3 ox33 = v3SubF(v3Fract(p33 * K), Ko);
    192.         Vector3 oy33 = v3SubF(v3Mod(v3Floor(p33 * K), 7f) * K, Ko);
    193.         Vector3 oz33 = v3SubF(v3Floor(p33 * K2) * Kz, Kzo);
    194.  
    195.         Vector3 dx11 = Pfx + jitter * ox11;
    196.         Vector3 dy11 = v3AddF(jitter * oy11, Pfy.x);
    197.         Vector3 dz11 = v3AddF(jitter * oz11, Pfz.x);
    198.  
    199.         Vector3 dx12 = Pfx + jitter * ox12;
    200.         Vector3 dy12 = v3AddF(jitter * oy12, Pfy.x);
    201.         Vector3 dz12 = v3AddF(jitter * oz12, Pfz.x);
    202.  
    203.         Vector3 dx13 = Pfx + jitter * ox13;
    204.         Vector3 dy13 = v3AddF(jitter * oy13, Pfy.x);
    205.         Vector3 dz13 = v3AddF(jitter * oz13, Pfz.x);
    206.  
    207.         Vector3 dx21 = Pfx + jitter * ox21;
    208.         Vector3 dy21 = v3AddF(jitter * oy21, Pfy.x);
    209.         Vector3 dz21 = v3AddF(jitter * oz21, Pfz.x);
    210.  
    211.         Vector3 dx22 = Pfx + jitter * ox22;
    212.         Vector3 dy22 = v3AddF(jitter * oy22, Pfy.x);
    213.         Vector3 dz22 = v3AddF(jitter * oz22, Pfz.x);
    214.  
    215.         Vector3 dx23 = Pfx + jitter * ox23;
    216.         Vector3 dy23 = v3AddF(jitter * oy23, Pfy.x);
    217.         Vector3 dz23 = v3AddF(jitter * oz23, Pfz.x);
    218.  
    219.         Vector3 dx31 = Pfx + jitter * ox31;
    220.         Vector3 dy31 = v3AddF(jitter * oy31, Pfy.x);
    221.         Vector3 dz31 = v3AddF(jitter * oz31, Pfz.x);
    222.  
    223.         Vector3 dx32 = Pfx + jitter * ox32;
    224.         Vector3 dy32 = v3AddF(jitter * oy32, Pfy.x);
    225.         Vector3 dz32 = v3AddF(jitter * oz32, Pfz.x);
    226.  
    227.         Vector3 dx33 = Pfx + jitter * ox33;
    228.         Vector3 dy33 = v3AddF(jitter * oy33, Pfy.x);
    229.         Vector3 dz33 = v3AddF(jitter * oz33, Pfz.x);
    230.  
    231.         Vector3 d11 = dist(dx11, dy11, dz11, manhattanDistance);
    232.         Vector3 d12 = dist(dx12, dy12, dz12, manhattanDistance);
    233.         Vector3 d13 = dist(dx13, dy13, dz13, manhattanDistance);
    234.         Vector3 d21 = dist(dx21, dy21, dz21, manhattanDistance);
    235.         Vector3 d22 = dist(dx22, dy22, dz22, manhattanDistance);
    236.         Vector3 d23 = dist(dx23, dy23, dz23, manhattanDistance);
    237.         Vector3 d31 = dist(dx31, dy31, dz31, manhattanDistance);
    238.         Vector3 d32 = dist(dx32, dy32, dz32, manhattanDistance);
    239.         Vector3 d33 = dist(dx33, dy33, dz33, manhattanDistance);
    240.  
    241.         Vector3 d1a = Vector3.Min(d11, d12);
    242.         d12 = Vector3.Max(d11, d12);
    243.         d11 = Vector3.Min(d1a, d13);
    244.         d13 = Vector3.Max(d1a, d13);
    245.         d12 = Vector3.Min(d12, d13);
    246.         Vector3 d2a = Vector3.Min(d21, d22);
    247.         d12 = Vector3.Max(d21, d22);
    248.         d11 = Vector3.Min(d2a, d23);
    249.         d13 = Vector3.Max(d2a, d23);
    250.         d12 = Vector3.Min(d22, d23);
    251.         Vector3 d3a = Vector3.Min(d31, d32);
    252.         d12 = Vector3.Max(d31, d32);
    253.         d11 = Vector3.Min(d3a, d33);
    254.         d13 = Vector3.Max(d3a, d33);
    255.         d12 = Vector3.Min(d32, d33);
    256.         Vector3 da = Vector3.Min(d11, d21);
    257.         d21 = Vector3.Max(d11, d21);
    258.         d11 = Vector3.Min(da, d31);
    259.         d31 = Vector3.Max(da, d31);
    260.         d11.x = (d11.x < d11.y) ? d11.x : d11.y;
    261.         d11.y = (d11.x < d11.y) ? d11.y : d11.x;
    262.         d11.x = (d11.x < d11.z) ? d11.x : d11.z;
    263.         d11.z = (d11.x < d11.z) ? d11.z : d11.x;
    264.         d12 = Vector3.Min(d12, d21);
    265.         d12 = Vector3.Min(d12, d22);
    266.         d12 = Vector3.Min(d12, d31);
    267.         d12 = Vector3.Min(d12, d32);
    268.         d11.y = (d11.y < d12.x) ? d11.y : d12.x;
    269.         d11.z = (d11.z < d12.y) ? d11.z : d12.y;
    270.         d11.y = Mathf.Min(d11.y, d12.z);
    271.         d11.y = Mathf.Min(d11.y, d11.z);
    272.         return new Vector2(Mathf.Sqrt(d11.x), Mathf.Sqrt(d11.y));
    273.     }
    274.  
    275.     Vector2 Worley(Vector2 P, float jitter, bool manhattanDistance)
    276.     {
    277.         float K = 0.142857142857f;
    278.         float Ko = 0.428571428571f;
    279.  
    280.         Vector2 Pi = v3Mod(v3Floor(P), 289f);
    281.         Vector2 Pf = v3Fract(P);
    282.         Vector3 oi = new Vector3(-1f, 0f, 1f);
    283.         Vector3 of = new Vector3(-0.5f, 0.5f, 1.5f);
    284.         Vector3 px = v3Perm(v3AddF(oi, Pi.x));
    285.         Vector3 p = v3Perm(v3AddF(v3AddF(oi, Pi.y), px.x));
    286.         Vector3 ox = v3SubF(v3Fract(p * K), Ko);
    287.         Vector3 oy = v3SubF(v3Mod(v3Floor(p*K),7f)*K,Ko);
    288.         Vector3 dx = v3AddF(jitter * ox, Pf.x + 0.5f);
    289.         Vector3 dy = jitter * oy + v3AddF(-of, Pf.y);
    290.         Vector3 d1 = dist(dx, dy, manhattanDistance);
    291.         p = v3Perm(v3AddF(oi, px.y + Pi.y));
    292.         ox = v3SubF(v3Fract(p*K),Ko);
    293.         oy = v3SubF(v3Mod(v3Floor(p*K),7f)*K,Ko);
    294.         dx = v3AddF(jitter * ox, Pf.x - 0.5f);
    295.         dy = jitter * oy + v3AddF(-of, Pf.y);
    296.         Vector3 d2 = dist(dx, dy, manhattanDistance);
    297.         p = v3Perm(v3AddF(oi, px.z + Pi.y));
    298.         ox = v3SubF(v3Fract(p * K), Ko);
    299.         oy = v3SubF(v3Mod(v3Floor(p * K), 7f) * K, Ko);
    300.         dx = v3AddF(jitter * ox, Pf.x - 1.5f);
    301.         dy = jitter * oy + v3AddF(-of, Pf.y);
    302.         Vector3 d3 = dist(dx, dy, manhattanDistance);
    303.         // Sort out the two smallest distances (F1, F2)
    304.         Vector3 d1a = Vector3.Min(d1, d2);
    305.         d2 = Vector3.Max(d1, d2);
    306.         d2 = Vector3.Min(d2, d3);
    307.         d1 = Vector3.Min(d1a, d2);
    308.         d2 = Vector3.Max(d1a, d2);
    309.         d1 = xySwap(d1);
    310.         d1 = xzSwap(d1);
    311.         d1 = yzMin(d1, d2);
    312.         d1.y = Mathf.Min(d1.y, d1.z);
    313.         d1.y = Mathf.Min(d1.y, d2.x);
    314.         return new Vector2(Mathf.Sqrt(d1.x), Mathf.Sqrt(d1.y));
    315.     }
    316.  
    317.     Vector3 xySwap(Vector3 v)
    318.     {
    319.         if (v.x < v.y)
    320.             return v;
    321.         else
    322.             return new Vector3(v.y, v.x, v.z);
    323.     }
    324.  
    325.     Vector3 xzSwap(Vector3 v)
    326.     {
    327.         if (v.x < v.z)
    328.             return v;
    329.         else
    330.             return new Vector3(v.z, v.y, v.x);
    331.     }
    332.  
    333.     Vector3 yzMin(Vector3 v, Vector3 w)
    334.     {
    335.         Vector2 yz = Vector2.Min(new Vector2(v.y, v.z), new Vector2(w.y, w.z));
    336.         return new Vector3(v.x, yz.x, yz.y);
    337.     }
    338. }
     
  2. themdubs

    themdubs

    Joined:
    Jan 12, 2014
    Posts:
    26
    Good news is that I ended up being able to find a working algorithm that produces Worley noise for a 3d texture. My code from the previous example has pretty much completely changed.



    However in script implementation it is unbelievably slow. I have a button in the inspector which runs the generator and even calculating just one of the channels took around 3 minutes. So I think I'll need to generate it in a shader which will allow the gpu to run it rather than cpu.

    Does anyone have any information on generating textures to be used in shaders, inside a shader? I really only know the function Graphics.blit and even then I just have a very basic understanding of that. I'm more curious of how the framework/pipeline should be setup.
     
  3. themdubs

    themdubs

    Joined:
    Jan 12, 2014
    Posts:
    26
    So good news first, I realized that I needed to be calculating these in a Compute Shader! However I quickly found out that the two 3D textures were not actually rendering out to my 3D Render Textures. I found one forum post here however the sample code is now unreachable :(. I also saw this post about OpenGL which seemed Has anyone had experience with compute shaders rendering to 3D textures?

    Here is part of my code so far:
    Code (CSharp):
    1. void Start()
    2. {
    3.         //Create 3D Render Texture 1
    4.         Tex1_3D = new RenderTexture(tex1Res, tex1Res, 24);
    5.         Tex1_3D.enableRandomWrite = true;
    6.         Tex1_3D.dimension = UnityEngine.Rendering.TextureDimension.Tex3D;
    7.         Tex1_3D.volumeDepth = tex1Res;
    8.         Tex1_3D.Create();
    9.         noise1Gen = noiseCompute.FindKernel("Noise1Gen");
    10.         noiseCompute.SetTexture(noise1Gen, "Noise1", Tex1_3D);
    11. }
    12.  
    13. public void GenTex1()
    14. {
    15.         noiseCompute.Dispatch(noise1Gen, tex1Res / 8, tex1Res / 8, tex1Res / 8);
    16. }
    As far as my compute shader code I'm just trying to render out the color red so its setup sort of like this
    Code (CSharp):
    1. #pragma kernel Noise1Gen
    2. RWTexture3D<float4> Noise1;
    3.  
    4. [numthreads(8,8,8)]
    5. void Noise1Gen(uint3 id : SV_DispatchThreadID)
    6. {
    7.     Noise1[id.xyz] = float4(1, 0, 0, 1);
    8. }
     
    OskarSwierad likes this.
  4. themdubs

    themdubs

    Joined:
    Jan 12, 2014
    Posts:
    26
    So I believe the mistake I was making is that I was simply looking at the rendered 3d texture in the inspector which was not showing its actual colors. To be fair for myself I do this pretty early in the morning :D. Placing the 3D render texture as the main texture in a custom shader got this as a result.

    Which is exactly what I need and also B-E-A-UTIFUL if I say so! If anyone is interested in the noise implemented here its based on and borrowed from this github repo.

    I'm going to keep this thread open to track my progress of developing the cloud renderer from here on out!
     
  5. Gurunext

    Gurunext

    Joined:
    Jan 23, 2013
    Posts:
    9
    I came here to look up how to setup a Texture3D - thanks for the help :3
     
    JSTTSJ likes this.