Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

How to maintain a sequence of Texture3D's in shader and access with indices?

Discussion in 'Shaders' started by ZephyrL, Jul 18, 2019.

  1. ZephyrL


    Jun 17, 2019
    Hi there,

    I'm a bit new to unity shader programming, currently, I want to maintain a realtime Global Distance Field which should be calculated out from all local signed distance field(SDF) data (you can search "SDFr" on Github for the tool). I've already had some baked Texture3D of those local SDF and pass each of them into the shader, now the shader has a number of Texture3D's.

    Since they are local SDF and the global SDF should convert them to the world space, here also pass a StructuredBuffer which contains a sequence of bounding boxes and transformations. Now the method to calculate the global distance at any sample point (regarding one Texture3D) is like:

    Code (CSharp):
    2.             Texture3D _VolumeATex;
    3.             Texture3D _VolumeBTex;
    4. ...
    5. struct SDFrVolumeData
    6. {
    7.     float4x4 WorldToLocal;
    8.     float3 Extents;
    9. };
    10. ...
    11.             StructuredBuffer<SDFrVolumeData> _VolumeBuffer;
    12. ...
    14.             fixed4 frag(...){
    16.                 float temp = 0;
    17.                 float minDistance = LARGE_DISTANCE;
    18.                 // globalPos is current sample position
    19.                 // check if the global position is inside the bounding box
    20.                 if(InsideAABB(globalPos, _VolumeBuffer[0])){
    21.                     // sample the distance from local SDF
    22.                     temp = DistanceFunctionTex3DFast(globalPos, _VolumeBuffer[0], _VolumeATex);
    23.                     distance1 = min(distance1, temp);
    24.                 } else {
    25.                     // otherwise return an approximate distance
    26.                     temp = GlobalDistanceToAABBPlus(globalPos, _VolumeBuffer[0], _VolumeATex);
    27.                     distance1 = min(distance1, temp);
    28.                 }
    29.                 ...
    30.                 // something similar to above for _VolumeBuffer[i] and _Volume[BCD]Tex
    31.            }
    As you could see I have to match up the _VolumeBuffer element with _Volume[x]Tex manually in the shader code, since there isn't something like Texture3Darray currently. I could bear this as now there are only 3 textures and volumes, but it's going to be more and I hope there is a matching method so that I can use for loop and index the textures. Besides, I'm not sure if I can put a Texture3D in the component of StructuredBuffer? Should this be done like storing a pointer to the texture?

    Glad if someone can help with this, many thanks.
    Last edited: Jul 18, 2019
  2. bgolus


    Dec 7, 2012
    You cannot. Structure buffers are limited to numerical data types.

    The answer would be to use a texture 3D atlas. Basically you want an array of 3D textures, which doesn't exist, so you can fake it by having a single 3D texture with multiple objects in it. Can either be an arbitrary 3D atlas, or z stacked. For example imagine you have two SDFs that are both stored in 32^3 textures, you'd store them both in a single 32x32x64 3D texture and store an index or scale & offset in the structured buffer data.
    ZephyrL likes this.
  3. ZephyrL


    Jun 17, 2019
    Thank you very much bgolus!
    This answer is very inspiring and I would try to put multiple texture3d into a single one. After looking up the documentation, I didn't find a way to directly append after texture3d, while I think Graphics.CopyTexture might work for this, I'll come back after trying it out.


    I've tried to use Graphics.CopyTexture to stack the textures into one, but it doesn't work for me, in substitution I use setPixel to copy the texture pixels one by one and call texture.Apply() to pass it to GPU side. It works fine now. I think there might be a way to use ComputeShader to copy more efficiently.
    Last edited: Jul 23, 2019