Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save haosizheng/ee23b75dac7fb12f02cae55959dad59f to your computer and use it in GitHub Desktop.
Save haosizheng/ee23b75dac7fb12f02cae55959dad59f to your computer and use it in GitHub Desktop.
Save image sequence in Unity with transparent background.
using UnityEngine;
using System.Collections;
using System.IO;
using UnityEngine.Rendering.Universal;
/*
Usage:
1. Attach this script to your chosen camera's game object.
2. Set that camera's Clear Flags field to Solid Color.
3. Use the inspector to set frameRate and framesToCapture
4. Choose your desired resolution in Unity's Game window (must be less than or equal to your screen resolution)
5. Turn on "Maximise on Play"
6. Play your scene. Screenshots will be saved to YourUnityProject/Screenshots by default.
*/
public class ImageSequenceRecorderWithTransparentBackground : MonoBehaviour
{
#region public fields
[Tooltip("A folder will be created with this base name in your project root")]
public string folderBaseName = "Screenshots";
[Tooltip("How many frames should be captured per second of game time")]
public int frameRate = 24;
[Tooltip("How many frames should be captured before quitting")]
public int framesToCapture = 24;
#endregion
#region private fields
private string folderName = "";
private GameObject whiteCamGameObject;
private Camera whiteCam;
private UniversalAdditionalCameraData whiteCamAddData;
private GameObject blackCamGameObject;
private Camera blackCam;
private UniversalAdditionalCameraData blackCamAddData;
private Camera mainCam;
private int videoFrame = 0; // how many frames we've rendered
private float originalTimescaleTime;
private bool done = false;
private int screenWidth;
private int screenHeight;
[SerializeField] bool _postProcessing = false;
[SerializeField] private Texture2D textureBlack;
[SerializeField] private Texture2D textureWhite;
[SerializeField] private Texture2D textureTransparentBackground;
#endregion
void Awake()
{
mainCam = gameObject.GetComponent<Camera>();
CreateBlackAndWhiteCameras();
CreateNewFolderForScreenshots();
CacheAndInitialiseFields();
Time.captureFramerate = frameRate;
}
void LateUpdate()
{
if (!done)
{
StartCoroutine(CaptureFrame());
}
else
{
Debug.Log("Complete! " + videoFrame + " videoframes rendered. File names are 0 indexed)");
Debug.Break();
}
}
IEnumerator CaptureFrame()
{
yield return new WaitForEndOfFrame();
if (videoFrame < framesToCapture)
{
RenderCamToTexture(whiteCam, textureWhite);
RenderCamToTexture(blackCam, textureBlack);
CalculateOutputTexture();
SavePng();
videoFrame++;
Debug.Log("Rendered frame " + videoFrame);
}
else
{
done = true;
StopCoroutine("CaptureFrame");
}
}
void RenderWiteRT2Texture()
{
}
void RenderCamToTexture(Camera cam, Texture2D tex)
{
RenderTexture renderTexture;
if (_postProcessing)
{
renderTexture = new RenderTexture(screenWidth, screenHeight, 0, RenderTextureFormat.DefaultHDR);
}
else
{
renderTexture = new RenderTexture(screenWidth, screenHeight, 16);
}
cam.targetTexture = renderTexture;
cam.Render();
RenderTexture.active = renderTexture;
WriteScreenImageToTexture(tex);
cam.targetTexture = null;
RenderTexture.active = null;
Destroy(renderTexture);
renderTexture = null;
}
void WriteScreenImageToTexture(Texture2D tex)
{
tex.ReadPixels(new Rect(0, 0, screenWidth, screenHeight), 0, 0);
tex.Apply();
}
void CreateBlackAndWhiteCameras()
{
blackCamGameObject = (GameObject)new GameObject();
blackCamGameObject.name = "Black Background Camera";
blackCam = blackCamGameObject.AddComponent<Camera>();
blackCamAddData = blackCamGameObject.AddComponent<UniversalAdditionalCameraData>();
blackCamAddData.renderPostProcessing = true;
blackCam.CopyFrom(mainCam);
blackCam.backgroundColor = Color.black;
blackCamGameObject.transform.SetParent(gameObject.transform, true);
whiteCamGameObject = (GameObject)new GameObject();
whiteCamGameObject.name = "White Background Camera";
whiteCam = whiteCamGameObject.AddComponent<Camera>();
whiteCamAddData = whiteCamGameObject.AddComponent<UniversalAdditionalCameraData>();
whiteCamAddData.renderPostProcessing = true;
whiteCam.CopyFrom(mainCam);
whiteCam.backgroundColor = Color.white;
whiteCamGameObject.transform.SetParent(gameObject.transform, true);
}
void CreateNewFolderForScreenshots()
{
// Find a folder name that doesn't exist yet. Append number if necessary.
folderName = folderBaseName;
int count = 1;
while (System.IO.Directory.Exists(folderName))
{
folderName = folderBaseName + count;
count++;
}
System.IO.Directory.CreateDirectory(folderName); // Create the folder
}
void CalculateOutputTexture()
{
Color color;
for (int y = 0; y < textureTransparentBackground.height; ++y)
{
// each row
for (int x = 0; x < textureTransparentBackground.width; ++x)
{
// each column
float alpha = textureWhite.GetPixel(x, y).r - textureBlack.GetPixel(x, y).r;
alpha = 1.0f - alpha;
if (alpha == 0)
{
color = Color.clear;
}
else
{
color = textureBlack.GetPixel(x, y) / 1;
}
color.a = alpha;
textureTransparentBackground.SetPixel(x, y, color);
}
}
}
void SavePng()
{
string name = string.Format("{0}/{1:D04} shot.png", folderName, videoFrame);
var pngShot = textureTransparentBackground.EncodeToPNG();
File.WriteAllBytes(name, pngShot);
}
void CacheAndInitialiseFields()
{
originalTimescaleTime = Time.timeScale;
//Output the current screen window width in the console
var size = GetMainGameViewSize();
screenWidth = (int)size.x;
screenHeight = (int)size.y;
textureBlack = new Texture2D(screenWidth, screenHeight, TextureFormat.RGB9e5Float, false);
textureWhite = new Texture2D(screenWidth, screenHeight, TextureFormat.RGB9e5Float, false);
textureTransparentBackground = new Texture2D(screenWidth, screenHeight, TextureFormat.RGB9e5Float, false);
}
public static Vector2 GetMainGameViewSize()
{
System.Type T = System.Type.GetType("UnityEditor.GameView,UnityEditor");
System.Reflection.MethodInfo GetSizeOfMainGameView = T.GetMethod("GetSizeOfMainGameView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
System.Object Res = GetSizeOfMainGameView.Invoke(null, null);
return (Vector2)Res;
}
}
@haosizheng
Copy link
Author

haosizheng commented May 25, 2022

update to a version suitable with unity 2022.2.0a & 2021.3.12f1

  • alpha channel supported
  • post processing supported
  • get bad result with vfx in my test

update 2022.10.28

@DenverNova
Copy link

Just wanted to say thank you for updating this script. It's the only thing I've found out of about 8 other scripts/assets that will actually allow you to take a screenshot of a prefab and keep the transparent background in Unity 2022 using URP.

@haosizheng
Copy link
Author

Just wanted to say thank you for updating this script. It's the only thing I've found out of about 8 other scripts/assets that will actually allow you to take a screenshot of a prefab and keep the transparent background in Unity 2022 using URP.

you're welcome and glad it worked.

@Valkrysa
Copy link

Thank you for uploading this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment