So i am currently working on a drawing functionality for a iOS application. So the user can select a color and then draw with a brush on a canvas.
The way i am thinking of doing this so far is having a 2D Color array that i actually do all the editing on. And then apply this array to a Texture2D a few times a second. I will have to see how test and find out how often i can update the Texture2D on a iOS device and keep a reasonable FPS.
My question is however is more how the brush function should interact with the 2D color array.
Say i know where on the 2D array the center of the touch position is. How can i then apply a Color.Lerp(from the current pixel color, to the brush color) based to the nearby points based on the distance from the touch position. I could loop trough the entire 2D array and check each pixels Vector2.distance from the touch position, but this seems a but redundant. Especially as i am probably pushing the overhead already with this app already. Is there a faster way to apply the Color.Lerp only to the nearby color points in the 2D color array?
This is actually pretty simple. Assuming that you know the size of your brush. You need to define a Rect which is the area of your color array that will be affected. Since the color array has to be predefined with the screen width * screen height, you also then have to define a rect for that. Then simply do a couple of loops to span the brush only. At every point, ask if the brush’s rect is inside of the screen rect and process your brush accordingly.
Attached is some code, it is not tested but it is the same thing in theory.
private var screenTexture : Texture2D;
var brush : Texture2D;
var currentColor : Color;
var updateEvery : float = 0.2;
private updateAt : float = 0.0;
private lastPosition : Vector2;
function Start(){
var screenTexture = new Texture2D (Screen.width, Screen.height);
currentColor = new Color(1,1,1,1);
}
function Update(){
if(brush == null) return;
if(Time.time < updateAt) return; // only update every updateEvery seconds
updateAt=Time.time + updateEvery;
// get a touch
if(Input.touchCount == 0) return;
// we moved, so we want to only update the distance of the move from the last position + 0.25
if(Input.GetTouch(0).phase == TouchPhase.Moved){
var brushSize=Vector2(brush.width, brush.height).magnitude;
for(var i=0.0; i<( lastPosition - Input.GetTouch(0).position); i+=brushSize/4){
var position=Vector2.Lerp(lastPosition, Input.GetTouch(0).position, i * brushSize);
ProcessBrush(position.x, position.y);
}
lastPosition = position; // done so it is smooth
} else {
position=Input.GetTouch(0).position;
ProcessBrush(position.x, position.y);
lastPosition = Input.GetTouch(0).position;
}
}
function ProcessBrush(x : int, y : int){
if(brush == null) return;
var colors=screenTexture.GetPixels();
var cbrush=brush.GetPixels();
var brect : Rect=new Rect(x - brush.width/2, y-brush.height/2, brush.width, brush.height);
var srect : Rect=new Rect(0,0,screenTexture.width, screenTexture.height);
for(var iy : int=brect.y; iy<brect.height; iy++){
for(var ix : int=brect.y; ix<brect.width, ix++){
// check to see if the screen contains our part of the brush
if(srect.Contains(ix, iy)){
var newColor=color * cbrush.[(ix-brect.x) * (iy-brect.y) brush.width];
var alpha=newColor.a;//force the alpha out for the lerp
newColor.a=1;
colors[ix + iy * screenTexture.width]=Mathf.Lerp(colors[ix + iy * screenTexture.width], newColor, alpha);
}
}
}
screenTexture.SetPixels(colors);
screenTexture.Apply(false);
}
…or like an option u can paint on a plane that has MeshCollider. When u make a raycast u can extract UV coordinates of hitted pixel from HitInfo, then knowing size of texture, count which exact pixel u hit, and get some anothers close to it.