How do I copy a 3D renderTexture (isVolume = true) to a Texture3D object?

How do I copy a 3D renderTexture (isVolume = true) to a Texture3D object?

Is there anyway to use Texture3D ReadPixels method to do that?

I know that is a bit late to answer this, anyway, there we go.

There is a way to do this. The procedure is to slice the 3D RenderTexture into an array of 2D RenderTextures using a compute shader. After that you have to transform that 2D RenderTextures into Texture2D and then fill a Texture3D with the content of the slices.

    RenderTexture Copy3DSliceToRenderTexture(RenderTexture source, int layer)
    {
        RenderTexture render = new RenderTexture(voxelSize, voxelSize, 0, RenderTextureFormat.ARGB32);
        render.dimension = UnityEngine.Rendering.TextureDimension.Tex2D;
        render.enableRandomWrite = true;
        render.wrapMode = TextureWrapMode.Clamp;
        render.Create();

        int kernelIndex = slicer.FindKernel("CSMain");
        slicer.SetTexture(kernelIndex, "voxels", source);
        slicer.SetInt("layer", layer);
        slicer.SetTexture(kernelIndex, "Result", render);
        slicer.Dispatch(kernelIndex, voxelSize, voxelSize, 1);

        return render;
    }

    Texture2D ConvertFromRenderTexture(RenderTexture rt)
    {
        Texture2D output = new Texture2D(voxelSize, voxelSize);
        RenderTexture.active = rt;
        output.ReadPixels(new Rect(0, 0, voxelSize, voxelSize), 0, 0);
        output.Apply();
        return output;
    }

    void Save()
    {
        Texture3D export = new Texture3D(voxelSize, voxelSize, voxelSize, TextureFormat.ARGB32, false);
        RenderTexture selectedRenderTexture;
        if (useA)
            selectedRenderTexture = renderA;
        else
            selectedRenderTexture = renderB;

        RenderTexture[] layers = new RenderTexture[voxelSize];
        for( int i = 0; i < 64; i++)        
            layers *= Copy3DSliceToRenderTexture(selectedRenderTexture, i);*

Texture2D[] finalSlices = new Texture2D[voxelSize];
for ( int i = 0; i < 64; i++)
finalSlices = ConvertFromRenderTexture(layers*);*

Texture3D output = new Texture3D(voxelSize, voxelSize, voxelSize, TextureFormat.ARGB32, true);
output.filterMode = FilterMode.Trilinear;
Color[] outputPixels = output.GetPixels();

for (int k = 0; k < voxelSize; k++) {
Color[] layerPixels = finalSlices[k].GetPixels();
for (int i = 0; i < voxelSize; i++)
for (int j = 0; j < voxelSize; j++)
{
outputPixels[i + j * voxelSize + k * voxelSize * voxelSize] = layerPixels[i + j * voxelSize];
}
}

output.SetPixels(outputPixels);
output.Apply();

AssetDatabase.CreateAsset(output, “Assets/” + nameOfTheAsset + “.asset”);
}
Here is the slicer compute shader:

#pragma kernel CSMain

Texture3D voxels;
RWTexture2D Result;
int layer;

[numthreads(32,32,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
* uint3 pos = uint3(id.x,id.y,layer);*
* Result[id.xy] = voxels[pos];*
}

Sorry for the necro but since this is on top of some google searches about this:

void SaveRT3DToTexture3DAsset(RenderTexture rt3D, string pathWithoutAssetsAndExtension)
{
    int width = rt3D.width, height = rt3D.height, depth = rt3D.volumeDepth;
    var a = new NativeArray<byte>(width * height * depth, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); //change if format is not 8 bits (i was using R8_UNorm) (create a struct with 4 bytes etc)
    AsyncGPUReadback.RequestIntoNativeArray(ref a, rt3D, 0, (_) =>
    {
        Texture3D output = new Texture3D(width, height, depth, rt3D.graphicsFormat, TextureCreationFlags.None);
        output.SetPixelData(a, 0);
        output.Apply(updateMipmaps: false, makeNoLongerReadable: true);
        AssetDatabase.CreateAsset(output, $"Assets/{pathWithoutAssetsAndExtension}.asset");
        AssetDatabase.SaveAssetIfDirty(output);
        a.Dispose();
        rt3D.Release();
    });
}

What happened when you used the ReadPixels function?