// Update one custom render texture. public static void UpdateCustomRenderTexture(CommandBuffer cmd, CustomRenderTexture crt) { bool firstPass = crt.updateCount == 0; // Handle initialization here too: if (crt.initializationMode == CustomRenderTextureUpdateMode.Realtime || needsInitialization.Contains(crt) || (firstPass && crt.initializationMode == CustomRenderTextureUpdateMode.OnLoad)) { switch (crt.initializationSource) { case CustomRenderTextureInitializationSource.Material: // TODO break; case CustomRenderTextureInitializationSource.TextureAndColor: // TODO break; } needsInitialization.Remove(crt); } needsUpdate.TryGetValue(crt, out int updateCount); if (crt.material != null && (crt.updateMode == CustomRenderTextureUpdateMode.Realtime || updateCount > 0 || (firstPass && crt.updateMode == CustomRenderTextureUpdateMode.OnLoad))) { onBeforeCustomTextureUpdated?.Invoke(cmd, crt); #if CUSTOM_TEXTURE_PROFILING customRenderTextureSamplers.TryGetValue(crt, out var sampler); if (sampler == null) { sampler = customRenderTextureSamplers[crt] = CustomSampler.Create($"{crt.name} - {crt.GetInstanceID()}", true); sampler.GetRecorder().enabled = true; } cmd.BeginSample(sampler); #endif // using (new ProfilingScope(cmd, new ProfilingSampler($"Update {crt.name}"))) { updateCount = Mathf.Max(updateCount, 1); crtExecInfo.TryGetValue(crt, out var execInfo); if (execInfo != null && execInfo.runOnAllMips) { for (int mipLevel = 0; mipLevel < crt.mipmapCount; mipLevel++) { UpdateCustomRenderTexture(cmd, crt, updateCount, mipLevel: mipLevel); } } else { UpdateCustomRenderTexture(cmd, crt, updateCount); } needsUpdate.Remove(crt); } #if CUSTOM_TEXTURE_PROFILING cmd.EndSample(sampler); #endif crt.IncrementUpdateCount(); } }
private static void SaveToDisk(MenuCommand command) { CustomRenderTexture customRenderTexture = command.context as CustomRenderTexture; int width = customRenderTexture.width; int height = customRenderTexture.height; int volumeDepth = customRenderTexture.volumeDepth; bool flag = RenderTextureEditor.IsHDRFormat(customRenderTexture.format); bool flag2 = customRenderTexture.format == RenderTextureFormat.ARGBFloat || customRenderTexture.format == RenderTextureFormat.RFloat; TextureFormat format = (!flag) ? TextureFormat.RGBA32 : TextureFormat.RGBAFloat; int width2 = width; if (customRenderTexture.dimension == TextureDimension.Tex3D) { width2 = width * volumeDepth; } else if (customRenderTexture.dimension == TextureDimension.Cube) { width2 = width * 6; } Texture2D texture2D = new Texture2D(width2, height, format, false); if (customRenderTexture.dimension == TextureDimension.Tex2D) { Graphics.SetRenderTarget(customRenderTexture); texture2D.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0); texture2D.Apply(); } else if (customRenderTexture.dimension == TextureDimension.Tex3D) { int num = 0; for (int i = 0; i < volumeDepth; i++) { Graphics.SetRenderTarget(customRenderTexture, 0, CubemapFace.Unknown, i); texture2D.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), num, 0); texture2D.Apply(); num += width; } } else { int num2 = 0; for (int j = 0; j < 6; j++) { Graphics.SetRenderTarget(customRenderTexture, 0, (CubemapFace)j); texture2D.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), num2, 0); texture2D.Apply(); num2 += width; } } byte[] bytes; if (flag) { bytes = texture2D.EncodeToEXR(Texture2D.EXRFlags.CompressZIP | ((!flag2) ? Texture2D.EXRFlags.None : Texture2D.EXRFlags.OutputAsFloat)); } else { bytes = texture2D.EncodeToPNG(); } UnityEngine.Object.DestroyImmediate(texture2D); string extension = (!flag) ? "png" : "exr"; string directoryName = Path.GetDirectoryName(AssetDatabase.GetAssetPath(customRenderTexture.GetInstanceID())); string text = EditorUtility.SaveFilePanel("Save Custom Texture", directoryName, customRenderTexture.name, extension); if (!string.IsNullOrEmpty(text)) { File.WriteAllBytes(text, bytes); AssetDatabase.Refresh(); } }
static void SaveToDisk(MenuCommand command) { CustomRenderTexture texture = command.context as CustomRenderTexture; int width = texture.width; int height = texture.height; int depth = texture.volumeDepth; // This has its TextureFormat helper equivalent in C++ but since we are going to try to refactor TextureFormat/RenderTextureFormat into a single type so let's not bloat Scripting APIs with stuff that will get useless soon(tm). bool isFormatHDR = GraphicsFormatUtility.IsIEEE754Format(texture.graphicsFormat); bool isFloatFormat = GraphicsFormatUtility.IsFloatFormat(texture.graphicsFormat); TextureFormat format = isFormatHDR ? TextureFormat.RGBAFloat : TextureFormat.RGBA32; int finalWidth = width; if (texture.dimension == UnityEngine.Rendering.TextureDimension.Tex3D) { finalWidth = width * depth; } else if (texture.dimension == UnityEngine.Rendering.TextureDimension.Cube) { finalWidth = width * 6; } Texture2D tex = new Texture2D(finalWidth, height, format, false); // Read screen contents into the texture if (texture.dimension == UnityEngine.Rendering.TextureDimension.Tex2D) { Graphics.SetRenderTarget(texture); tex.ReadPixels(new Rect(0, 0, width, height), 0, 0); tex.Apply(); } else if (texture.dimension == UnityEngine.Rendering.TextureDimension.Tex3D) { int offset = 0; for (int i = 0; i < depth; ++i) { Graphics.SetRenderTarget(texture, 0, CubemapFace.Unknown, i); tex.ReadPixels(new Rect(0, 0, width, height), offset, 0); tex.Apply(); offset += width; } } else { int offset = 0; for (int i = 0; i < 6; ++i) { Graphics.SetRenderTarget(texture, 0, (CubemapFace)i); tex.ReadPixels(new Rect(0, 0, width, height), offset, 0); tex.Apply(); offset += width; } } // Encode texture into PNG byte[] bytes = null; if (isFormatHDR) { bytes = tex.EncodeToEXR(Texture2D.EXRFlags.CompressZIP | (isFloatFormat ? Texture2D.EXRFlags.OutputAsFloat : 0)); } else { bytes = tex.EncodeToPNG(); } Object.DestroyImmediate(tex); var extension = isFormatHDR ? "exr" : "png"; var directory = Path.GetDirectoryName(AssetDatabase.GetAssetPath(texture.GetInstanceID())); string assetPath = EditorUtility.SaveFilePanel("Save Custom Render Texture", directory, texture.name, extension); if (!string.IsNullOrEmpty(assetPath)) { File.WriteAllBytes(assetPath, bytes); AssetDatabase.Refresh(); } }
// Update one custom render texture. public static void UpdateCustomRenderTexture(CommandBuffer cmd, CustomRenderTexture crt) { bool firstPass = crt.updateCount == 0; // Handle initialization here too: if (crt.initializationMode == CustomRenderTextureUpdateMode.Realtime || needsInitialization.Contains(crt) || (firstPass && crt.initializationMode == CustomRenderTextureUpdateMode.OnLoad)) { switch (crt.initializationSource) { case CustomRenderTextureInitializationSource.Material: // TODO break; case CustomRenderTextureInitializationSource.TextureAndColor: // TODO break; } needsInitialization.Remove(crt); } needsUpdate.TryGetValue(crt, out int updateCount); if (crt.material != null && (crt.updateMode == CustomRenderTextureUpdateMode.Realtime || updateCount > 0 || (firstPass && crt.updateMode == CustomRenderTextureUpdateMode.OnLoad))) { onBeforeCustomTextureUpdated?.Invoke(cmd, crt); #if CUSTOM_TEXTURE_PROFILING customRenderTextureSamplers.TryGetValue(crt, out var sampler); if (sampler == null) { sampler = customRenderTextureSamplers[crt] = CustomSampler.Create($"{crt.name} - {crt.GetInstanceID()}", true); sampler.GetRecorder().enabled = true; } cmd.BeginSample(sampler); #endif using (new ProfilingScope(cmd, new ProfilingSampler($"Update {crt.name}"))) { // Prepare "self" texture for reading in the shader for double buffered custom textures RenderTexture textureSelf2D = null; RenderTexture textureSelf3D = null; RenderTexture textureSelfCube = null; if (crt.doubleBuffered) { if (crt.dimension == TextureDimension.Tex2D) { textureSelf2D = crt; } if (crt.dimension == TextureDimension.Cube) { textureSelfCube = crt; } if (crt.dimension == TextureDimension.Tex3D) { textureSelf3D = crt; } } if (crt.doubleBuffered) { // Update the internal double buffered render texture (resize / alloc / ect.) crt.EnsureDoubleBufferConsistency(); } MaterialPropertyBlock block = new MaterialPropertyBlock(); // If the user didn't called the update on CRT, we still process it because it's realtime updateCount = Mathf.Max(updateCount, 1); for (int i = 0; i < updateCount; i++) { // TODO: cache everything List <CustomRenderTextureUpdateZone> updateZones = new List <CustomRenderTextureUpdateZone>(); crt.GetUpdateZones(updateZones); if (updateZones.Count == 0) { updateZones.Add(new CustomRenderTextureUpdateZone { needSwap = false, updateZoneCenter = new Vector3(0.5f, 0.5f, 0.5f), updateZoneSize = Vector3.one, rotation = 0, passIndex = 0 }); } foreach (var zone in updateZones) // int sliceCount = GetSliceCount(crt); // for (int slice = 0; slice < sliceCount; slice++) { var zoneCenters = updateZones.Select(z => new Vector4(z.updateZoneCenter.x, z.updateZoneCenter.y, z.updateZoneCenter.z, 0)).ToList(); var zoneSizesAndRotation = updateZones.Select(z => new Vector4(z.updateZoneSize.x, z.updateZoneSize.y, z.updateZoneSize.z, z.rotation)).ToList(); var zonePrimitiveIDs = Enumerable.Range(0, updateZones.Count).Select(j => (float)j).ToList();// updateZones.Select(z => 0.0f).ToList(); int sliceCount = GetSliceCount(crt); // Copy all the slices in case the texture is double buffered if (zone.needSwap) { var doubleBuffer = crt.GetDoubleBufferRenderTexture(); if (doubleBuffer != null) { // For now, it's just a copy, once we actually do the swap of pointer, be careful to reset the Active Render Texture for (int slice = 0; slice < sliceCount; slice++) { cmd.CopyTexture(doubleBuffer, slice, crt, slice); } } } // foreach (var zone in updateZones) for (int slice = 0; slice < sliceCount; slice++) { RenderTexture renderTexture = crt.doubleBuffered ? crt.GetDoubleBufferRenderTexture() : crt; cmd.SetRenderTarget(renderTexture, 0, (crt.dimension == TextureDimension.Cube) ? (CubemapFace)slice : 0, (crt.dimension == TextureDimension.Tex3D) ? slice : 0); cmd.SetViewport(new Rect(0, 0, crt.width, crt.height)); block.SetVector(kCustomRenderTextureInfo, GetTextureInfos(crt, slice)); block.SetVector(kCustomRenderTextureParameters, GetTextureParameters(crt, slice)); if (textureSelf2D != null) { block.SetTexture(kSelf2D, textureSelf2D); } if (textureSelf3D != null) { block.SetTexture(kSelf3D, textureSelf3D); } if (textureSelfCube != null) { block.SetTexture(kSelfCube, textureSelfCube); } int passIndex = zone.passIndex == -1 ? 0 : zone.passIndex; block.SetVectorArray(kUpdateDataCenters, zoneCenters); block.SetVectorArray(kUpdateDataSizesAndRotation, zoneSizesAndRotation); block.SetFloatArray(kUpdateDataPrimitiveIDs, zonePrimitiveIDs); cmd.DrawProcedural(Matrix4x4.identity, crt.material, passIndex, MeshTopology.Triangles, 6 * updateZones.Count, 1, block); } } } needsUpdate.Remove(crt); } #if CUSTOM_TEXTURE_PROFILING cmd.EndSample(sampler); #endif crt.IncrementUpdateCount(); } }