-
-
Save haosizheng/ee23b75dac7fb12f02cae55959dad59f to your computer and use it in GitHub Desktop.
| 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; | |
| } | |
| } |
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.
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.
Thank you for uploading this!
Thanks for the script! I just tested it in Unity 6.2 and it works and I get a screenshot, but the background is black. I did everything as described. Normally it should export an image with transparent background, right? Or is there some other manual work to do to get a transparent backround?
update to a version suitable with unity 2022.2.0a & 2021.3.12f1
update 2022.10.28