2
\$\begingroup\$

I have spent some time looking for different solutions to be implemented in a mobile painting game I'm creating. At this time, everything is working but I have some serious performance problems on large screens and slow devices because I massively use setPixel / setPixels and apply on Texture2D.

I have come across 2 ways to speed things up:

1) Tile the image in small chunks, every chunk would be a Texture2D, and just upload (calling Texture2D.Apply()) the modified chunks.

2) Another trick I could apply on top of the tiling solution is to catch changes in an array and write them down to the needed Texture2D chunk and apply it every X miliseconds if modified.

I would like to know what other optimizations I could apply to this subject. Perhaps I should throw setPixel away and go with another more efficient way?

Cheers.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

A major bottleneck here is syncing the CPU & GPU to shuttle the texture back and forth - to the CPU for modification with SetPixels(), and to the GPU for display.

Also, the CPU is typically working on just one pixel at a time, while the GPU can churn through them in huge batches.

So, we can often greatly improve performance by keeping the texture work on the GPU side, using RenderTextures, Graphics.Blit, and the like. That lets the graphics hardware do what it was designed for, and it's very fast at it.

The exact steps will depend on the kind of painting program you want to make, and how much you'd like to do in-scene or in code.

One common approach is to set up a camera looking at a copy of your current canvas texture, rendering to another texture. Anything you put between the canvas and that camera will get composited into the new texture every frame. You can use a coloured sprite that represents the shape of your brush, or an image stamp, setting its position in Update() so that it gets drawn in the right place each frame.

You can ping-pong the two RenderTextures (one for reading the current canvas, one for writing the new one) each time you add a segment of brush stroke or stamp to your image.

(Note that you'll want any UI or preview graphics to be added by a second camera, to ensure they don't get baked into the canvas image)

For more specialized image operations, I'd recommend asking a new question with specifics of the effect that you want to achieve.

\$\endgroup\$
8
  • \$\begingroup\$ So, it seems The RTT process happens all in GPU. I suppose the camera information will be uploaded to the gpu and this will be used to do the render to texture, is it done this way? I like the idea but I can't see how I could implement erasing using the method you have explained. I can just come across this: Get current affect cuad (the one erasing has occurred) from the original image, set affected pixels to transaprent and reuploading with apply the cuad to update the zone. Am I missing something? \$\endgroup\$
    – Notbad
    Commented Jun 8, 2015 at 13:53
  • \$\begingroup\$ Correct, all rendering happens on the GPU, based on minimal instructions sent from the CPU side, like camera & object transformation matrices. If "erasing" means lowering the alpha value, then you can write a custom shader that keeps the underlying colour and only modifies the alpha. Apply a material with that shader to your brush quad and you're good to go, still keeping all the heavy lifting GPU-side. \$\endgroup\$
    – DMGregory
    Commented Jun 8, 2015 at 14:36
  • 1
    \$\begingroup\$ Try playing with this paint pacage developed with SetPixels and see if it fits your needs, arongranberg.com/unity/unitypaint \$\endgroup\$
    – idurvesh
    Commented Jun 8, 2015 at 14:46
  • \$\begingroup\$ @idurvesh I started my project following that tutorial but it was too slow when using big images. Thanks anyway. \$\endgroup\$
    – Notbad
    Commented Jun 8, 2015 at 22:45
  • \$\begingroup\$ @DMGregory I will try first the tiling method I exposed and then will try your method to see wich is better. I think having the image splitted is a good way to balance CPU vs Texture Uploading bottleneck vs GPU and this is something I would like to test. \$\endgroup\$
    – Notbad
    Commented Jun 8, 2015 at 22:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .