Last active
May 31, 2023 12:21
-
-
Save aberloni/87c256004e8b9142358623194d3af70f to your computer and use it in GitHub Desktop.
Take a screenshot into a png file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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