- Home /
blending colors on a texture: shader, render texture, or other
I want to write on a texture and be able to blend colors together. For example, if the user colors a yellow area, and the picks a transparant blue, coloring over the yellow will produce green. I've tried a couple different ways with varying success. Here a couple of them:
new pixel = base pixel base pixel alpha + brush pixel brush pixel alpha this one worked pretty well, but the overlapping brush strokes became very visible. In order to remove the brush circle stroke, I stored the coordinates of the last set of pixels that were changed in an array, and then checked to see if any of the pixels I was setting had been changed on the previous pass so that I wouldn't rewrite over anything I had already changed. This comparison made drawing slow on the device.
writing on a transparant buffer, and then averaging the colors together this one worked, but was the slowest of all. It was pretty similar to the last method, but instead of storing the last set of pixels that were changed, I just wrote on a buffer and applied on mouse up.
I tried playing with render textures, but I keep running into scaling issues, and I don't have much experience with them, so I'm probably doing something wrong.
I looked at a couple shaders, but I don't know Cg and have never made a shader. It looks like what I want done could be quite easily with a shader though.
I'm quite stumped. I wish I was more familiar with shaders and render textures, as they seem to be quite powerful if you know how to use them.
Seen here is the overlapping transparent brush strokes and the problem they create. I need an efficient way to get rid of them.
Actually, I guess the brush question is a different question all together. I'll make a new thread for it. Thanks guys.
Answer by ScroodgeM · Aug 04, 2012 at 12:09 PM
solution 1
very similar to your solution 1, but use blend formula:final color = base color * (1 - brush alpha) + brush pixel * brush alphaand you needn't to store any previous actions
solution 2
just place a transparent planes (each is 4 vertices + 2 triangles) with texture of brush and color customized in material. shader should be additive or simple transparent, depends on your task. so background is static image, and at front of it a set of planes that placed in brush way. using scale and alpha you can customize size/power of brush. color is color as is. in performance reason you can do something like 'bake drawing', that will take a brushed image and place it as background with removing all drawed planes.edit:
http://zammyart.com/UA/Painter/WebPlayer.html
using UnityEngine; using System.Collections; using System.Collections.Generic; public class UnbreakablePaint : MonoBehaviour { public Transform BrushPrefab; public Material MaterialForPrefab; public Material MaterialForDrawPlane; public Camera BakeCamera; public RenderTexture TextureUsedInBakeCamera; float betweenPointDistance = 0.1f; Vector3 lastBrushPosition = Vector3.zero; bool lastBrushExists = false; Material currentMaterial; Color materialColor = Color.black; List brushesToDelete; void OnGUI() { GUI.Label(new Rect(10f, 10f, 10f, 30f), "R"); GUI.Label(new Rect(10f, 40f, 10f, 30f), "G"); GUI.Label(new Rect(10f, 70f, 10f, 30f), "B"); GUI.Label(new Rect(10f, 100f, 10f, 30f), "A"); materialColor.r = GUI.HorizontalSlider(new Rect(30f, 10f, 100f, 30f), materialColor.r, 0f, 1f); materialColor.g = GUI.HorizontalSlider(new Rect(30f, 40f, 100f, 30f), materialColor.g, 0f, 1f); materialColor.b = GUI.HorizontalSlider(new Rect(30f, 70f, 100f, 30f), materialColor.b, 0f, 1f); materialColor.a = GUI.HorizontalSlider(new Rect(30f, 100f, 100f, 30f), materialColor.a, 0f, 1f); GUI.Label(new Rect(10f, Screen.height - 40f, 400f, 30f), "select color and draw with right mouse button"); } void Update() { if (Input.GetMouseButtonDown(1)) { currentMaterial = new Material(MaterialForPrefab); currentMaterial.color = materialColor; brushesToDelete = new List(); } if (Input.GetMouseButton(1)) { Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition); Vector3 newBrushPosition = mouseRay.origin - mouseRay.direction / mouseRay.direction.y * mouseRay.origin.y; while (!lastBrushExists || (newBrushPosition - lastBrushPosition).sqrMagnitude >= betweenPointDistance * betweenPointDistance) { MakePaint(newBrushPosition); } } if (Input.GetMouseButtonUp(1)) { lastBrushExists = false; BakeCamera.Render(); RenderTexture.active = TextureUsedInBakeCamera; Texture2D tex2d = new Texture2D(TextureUsedInBakeCamera.width, TextureUsedInBakeCamera.height, TextureFormat.RGB24, false); tex2d.ReadPixels(new Rect(0, 0, TextureUsedInBakeCamera.width, TextureUsedInBakeCamera.height), 0, 0); tex2d.Apply(); MaterialForDrawPlane.mainTexture = tex2d; for (int i = brushesToDelete.Count - 1; i >= 0; i--) { Destroy(brushesToDelete[i].gameObject); } } } void MakePaint(Vector3 pointPaintDirectionTo) { Vector3 pointPaintNow = lastBrushExists ? Vector3.MoveTowards(lastBrushPosition, pointPaintDirectionTo, betweenPointDistance) : pointPaintDirectionTo; Transform brush = Instantiate(BrushPrefab, pointPaintNow, Quaternion.identity) as Transform; brushesToDelete.Add(brush); brush.renderer.material = currentMaterial; lastBrushPosition = pointPaintNow; lastBrushExists = true; } }
Thanks guys, but that still doesn't solve the problem of the overlapping brush strokes. I'm going to add an attachment so you can see what I mean.
Answer by tartious · Aug 06, 2012 at 04:53 PM
I figured out how to get rid of the dots. I was on the right track before, I just needed to read from the base texture and write to the buffertexture and apply the buffer texture on mouse up. Derp.
http://zammyart.com/UA/Painter/WebPlayer.html
look answer, i'd explain it
Your answer
Follow this Question
Related Questions
How to make a part of a texture on an object seamlessly change to another texture? 0 Answers
Grab texture from Vertex Shader 0 Answers
Change Color Based On Pixel X Coordinate in Shader 1 Answer
Material doesn't have a color property '_Color' 4 Answers
Use RenderTexture as ShaderResource in DX11 native plug-in 1 Answer