- Home /
Texture2D.ReadPixels Being Set But Not Saved?
Hello everyone and thanks in advance for any help given here.
Basically i added to the: Texture2D.ReadPixels
What i am trying to do is save the cameras view to a RawImage UI component and allow it to be saved on that RawImage so that when i load the games playerprefs, that image is still there and they can choose what save they want to load. A similar reference is the way skyrim presents saves in the form of images of the scene view.
I was also thinking of trying an alternative maybe creating a screenshot using Application.Screenshot i think is what it is and then setting that saved file to the RawImage or just directly to a sprite? Just a thought.
Here is what i have working:
-Load & Save system -Setting the RawImage to the scene view
Here is whats not working:
-Playing the scene again in the editor a second time removes the Texture from the RawImage
Here is my script:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using plyBloxKit;
// Here we make sure you added the required components to this camera,
// if not, we will add them for you when you attach the script.
// WARNING: Be sure to place this on a camera.
[RequireComponent (typeof (Camera))]
[RequireComponent (typeof (plyBlox))]
public class ScreenGrab : MonoBehaviour {
// This variable will present our bool that will be called when the
// player saves the game so that we can grab a camera snapshot and
// run our events.
public bool setImage = true;
// This variable holds the object with the blox component on it
// and will fire a custom state when the player saves the game.
public plyBlox bloxLogic;
// This variable is the number that will be set on the script so that it can decide
// which slot image to save to. The values by default range from 1-3 with 0 being null.
public static int saveSlotNumber = 0;
// OPTIONAL: Uncomment the variable line below if you want to be able to see the slot number change
// while inside the inspector. Be sure to comment the above variable out if you want this one active.
//public int saveSlotNumber;
// These variables hold our save game slot images. Each one correlates
// to its respective slot to be called in our events below. To add more
// slots, simply copy and paste the whole variable line and change the
// variable name to a unique name like shown below.
public RawImage saveSlotOneImage;
public RawImage saveSlotTwoImage;
public RawImage saveSlotThreeImage;
// OPTIONAL: These variables will serve as optional offsets that you can apply to
// the screen capture ranging from any value in the X or Y axis.
public float imagePosXOffset = 0;
public float imagePosYOffset = 0;
// These variables will capture the cameras view in accordance to the end users actual screen width
// and size.
private int grabWidthResolution = Screen.width;
private int grabHeightResolution = Screen.height;
// This function will be called from the camera after regular rendering is done.
void OnPostRender() {
// Here we will first check if our bool is True, if so, capture the scene view and save it to a texture
// in accordance to the variables we have set in the inspector, excluding the getResolution variables.
if (setImage) {
Texture2D tex = new Texture2D(grabWidthResolution, grabHeightResolution);
tex.ReadPixels(new Rect(imagePosXOffset, imagePosYOffset, grabWidthResolution, grabHeightResolution), 0, 0);
tex.Apply();
// Here check if the slot we want to save to is the correct slot and if so,
// we will set our save slot image to our newly captured screen view.
if (saveSlotNumber == 1) {
saveSlotOneImage.texture = (Texture)tex;
Debug.Log("Save Slot One Was Set");
}
// Here check if the slot we want to save to is the correct slot and if so,
// we will set our save slot image to our newly captured screen view.
if (saveSlotNumber == 2) {
saveSlotTwoImage.texture = (Texture)tex;
Debug.Log("Save Slot Two Was Set");
}
// Here check if the slot we want to save to is the correct slot and if so,
// we will set our save slot image to our newly captured screen view.
if (saveSlotNumber == 3) {
saveSlotThreeImage.texture = (Texture)tex;
Debug.Log("Save Slot Three Was Set");
}
// Here we will call an event from the plyBlox gameobject we specified in
// the inspector. To change the events name that will be called, edit the
// string after "blox.RunEvent".
plyBlox blox = bloxLogic.GetComponent<plyBlox>();
blox.RunEvent ("Test");
// Here we finish our screen capture logic and turn the fuction off so that
// it can be called again.
setImage = false;
}
}
}
Answer by Josh707 · Aug 21, 2015 at 04:58 PM
Hardly anything persists when exiting play mode, except for material property changes and maybe a few other things. So it's expected that your textures being created in play mode are getting disposed.
To do something like this, you're going to have to actually save the image data somewhere, most likely to a file. When starting up the game, you'll have to load these files, if they exist, and supply the RawImage components with them after loading.
A small example:
using System.IO;
string filePath = Application.dataPath + "/save1.png";
void Load()
{
if(File.Exists(filePath))
{
//Remember to save and load at the same resolution
Texture2D tex = new Texture2D(512, 512);
tex.LoadImage(File.ReadAllBytes(filePath))
saveSlotOneImage.texture = tex;
}
}
void Save()
{
//Same texture creation you already have
File.WriteAllBytes(filePath, tex.EncodeToPng());
}
Using Application.CaptureScreenshot
is probably not good in this case, since players with different resolutions will output different size images. It's probably best to keep a constant resolution for the save images.
@Josh707 I apologize in advance but could you possible tell me what i need to replace in my script. Im not a coder by any means, it took me about 6 hours to make that script above after reading alot of Unity docs and the manual.
I just dont know how to format what you supplied into my existing code, and to avoid me co$$anonymous$$g back because of errors, i think itd help if you can input that into my script and maybe comment out what you took out of $$anonymous$$e?
It would help me alot.
No apology needed! That's what this questions site is for.
Ins$$anonymous$$d of putting it in a comment here since it's fairly long, here: http://pastebin.com/kL8pkhGx
Note that nothing was removed, only a few things added. I tried to leave comments in the same style you had to make things as clear as possible.
@Josh707, Thank you for taking the time to do that, it helped to see the order in which they execute.
Now a final question. When im clearing my saves via the clear saved data, which does work, and i exit play mode and return, the save slots are cleared of data, but the images remain even though i replace those images with black transparent ones when clearing data.
So, if you can lend me aid once more, how can i remove those saved png's from the game for when the player wants to start a fresh campaign and remove all saves.
I just encountered this so i thought to come here first before making any custom events and editing code.
Thank you in advance as always!
EDIT Also, with my current setup, i can search the 3 slots to see if each is filled individually or all together, but this is done with visual scripting unfortunately. Just thought id inform you with as much of what i can do as far as that goes.
Glad I can help!
The way this works (checking if the save images exist by their file names, and loading them if they do) requires deleting those files when you clear the save data, so it doesn't load images for saves you've deleted. You can use the following whenever you clear a save, assu$$anonymous$$g it's in the same script with the filePathFormatString
variable:
void DeleteSaveImageFile(int saveNumber)
{
File.Delete(string.Format(this.filePathFormatString, saveNumber));
}
Hey - you won't need a boolean for this, you should just call the DeleteSaveImageFile
function when you need it to run. It seems like your save clearing code isn't inside this script, so I can't give you a better example. If the save clearing is inside a different script, you should be able to use GetComponent
and call that function with the number of the save you're trying to delete.
Regarding the string check, no you won't need anything like that, but I would recommend changing the name of the Start function to Awake, so in case you disable that script in the inspector, it will always have that string initialized. Otherwise, if disabled, Start won't run and the path won't be set. I didn't realize that before when I wrote the example.
Your answer
![](https://koobas.hobune.stream/wayback/20220612000652im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
What is the bottleneck in this iphone code? 3 Answers
ReadPixels() vs Windows ScreenShot 0 Answers
Texture.Apply() Crashes at Resolutions under 1920x1080 1 Answer
Using Screenshot as Texture 4 Answers