Skip to content

Instantly share code, notes, and snippets.

@Legogo
Last active May 31, 2023 12:21
Show Gist options
  • Save Legogo/87c256004e8b9142358623194d3af70f to your computer and use it in GitHub Desktop.
Save Legogo/87c256004e8b9142358623194d3af70f to your computer and use it in GitHub Desktop.
Take a screenshot into a png file
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.IO;
/// <summary>
/// https://answers.unity.com/questions/12070/capture-rendered-scene-to-png-with-background-tran.html
/// </summary>
public class ScreenshotManager : MonoBehaviour
{
/// <summary>
/// if multiple camera to render
/// must list each camera in order back->front
/// if empty : will use Camera.main
/// </summary>
public string[] layersCameraNames;
Camera[] layers; // stack of cameras
Texture2D virtualPhoto; // Tex2D that will be saved into png
/// <summary>
/// for debug, 1 render per camera
/// </summary>
public RenderTexture[] layersTexs;
IEnumerator Start()
{
setup();
yield return null;
takePhoto();
//yield return new WaitForSeconds(3f);
yield return null;
unSetup();
}
[ContextMenu("start process")]
public void setup()
{
if (layersCameraNames == null)
layersCameraNames = new string[0];
// get all cameras to render
if(layersCameraNames.Length > 0)
{
layers = getCameras(layersCameraNames);
}
else
{
//layers = getCameras(new string[] { Camera.main.name });
layers = new Camera[] { Camera.main };
}
}
Camera[] getCameras(string[] names)
{
Camera[] cams = GameObject.FindObjectsOfType<Camera>();
List<Camera> output = new List<Camera>();
for (int i = 0; i < cams.Length; i++)
{
for (int j = 0; j < names.Length; j++)
{
if (cams[i].name.EndsWith(names[j]))
{
output.Add(cams[i]);
}
}
}
return output.ToArray();
}
public void takePhoto()
{
// capture the virtuCam and save it as a square PNG.
// https://gamedev.stackexchange.com/questions/184785/saving-png-from-render-texture-results-in-much-darker-image=
// can't use external render tex
// https://docs.unity3d.com/ScriptReference/RenderTexture.html
RenderTexture mRt = new RenderTexture(Screen.width, Screen.height, 32);
// the 24 can be 0,16,24, formats like
// RenderTextureFormat.Default, ARGB32 etc.
// camera render : https://docs.unity3d.com/ScriptReference/Camera.Render.html
RenderTexture.active = mRt;
for (int i = 0; i < layers.Length; i++)
{
// debug, to save each pass into specific given render textures
if(layersTexs.Length > 0)
{
// debug, capture layer
layers[i].targetTexture = layersTexs[i];
layers[i].Render();
}
// inject into final tex
layers[i].targetTexture = mRt;
layers[i].Render();
//Debug.Log("rendering " + layers[i], layers[i]);
}
Camera cam = layers[0];
//generate tex
int w = cam.targetTexture.width;
int h = cam.targetTexture.height;
//var texFormat = TextureFormat.RGBAFloat;
var texFormat = TextureFormat.RGB48; // 16bits, no alpha
virtualPhoto = new Texture2D(w, h, texFormat,
false); // false, meaning no need for mipmaps
//extract info from render texture
//https://docs.unity3d.com/ScriptReference/Texture2D.ReadPixels.html
// "Reads pixels from the current render target and writes them to a texture."
virtualPhoto.ReadPixels(new Rect(0, 0, w, h), 0, 0);
virtualPhoto.Apply();
RenderTexture.active = null; //can help avoid errors
//cam.targetTexture = null;
// consider ... Destroy(tempRT);
//clearPinkPixels();
//DestroyImmediate(mRt);
saveToPng();
}
/// <summary>
/// remove all pink pixel to alpha transparent ones
/// </summary>
void clearPinkPixels()
{
Color32[] pixels = virtualPhoto.GetPixels32();
int count = 0;
for (int i = 0; i < pixels.Length; i++)
{
//pink pixel ?
if (
pixels[i].r > 0.99f &&
pixels[i].g < 0.01f &&
pixels[i].b > 0.99f)
{
count++;
pixels[i].r = pixels[i].b = pixels[i].g = 0;
pixels[i].a = 0;
}
}
virtualPhoto.SetPixels32(pixels);
virtualPhoto.Apply();
Debug.Log("modified " + count + " pink pixels / out of " + pixels.Length + " pixels total");
}
void saveToPng()
{
byte[] bytes;
//virtualPhoto.alphaIsTransparency = true;
bytes = virtualPhoto.EncodeToPNG();
string nm = Random.Range(10000, 99999).ToString();
if(!Directory.Exists(ProjectStatics.dirShot))
{
Directory.CreateDirectory(ProjectStatics.dirShot);
}
string path = ProjectStatics.dirShot + "/capture_" + nm + ".png";
UiFeedback.log("snapshot @ " + path);
System.IO.File.WriteAllBytes(path, bytes);
// virtualCam.SetActive(false); ... no great need for this.
//DestroyImmediate(virtualPhoto);
}
/// <summary>
/// entry point
/// will load a scene with the scritpt
/// script will auto launch, take pic, and unload
/// </summary>
static public AsyncOperation call()
{
return SceneManager.LoadSceneAsync(ProjectStatics.sceneExportName, LoadSceneMode.Additive);
}
//roll back whatever is needed
protected void unSetup()
{
RenderTexture.active = null;
for (int i = 0; i < layers.Length; i++)
{
layers[i].targetTexture = null;
}
layers = null;
//remove scene after
SceneManager.UnloadSceneAsync(ProjectStatics.sceneExportName);
}
}
public class ProjectStatics
{
public const string sceneExportName = "screenshoter";
public static string dirRoot = string.Empty;
public static string dirShot = "snapshots";
//public static string dirGif = "output";
public const string fileForm = "form.txt";
static public int sessionId = -1;
public const string ppref_uniq = "ppref_uniq_seed";
static public void generateSessionId()
{
//get and inc seed
int seed = PlayerPrefs.GetInt(ppref_uniq, 0);
seed += 1;
PlayerPrefs.SetInt(ppref_uniq, seed);
sessionId = seed;
}
[RuntimeInitializeOnLoadMethod]
static protected void generatePath()
{
//sessionId = PlayerPrefs.GetInt(ppref_uniq, 0);
generateSessionId();
//https://answers.unity.com/questions/1181652/difference-between-applicationpersistantdatapath-v.html
// in editor : Assets (without last /)
// in player : ?
string appPath = Application.dataPath;
Debug.Log(appPath);
dirRoot = appPath.Substring(0, appPath.LastIndexOf('/')); // remove "Assets"
dirShot = System.IO.Path.Combine(dirRoot, dirShot);
//dirGif = System.IO.Path.Combine(Application.dataPath, dirGif);
//Debug.Log("~ProjectStatics~ gif save dir path : " + dirGif);
Debug.Log("~ProjectStatics~ shots save dir path : " + dirShot);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment