1
\$\begingroup\$

I am currently working on a solution to make my game look very pixelated, like Doom or Quake. But there is a big problem.

I'm using Unity Personal.

I render my camera to a 1920x1080 texture, then I try to use Texture2D.Resize on it, then render it back to the screen using ScaleMode.StretchToFill.

But the problem is that the texture seems to corrupt when I use Texture2D.Resize on it.

And here is my current code: using UnityEngine; using System.Collections;

public class PixelRenderer : MonoBehaviour {

    Texture2D texture;

    // Use this for initialization
    void Start () {
        texture = new Texture2D(256, 256, TextureFormat.ARGB32, false);
    }

    // Update is called once per frame
    void OnPostRender() {
        texture = new Texture2D(Screen.width, Screen.height, TextureFormat.ARGB32, false);
        texture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
        texture.Apply();
        texture.Resize(256, 256);
    }

    void OnGUI() {
        GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), texture, ScaleMode.StretchToFill);
    }
}

Is there something that I'm missing here? Or am I doing something wrong?

\$\endgroup\$
2
  • 3
    \$\begingroup\$ For a pixelated look try rendering it to a smaller texture first then copying it back to the screen and skip the resize step altogether. \$\endgroup\$ Jun 11 '15 at 12:43
  • \$\begingroup\$ Quake wasn't pixelated, if you run it today, then it will fill up the whole screen correctly rasterized. \$\endgroup\$
    – Bálint
    Jan 24 '17 at 12:27
3
\$\begingroup\$

There is much simpler solution for re-sizing.

public static Texture2D Resize(Texture2D source, int newWidth, int newHeight)
{
    source.filterMode = FilterMode.Point;
    RenderTexture rt = RenderTexture.GetTemporary(newWidth, newHeight);
    rt.filterMode = FilterMode.Point;
    RenderTexture.active = rt;
    Graphics.Blit(source, rt);
    Texture2D nTex = new Texture2D(newWidth, newHeight);
    nTex.ReadPixels(new Rect(0, 0, newWidth, newHeight), 0,0);
    nTex.Apply();
    RenderTexture.active = null;
    RenderTexture.ReleaseTemporary(rt);
    return nTex;
}

Obviously if you want filtering you also can switch from point filtering to bilinear/trilinear.

Or, alternatively you can do point filtering, which gonna resize your texture with nearest neighbor, and from there you can apply shader like fastblur for much smoother control over resampled quality.

\$\endgroup\$
0
\$\begingroup\$

It might be your system or limitations in WebGL. Unless the screen you are resizing to is a Power-of-two texture. (POT/NPOT) Then your selections for read and write pixels would be off.

From the docs for the Texture-Importer:

It is possible to use other (non power of two - “NPOT”) texture sizes with Unity. Non power of two texture sizes generally take slightly more memory and might be slower to read by the GPU, so for performance it’s best to use power of two sizes whenever you can. If the platform or GPU does not support NPOT texture sizes, then Unity will scale and pad the texture up to next power of two size, which will use even more memory and make loading slower (in practice, this can happen on some older mobile devices). In general you’d want to use non power of two sizes only for GUI purposes.

I would assume this applies to all textures. Not just imported ones. And while the GUI supports NPOT textures, (uGUI and Canvas, maybe?) your texture isn't being scaled in the GUI, it's being scaled as a 2D texture after creating, before being displayed.

You might also want to look at the AssetPostprocessor. It would allow you to set your texture 'import' settings after creation. You may be able to limit texture size, or render a specific mipmap level and get the visual you desire.

Last resort, look for a 'pixlate' shader, and instead of resizing, just use a custom material.

\$\endgroup\$

You must log in to answer this question.

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