I have a Textured2D loaded which is represented in ETC_RGB4 how can I change this to another format? say RGBA32. Basically I want to switch from 3 channels to 4 and from 4 bit per channel to 8 per channel.
Thanks
You can change texture format during run-time.
1.Create new empty Texture2D and provide RGBA32 to the TextureFormat argument. This will create an empty texture with the RGBA32 format.
2.Use Texture2D.GetPixels to obtain the pixels of the old texture that's in ETC_RGB4 format then use Texture2D.SetPixels to put those pixels in the newly created Texture from #1.
3.Call Texture2D.Apply to apply the changes. That's it.
A simple extension method for this:
public static class TextureHelperClass
{
public static Texture2D ChangeFormat(this Texture2D oldTexture, TextureFormat newFormat)
{
//Create new empty Texture
Texture2D newTex = new Texture2D(2, 2, newFormat, false);
//Copy old texture pixels into new one
newTex.SetPixels(oldTexture.GetPixels());
//Apply
newTex.Apply();
return newTex;
}
}
USAGE:
public Texture2D theOldTextue;
// Update is called once per frame
void Start()
{
Texture2D RGBA32Texture = theOldTextue.ChangeFormat(TextureFormat.RGBA32);
}
Related
I am creating a simple game that need to capture a photo from the webcam every time the user click on some object. To avoid lag issues because of the task of convert the Texture2D to PNG and write the image on the disk, I am trying to store one List of Texture2D from the captures, and after the game ends, write all on the disk.
The problem is, when I capture one Texture2D texture from the webcam and try to do a List.Add(texture), all the elements of the list are updated because it store the reference of texture, not the Texture itself. Can anyone please, suggest me one alternative to store all the textures?
Edit: inserting code.
public class GetPhoto : MonoBehaviour
{
WebCamTexture webcam;
Texture2D photo;
List<Texture2D> photos;
IEnumerator TakePhoto()
{
//run when user click on object.
yield return new WaitForEndOfFrame();
photo.SetPixels(webcam.GetPixels());
photo.Apply();
photos.Add(photo);
}
}
As said rather use a new Texture2D instance for every press like e.g.
IEnumerator TakePhoto()
{
//run when user click on object.
yield return new WaitForEndOfFrame();
var photo = new Texture2D(yourTextureWidth, yourTextureHeight);
photo.SetPixels(webcam.GetPixels());
photo.Apply();
photos.Add(photo);
}
otherwise every entry in your list refers to the exact same Texture2D instance => everytime you overwrite the content of that instance.
In Unity, I'd like to generate 2D map from a large image file (965012573).
I already have a tile/image pieces generator but it generates 1900 images 256256, and it seems hard to create a map by hand like this (and I have more then one large image to process...).
These image pieces are sorted like this :
x/y.png
Where x starts from left to right and y from top to bottom.
As MelvMay suggests me here, I should use textures to achieve that, but how?
Do you have any idea of how to achieve that programmatically? Or may be with an existing bundle?
Thanks a lot!
[edit] As a workaround, I tried this :
public class MapGenerator : MonoBehaviour {
private Renderer m_Renderer;
private Texture2D m_MainTexture;
// Use this for initialization
void Start () {
//Fetch the Renderer from the GameObject
m_Renderer = GetComponent<Renderer> ();
m_MainTexture = LoadPNG("Assets/Tiles/Ressources/Map/0/3.png");
m_Renderer.material.mainTexture = m_MainTexture;
}
private Texture2D LoadPNG(string filePath) {
Texture2D tex = null;
byte[] fileData;
if (File.Exists(filePath)) {
UnityEngine.Debug.Log(filePath);
fileData = File.ReadAllBytes(filePath);
tex = new Texture2D(2, 2);
tex.LoadImage(fileData); //..this will auto-resize the texture dimensions.
}
return tex;
}
}
But even if I apply it on an empty object, I only see my dynamic texture in the inspector, not in the scene when I press run...
I have a camera in my scene that has a Target Texture set as a Render Texture. I want that camera to render the scene into the Render Texture, but then stop rendering anymore, essentially freezing the frame into the Render Texture. How can I achieve this? Disabling the camera or setting its target texture to null seems to just make the Render Texture appear invisible.
If you want to have like a snapshot function you could do it like this
public class SnapshotController : MonoBehaviour
{
[Tooltip("If you want to capture a specific camera drag it here, otherwise the MainCamera will be used")]
[SerializeField] private Camera _camera;
[Tooltip("If you have a specific RenderTexture for the snapshot drag it here, otherwise one will be generated on runtime")]
[SerializeField] private RenderTexture _renderTexture;
private void Awake()
{
if(!_camera) _camera = Camera.main;
if(!_renderTexture)
{
_renderTexture = new RenderTexture(Screen.width, Screen.height , 24 , RenderTextureFormat.ARGB32);
_renderTexture.useMipMap = false;
_renderTexture.antiAliasing =1;
}
}
public void Snapshot(Action<Texture2D> onSnapshotDone)
{
StartCoroutine(SnapshotRoutine(onSnapshotDone));
}
private IEnumerator SnapshotRoutine (Action<Texture2D> onSnapshotDone)
{
// this also captures gui, remove if you don't wanna capture gui
yield return new WaitForEndOfFrame();
// If RenderTexture.active is set any rendering goes into this RenderTexture
// instead of the GameView
RenderTexture.active = _renderTexture;
_camera.targetTexture = _renderTexture;
// renders into the renderTexture
_camera.Render();
// Create a new Texture2D
var result = new Texture2D(Screen.width,Screen.height,TextureFormat.ARGB32,false);
// copies the pixels into the Texture2D
result.ReadPixels(new Rect(0,0,Screen.width,Screen.height),0,0,false);
result.Apply();
// reset the RenderTexture.active so nothing else is rendered into our RenderTexture
RenderTexture.active = null;
_camera.targetTexture = null;
// Invoke the callback with the resulting snapshot Texture
onSnapshotDone?.Invoke(result);
}
}
You would then use it like e.g.
// Pass in a callback telling the routine what to do when the snapshot is ready
xy.GetComponent<SnapshotController>(). Snapshot(HandleNewSnapshotTexture);
...
private void HandleNewSnapshotTexture (Texture2D texture)
{
var material = GetComponent<Renderer>().material;
// IMPORTANT! Textures are not automatically GC collected.
// So in order to not allocate more and more memory consider actively destroying
// a texture as soon as you don't need it anymore
if(material.mainTexture) Destroy (material.mainTexture);
material.mainTexture = texture;
}
You can take a snapchot of the actual render texture in the frame where you start freezing, get this image data and replace the render texture by an actual texture with this freeze image applied.
I'm attempting to draw a RenderTexture into a Texture2D with the goal of saving it to disk. This approach has been working in the OSX editor, as well as on Android.
I don't see any errors in the XCode console, and my app becomes completely frozen when I call Texture2D.ReadPixels()
Here's a summary of the code:
// declaring variables...
RenderTexture outputTexture;
RenderTextureFormat RTFormat = RenderTextureFormat.ARGB32;
// use an appropriate format for render textures
if(SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBFloat)){
RTFormat = RenderTextureFormat.ARGBFloat;
}else if(SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf)){
RTFormat = RenderTextureFormat.ARGBHalf;
}
// create instance of output texture
outputTexture = new RenderTexture (res.x, res.y, 0, RTFormat);
// in Update, draw stuff to outputTexture
Graphics.Blit (outputTexture, canvasTexture);
Graphics.Blit (canvasTexture, outputTexture, material);
// later... user wants to save the image
// draw rendertexture to a Texture2D so we can write to disk
RenderTexture.active = outputTexture;
tmpTexture = new Texture2D (outputTexture.width, outputTexture.height, TextureFormat.ARGB32, false);
tmpTexture.ReadPixels (new Rect (0, 0, outputTexture.width, outputTexture.height), 0, 0, false);
tmpTexture.Apply ();
RenderTexture.active = null;
I have tried using a variety of RenderTextureFormat and TextureFormat, but nothing seems to work!
I believe this is being caused by your render texture format call. Something similar happened to be before.
This bit of code assigns a default texture format, then alters the default format if the currently executing environment supports it (my comments are added)
//set a default render texture of RenderTextureFormat.ARGB32;
RenderTextureFormat RTFormat = RenderTextureFormat.ARGB32;
// if my system supports it, switch to either ARGBFloat or ARGBHalf
// use an appropriate format for render textures
if(SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBFloat)){
RTFormat = RenderTextureFormat.ARGBFloat;
}else if(SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf)){
RTFormat = RenderTextureFormat.ARGBHalf;
}
However, when you actually later define your temp texture to fill with ReadPixels(), you only define it one way (again, my comments added)
//define a new tmpTexture container, ALWAYS with a TextureFormat of ARGB32
tmpTexture = new Texture2D (outputTexture.width, outputTexture.height, TextureFormat.ARGB32, false);
Thus on some systems (whichever supports the format), you're trying to readPixels() from one texture format into another. This is probably causing your issue.
You can fix this by also dynamically changing the format of the destination texture. So in the first section, you would change it to:
RenderTextureFormat RTFormat = RenderTextureFormat.ARGB32;
//add another variable here for the destination Texture format
var destinationFormat = TextureFormat.ARGB32;
// use an appropriate format for render textures
if(SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBFloat)){
RTFormat = RenderTextureFormat.ARGBFloat;
//also set destination format
destinationFormat = TextureFormat.RGBAFloat;
}else if(SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf)){
RTFormat = RenderTextureFormat.ARGBHalf;
//also set destination format
destinationFormat = TextureFormat.RGBAHalf;
}
and then of course, later consume the dynamically set format when declaring the destination object:
//define a new tmpTexture container, with a dynamically set destination format that always matches the input texture
tmpTexture = new Texture2D (outputTexture.width, outputTexture.height, destinationFormat, false);
Let me know if you still have issues in the comments.
I'm currently making a game in XNA. I have been going well so far but I don't know how to change the texture of a sprite whilst running the game. An example of this would be. When the character is still that's one image, then when he walks that's a different image. How would I make this happen?
Run checks and just set the instance's Texture2D texture to some other texture from your preloaded library.
I usually load all the textures in my content folder into a dictionary and use like so:
var StringTextureDic = new Dictionary<string, Texture2D>();
// code that loads all textures into the dictionary, file names being keys
// whenever I need to assign some texture, I do this:
if (!playerIsMoving)
Player.texture = StringTextureDic["player standing"];
if (playerIsMoving)
Player.texture = StringTextureDic["player moving"];
Well, actually, change the player texture midgame is a bad idea. In such cases, i prefer to use a texture sheet.
Rectangle frame;
int curFrame;
int frameWidth;
int frameHeight;
int runAnimationLength;
Update()
{
//Handle your "animation code"
if(playerIsMoving)
curFrame++; //Running
if(curFrame == runAnimationLength)
curFrame =0;
else
curFrame = 0; //Standing still
}
Draw(SpriteBatch spriteBatch)
{
frame = new Rectangle(curFrame*frameWidth,curFrame*frameHeight,frameWidth,frameHeight);
spriteBatch.Draw(
texture,
position,
**frame**,
color,
rotation,
origin,
SpriteEffects.None,
1);
}