- Home /
Painting on Textures at Runtime?
Everyone,
We have an application in which we need to dynamically painting on an object's texture at runtime. After experimenting with SetPixels/Apply, seems that this is NOT a viable solution (due to performance).
We are working on a method to implement a virtual spray gun.. So, as a first step we have set up a plane and a cube in a scene, and are raycasting from a point on a FP controller. We are casting a fan pattern of rays (just in the Y axis). When we record hits we want to disturb the texture of the cube to emulate paint drops.
We have this basically working with a Texture2D and using SetPixel(s)/Apply.. It works, but it is a bit jerky and slow. We have optimized using SetPixels, and only doing a single Apply per Texture, but we are just on the edge of reasonable!
From what we have read regarding RenderTexture, we are confused about how to use this since it is rendered in a separate camera? Is it possible to attach the RenderTexture for example to the cube surface, still hit detect, and get coords that relate to the RT? Also, how do we perform the equivalent of SetPixel(s)/Apply on an RT?
If not RenderTexture, anybody have another way to effectively do these type of operations against textures?
Any insight or ideas would be greatly appreciated!
Thanks in advance.
Answer by Waz · Jul 15, 2011 at 05:42 AM
RenderTexture is hugely powerful. You can even use Shaders to modify the texture, so performance is magnitudes better than Texture2D.SetPixel.
For example, you can draw a texture onto a RenderTexture (set it active and call Graphics.DrawTexture). This gives you the equivalent of SetPixels, but a whole source image at a time can be drawn at any position. You can also use the GL functions to draw, DrawMesh, or just execute a shader over the pixels (by drawing a plane over the pixels to be modified, with a Material using your shader).
It's not quite as simple as Texture2D.SetPixels, but neither is a Matrix4x4 as simple to use as an int.
Ok.. But here's the confusion.. From the examples seems that we have to attach an RT to a camera.. Is this really true?
Seems we can create an RT at runtime (e.g. new RenderTexture(1024,1024,0,ARGB32) then .Create()), then assign this to an object's texture (e.g. renderer.material.mainTexture = RT)..
But how do we draw on this animal?
I listed the ways. Camera+Shader is only one way, it's the most powerful though, which I guess is why you see it in examples. I actually expect it would be the way to do what you're doing too though, so focus on it. Note that a Camera is just a rendering mechanism. It need have nothing to do with your scene.
We have been playing with an approach to simply record the RaycastHit coords, + angle/distance in an array buffer (we need these to model the real spray pattern for the gun), then in the RT camera OnPostRender use Immediate GL calls to modify the RT that is attached to the object.
Trouble is we can't seem to get the RT to modify correctly.. It is starting to make us crazy (crazier than we already are!)
I am not sure we need a custom shader, just a way to update an objects texture dynamically without killing the framerate.
The confusion is to understand really how RenderTexture is different from Texture2D/SetPixel.. $$anonymous$$y understanding was that when you use this method you are manipulating the texture in memory, and Apply was having to transfer this to the GPU (which is slow). The RT however was managed fully in the GPU, so by-passing the need to copy the Texture over each time?
Do you know of an examples that could help us?
Thanks again for you help!
Did you find any solution to the problem yet? I'm on a similar issue at the moment.. I changed from the SetPixel to working with decals to get splatter effects, but still performance is very bad due to draw calls. (little better than with the SetPixel method though)
the problem with renderTexture is that you can't encodeToPng and save it... is there a way to get around that?
Answer by Mischa · Sep 10, 2011 at 02:58 PM
hmm, I'm experimenting for some time now with the RT solution. Here's my code drawing some circles with GL calls.
private void OnPostRender(){
//Temp declarations for testing
Vector2 splatCenter = new Vector2();
float splatRadius = 5f;
//do immediate GL calls to modify the rendertexture
GL.PushMatrix();
GL.LoadPixelMatrix();
splatterMaterial.SetPass(0);
// Draw splatters with center x,y from splatInfo array
for(int k=0;k<splatInfo.Count;k=k+2){
splatCenter = new Vector2(splatInfo[k],splatInfo[k+1]);
GL.Begin( GL.TRIANGLE_STRIP );
for(int i=0; i<360;i++){
GL.Vertex3(splatCenter.x,splatCenter.y,0);
GL.Vertex3(splatCenter.x+Mathf.Sin(i)*splatRadius,splatCenter.y+Mathf.Cos(i)*splatRadius,0);
}
GL.End();
}
GL.PopMatrix();
}
But I still get very low performance due to the splatter calculations. Is there any way I can store the GL Matrix, so I just have to calculate once, when adding new splatters?
I did get reasonable performance finally using the RT plus Direct OpenGL calls in OnPostRender. This was rather complicated, but in the end it seems to work. Take note that this method requires the Pro version!
I don't suppose you would be able to share the code? If so, is it able to update a large textures per frame at 30 FPS+ ?
Your answer
Follow this Question
Related Questions
Render Texture to Full Quality Texture for GUI Use 1 Answer
Raycast project to texture at runtime 1 Answer
How to update texture during runtime to display damage? 0 Answers
Reverse of Texture.EncodeToEXR in unity? 0 Answers
Vehicle color select? 2 Answers