Search Unity

Question Pixelate individual 3D objects but retain resolution over distance

Discussion in 'Universal Render Pipeline' started by Cd12sd4, Jul 27, 2022.

  1. Cd12sd4

    Cd12sd4

    Joined:
    Apr 15, 2020
    Posts:
    3
    I've been doing research around how to create a pixilated effect in Unity for 3D objects. I came across the following tutorials that were useful to me:




    For the most part, it is what I am looking for, where I can pixelate certain objects in my scene (I don't want to render all objects as pixelated).

    The effect, however, works based of the screen resolution so when you are closer to objects they become less pixelated and vice versa:



    Notice how the cube on the right consists of less pixels as it is further away.

    Do you perhaps have an idea as to how you would keep the resolution of the pixelated object consistent regardless of distance to them such as below (this effect was done in photoshop, I am unaware as to how to actually implement it):




    I'm not sure if this even is possible with the method provided by most pixelart methods.

    I was thinking maybe if you could use a shader per object in the scene that would render the pixelated object then you could do some fancy shader math to fix the resolution keeping it consistent per object, however I have no idea as to how you would even render a pixel effect with just a shader. (The only method I can think of is what is described in the videos in which you render the objects onto a smaller resolution via render texture then upscale to screen resolution, which you can't really do with a shader assigned to a material).

    Another thought I had was to render each object separately using a separate camera for each object I wanted pixelated, then I could set the camera to be a fixed distance away from the object and blit the render together onto the main camera. This way since each pixelated object is rendered individually with their own camera at a fixed distance, they will retain a fixed pixel resolution regardless of distance from the main camera. (Essentially you can think of it as converting each object into a sprite and rendering that sprite in the scene, thus keeping the resolution of each object consistent despite distance) But this obviously has its own set of problems from performance, to different orientations etc...

    Maybe rendering each object on its own separate render texture so I can control each ones resolution independently could work, but that seems really not performant. And i'm not sure how you would implement that in a render feature on the URP pipeline.

    Any ideas?

    Ideally I am able to specify the resolution I want for a specific 3D object in my scene to be pixelated to and it retains that over any distance. This way I have the flexibility to have different objects rendered at different resolutions.

    I should mention that I am using the Universal Render Pipeline at the moment with a custom render feature to achieve my current pixelated effect through downscaling a render texture and upscaling to screen resolution, in which I can change the resolution of the downscaled texture.
     
  2. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    You could use a model that's voxelized and do lighting in the vertex shader per voxel.

    This is basically what this guy is doing: https://forum.unity.com/threads/efficiently-doing-real-time-prerendering.1211745/ . You don't want to create a separate camera for every object, just put them all on one render target with their own offset and bounds.
     
    Last edited: Jul 30, 2022
  3. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    289
    The problem you've identified is true for pretty much any screen-space pixelization effect. Perspective transforms are also nasty because of the pincushion effect, so you'll never be able to have 'stability' as the object moves around, and some swimming is always inevitable even with the size issue aside.

    I tried a few different methods and compared them in this article here, you might find it useful:
    https://medium.com/@elliotbentine/pixelizing-3d-objects-b55ec33328f1

    Obvious disclaimer - I wrote and maintain ProPixelizer on the asset store, so I have some biases :)

    "Maybe rendering each object on its own separate render texture so I can control each ones resolution independently could work, but that seems really not performant. And i'm not sure how you would implement that in a render feature on the URP pipeline."

    Depending on your game it might work fine, when I did the tests in that article I found for ~10 objects at low resolution in BIRP it was ok.

    I generally don't like the downscaling method because of two reasons:
    • Every pixelated object has to have the same pixel size
    • You can't move objects smoothly at the screen resolution, which makes the movement feel quite coarse and possibly unresponsive (this is personal taste though, and I understand people may not agree with me always here).
    Method 3 in the article is what I used for ProPixelizer, which has the benefit of allowing per-object pixel size without enforcing separate render targets for each object, and still allows smooth movement. It might be useful for your case where you can change the object pixel size depending on distance to camera to maintain a level of detail. The article doesn't have the full ProPixelizer code, but it does have a minimal example on how to do the pixelation.

    hope it helps,
    Elliot
     
  4. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    You can just allocate one or two and draw them to separate rects (much like you would with a sprite sheet).