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;
}
}
}