using System;
using System.IO;
using Unity.Collections;
using UnityEngine.Assertions;
using UnityEngine.Experimental.Rendering;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.Rendering.HighDefinition
{
internal static partial class HDTextureUtilities
{
public static void WriteTextureToDisk(Texture target, string filePath)
{
var rt = target as RenderTexture;
var cube = target as Cubemap;
if (rt != null)
{
var t2D = RenderTextureToTexture(rt) as Texture2D;
var bytes = t2D.EncodeToEXR(Texture2D.EXRFlags.CompressZIP);
HDBakingUtilities.CreateParentDirectoryIfMissing(filePath);
File.WriteAllBytes(filePath, bytes);
return;
}
else if (cube != null)
{
var t2D = new Texture2D(cube.width * 6, cube.height, GraphicsFormat.R16G16B16A16_SFloat, TextureCreationFlags.None);
var cmd = new CommandBuffer { name = "CopyCubemapToTexture2D" };
for (int i = 0; i < 6; ++i)
{
cmd.CopyTexture(
cube, i, 0, 0, 0, cube.width, cube.height,
t2D, 0, 0, cube.width * i, 0
);
}
Graphics.ExecuteCommandBuffer(cmd);
var bytes = t2D.EncodeToEXR(Texture2D.EXRFlags.CompressZIP);
HDBakingUtilities.CreateParentDirectoryIfMissing(filePath);
File.WriteAllBytes(filePath, bytes);
return;
}
throw new ArgumentException();
}
// Write to disk via the Unity Asset Pipeline rather than File.WriteAllBytes.
public static void WriteTextureToAsset(Texture target, string filePath)
{
#if UNITY_EDITOR
var rt = target as RenderTexture;
if (rt == null)
return;
HDBakingUtilities.CreateParentDirectoryIfMissing(filePath);
AssetDatabase.CreateAsset(RenderTextureToTexture(rt), filePath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
#endif
}
///
/// Export a render texture to a texture2D/3D.
///
///
/// - Cubemap will be exported in a Texture2D of size (size * 6, size) and with a layout +X,-X,+Y,-Y,+Z,-Z
/// - Texture2D will be copied to a Texture2D
///
///
///
/// The copied texture.
public static Texture2D CopyRenderTextureToTexture2D(RenderTexture source)
{
Assert.IsTrue(source.dimension is TextureDimension.Tex2D or TextureDimension.Cube);
return (Texture2D)RenderTextureToTexture(source);
}
private static Texture RenderTextureToTexture(RenderTexture source)
{
GraphicsFormat format = source.graphicsFormat;
switch (source.dimension)
{
case TextureDimension.Cube:
{
var resolution = source.width;
var result = RenderTexture.GetTemporary(resolution * 6, resolution, 0, source.format);
var cmd = new CommandBuffer();
for (var i = 0; i < 6; ++i)
cmd.CopyTexture(source, i, 0, 0, 0, resolution, resolution, result, 0, 0, i * resolution, 0);
Graphics.ExecuteCommandBuffer(cmd);
var t2D = new Texture2D(resolution * 6, resolution, format, TextureCreationFlags.None);
var a = RenderTexture.active;
RenderTexture.active = result;
t2D.ReadPixels(new Rect(0, 0, 6 * resolution, resolution), 0, 0, false);
RenderTexture.active = a;
RenderTexture.ReleaseTemporary(result);
return t2D;
}
case TextureDimension.Tex2D:
{
var resolution = source.width;
var result = new Texture2D(resolution, resolution, format, TextureCreationFlags.None);
Graphics.SetRenderTarget(source, 0);
result.ReadPixels(new Rect(0, 0, resolution, resolution), 0, 0);
result.Apply();
Graphics.SetRenderTarget(null);
return result;
}
case TextureDimension.Tex3D:
{
var result = new Texture3D(source.width, source.height, source.volumeDepth, format, TextureCreationFlags.None);
// Determine the number of bytes elements that need to be read based on the texture format.
int stagingMemorySize = (int)GraphicsFormatUtility.GetBlockSize(format) * (source.width * source.height * source.volumeDepth);
// Staging memory for the readback.
var stagingReadback = new NativeArray(stagingMemorySize, Allocator.Persistent);
// Async-readbacks do not work if the RT resource is not registered with the graphics API backend.
Assert.IsTrue(source.IsCreated());
// Request and wait for the GPU data to transfer into staging memory.
var request = AsyncGPUReadback.RequestIntoNativeArray(ref stagingReadback, source, 0, format);
request.WaitForCompletion();
// Finally transfer the staging memory into the texture asset.
result.SetPixelData(stagingReadback, 0);
// Free the staging memory.
stagingReadback.Dispose();
return result;
}
default:
throw new ArgumentException();
}
}
}
}