- Home /
Changing texture import settings during runtime
I'm working on a painting game that has to copy texture files during runtime, but I'm running into problems getting everything to work as desired.
After a lot of goofing around with all kinds of different copy, delete, and load functions I figured out that I need to be able to change import settings on individual textures during runtime. (OR at the very least I need to be able to enable read/write to a texture file)
Also: I want to avoid a situation that enables read/write for every texture in the game, ideally I would like to only flag the files I want for read/write.
Any insight?
Answer by MirrorIrorriM · Aug 04, 2013 at 06:05 PM
I ran into a similar problem in my own little paint program. I have figured out how to change their settings by using the AssetPostprocessor. As an example :
using UnityEngine;
using UnityEditor;
public class TexturePostProcessor : AssetPostprocessor
{
void OnPreprocessTexture()
{
if(assetPath.Contains("DirectoryOfInterest"))
{
TextureImporter importer = assetImporter as TextureImporter;
importer.textureType = TextureImporterType.Advanced;
importer.textureFormat = TextureImporterFormat.AutomaticTruecolor;
importer.isReadable = true;
importer.filterMode = FilterMode.Point;
importer.npotScale = TextureImporterNPOTScale.None;
Object asset = AssetDatabase.LoadAssetAtPath(importer.assetPath, typeof(Texture2D));
if (asset)
{
EditorUtility.SetDirty(asset);
}
else
{
importer.textureType = TextureImporterType.Advanced ;
}
}
}
}
You see here I'm able to change tons of different settings for the texture, including but not limited to read/write capability. What we are doing here is highjacking the importer before it actually applies the default settings, and applying our OWN default settings. This script must be placed inside a folder called "Editor" inside your asset hierarchy. By using if(assetPath.Contains("YourDirectoryHere")) you can change the import settings of files in a particular folder only. You can also have this check the name. For example if the name of your file was always going to be TempImageFIle, you could use assetPath.Contains("TempImageFile") to find it.
Finally, if create an image during runtime and want to be able to load the file without actually restarting the program, you need to refresh the unity assets. To do this you use AssetDataBase.Refresh(); Make sure whatever script calls AssetDataBase.Refresh() is using UnityEditor!
You can also call this in Start on a script that is ExecuteInEdit$$anonymous$$ode
HI $$anonymous$$irrorIrorri$$anonymous$$ how to call this function at runtime as I have a texture co$$anonymous$$g from server and I have to change its texture to readable and wri$$anonymous$$ble at runtime
Worked great - Thank you so much! I only needed to set the NPOT to none, so I stripped away most of the rest.
Answer by jogo13 · Jan 17, 2013 at 09:53 PM
The imported texture in the editor is not the texture that will be available in the runtime. (You can't change it during a real game build's runtime as there's no longer a untouched source texture to work from.)
You can manipulate it anyway you wish using Texture2D.SetPixels, etc. Keep in mind it creates additional ram/cpu usage. http://docs.unity3d.com/Documentation/ScriptReference/Texture2D.html
If you can achieve the desired effects using shaders instead that's recommended.
I'm already using setpixels to paint on the texture, but setpixels is a very slow way to do a clear function, individually modifying 4 floats for each pixel in the texture. $$anonymous$$y solution to speed it up is to have a blank transparent texture that never gets modified kept in the textures folder and when Clear is called the current painting texture is deleted, the copy file is copied, and the new copy gets the same location and name of the old painting texture.
All of that works fine, but once I create the copy I can no longer use setpixels to change it because it is read only. Is there a way to set default texture importer settings so new files automatically get the values I want?
http://docs.unity3d.com/Documentation/ScriptReference/Texture2D.SetPixels32.html says "Using SetPixels32 is faster than calling SetPixels."
Answer by Pangamini · May 07, 2019 at 10:24 AM
I've made painting using GPU, that's what it's for, right? Obviously, you can't change import settings during runtime (it's IMPORT settings, just a way how to translate a png or other format to a texture. Once it's done it's done). You don't have to enable read/write, you can just blit / render your texture to a renderTexture (and then if you really want, you can read pixels from that). But for painting, i'd suggest entirely gpu-based solution, by sequentially rendering into a renderTexture and not clearing it.
Anyway here's my texture painting tool, as is
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TexturePaint : System.IDisposable
{
private Texture2D m_targetTexture;
private RenderTexture m_rt;
private bool m_painting;
public Material brush;
public event System.Action<Texture> onDisplayTextureChanged;
public bool painting
{
get { return m_painting; }
set
{
if (m_painting == value) return;
m_painting = value;
if (m_painting)
OnBeginPainting();
else
OnEndPainting();
}
}
private void OnBeginPainting()
{
if (!m_rt)
m_rt = new RenderTexture(2,2,24, RenderTextureFormat.ARGBFloat);
m_rt.width = m_targetTexture.width;
m_rt.height = m_targetTexture.height;
m_rt.Create();
Graphics.Blit(m_targetTexture, m_rt);
if (onDisplayTextureChanged != null)
onDisplayTextureChanged(m_rt);
}
private void OnEndPainting()
{
var tempLdr = RenderTexture.GetTemporary(m_rt.width, m_rt.height, 0, RenderTextureFormat.ARGB32);
try
{
Graphics.Blit(m_rt, tempLdr);
RenderTexture.active = tempLdr;
m_targetTexture.ReadPixels(new Rect(0, 0, tempLdr.width, tempLdr.height), 0, 0, false);
m_targetTexture.Apply(true);
RenderTexture.active = null;
m_rt.Release();
}
finally
{
RenderTexture.ReleaseTemporary(tempLdr);
if (onDisplayTextureChanged != null)
onDisplayTextureChanged(m_targetTexture);
}
}
public void Dispose()
{
painting = false;
}
~TexturePaint()
{
Dispose();
}
public Texture2D targetTexture
{
get { return m_targetTexture; }
set
{
if (m_targetTexture == value)
return;
m_targetTexture = value;
}
}
public void Paint(Vector2 uv, float radius, float amount)
{
if (!painting) throw new System.InvalidOperationException();
Paint(uv, radius, amount, brush, m_rt);
}
public static void Paint(Vector2 uv, float radius, float amount, Material brush, RenderTexture target )
{
var origColor = brush.color;
try
{
var color = origColor;
color.a *= amount;
brush.color = color;
Vector2 radius2 = new Vector2(radius, radius);
Graphics.SetRenderTarget(target);
GL.LoadOrtho();
brush.SetPass(0);
GL.Begin(GL.TRIANGLE_STRIP);
GL.TexCoord2(1, 0);
GL.Vertex(new Vector2(uv.x + radius2.x, uv.y - radius2.y));
GL.TexCoord2(0, 0);
GL.Vertex(new Vector2(uv.x - radius2.x, uv.y - radius2.y));
GL.TexCoord2(1, 1);
GL.Vertex(new Vector2(uv.x + radius2.x, uv.y + radius2.y));
GL.TexCoord2(0, 1);
GL.Vertex(new Vector2(uv.x - radius2.x, uv.y + radius2.y));
GL.End();
}
finally
{
brush.color = origColor;
}
}
}
It creates a renderTarget when you set painting to true. You are then allowed to paint using Paint() (even thousands of paints are fast, to draw a smooth line using a custom texture brush). Setting painting to false switches from renderTexture to a texture2D, generating mipmaps for nicer display. onDisplayTextureChanged event is called to notify the renderer of these texture swaps (so you know which texture should be displayed)
Your answer
Follow this Question
Related Questions
Apply transparent texture to plain at runtime 1 Answer
Runtime Normal Map Import Issues 0 Answers
Assigning UV Map to model at runtime 0 Answers
Reverse of Texture.EncodeToEXR in unity? 0 Answers