[SOLVED] Graphics.DrawTexture() with Sprites

Hello,

I’m trying to render a sprite inside the Editor using Graphics.DrawTexture(). I have a simple script with just a single public var pointing to a prefab (GameObject). Now I would like to see a preview of the sprite inside the Editor even if the prefab has not been actually instantiated. To do so I’m using OnDrawGizmos in the following way:

public class PrefabLink : MonoBehaviour
{
    public GameObject Prefab;


    private void OnDrawGizmos()
    {
        if (Prefab == null)
            return;

        var spriteRenderer = Prefab.GetComponent<SpriteRenderer>();
        if (spriteRenderer == null)
            return;

        var spriteRect = new Rect(transform.position, spriteRenderer.bounds.size);
        var spriteTexture = spriteRenderer.sprite.texture;

        Graphics.DrawTexture(spriteRect, spriteTexture);
    }
}

The result is weird. The sprite is actually rendered but I have the following issues:

1 - The sprite is flipped vertically
2 - The position is snapped to integer units. For example if the GameObject’s X coord is 4.7f the Sprite will be renderered at X = 5.0f (same for Y)

I suppose it’s the projection matrix that is causing the above but I’m not certain.

Any help would be greatly appreciated, thank you.

** Update **
Updated the script to support ‘Multiple’ Sprite Mode.

I think I found a solution to the problem. The following modified version of my previous script will correctly draw a textured quad using GL functions:

public class PrefabLink : MonoBehaviour
{
    public GameObject Prefab;


    private static Material m_Material;


    private void OnDrawGizmos()
    {
        if (m_Material == null)
            m_Material = new Material(Shader.Find("Sprites/Default"));

        if (Prefab == null)
            return;

        var spriteRenderer = Prefab.GetComponent<SpriteRenderer>();
        if (spriteRenderer == null)
            return;

        var sprite = spriteRenderer.sprite;

        var xyMin = Camera.current.WorldToScreenPoint(transform.position + sprite.bounds.min);
        var xyMax = Camera.current.WorldToScreenPoint(transform.position + sprite.bounds.max);

        var texW = sprite.texture.width;
        var texH = sprite.texture.height;
        var uvMin = new Vector2(sprite.rect.min.x / texW, sprite.rect.min.y / texH);
        var uvMax = new Vector2(sprite.rect.max.x / texW, sprite.rect.max.y / texH);

        var invU = spriteRenderer.flipX;
        var invV = spriteRenderer.flipY;

        GL.PushMatrix();

        GL.LoadPixelMatrix();

        m_Material.mainTexture = sprite.texture;
        m_Material.SetPass(0);

        GL.Begin(GL.QUADS);

        GL.MultiTexCoord(0, new Vector3(invU ? uvMax.x : uvMin.x, invV ? uvMax.y : uvMin.y, 0));
        GL.Vertex3(xyMin.x, xyMin.y, 0);

        GL.MultiTexCoord(0, new Vector3(invU ? uvMax.x : uvMin.x, invV ? uvMin.y : uvMax.y, 0));
        GL.Vertex3(xyMin.x, xyMax.y, 0);

        GL.MultiTexCoord(0, new Vector3(invU ? uvMin.x : uvMax.x, invV ? uvMin.y : uvMax.y, 0));
        GL.Vertex3(xyMax.x, xyMax.y, 0);

        GL.MultiTexCoord(0, new Vector3(invU ? uvMin.x : uvMax.x, invV ? uvMax.y : uvMin.y, 0));
        GL.Vertex3(xyMax.x, xyMin.y, 0);

        GL.End();

        GL.PopMatrix();
    }
}
3 Likes

This thread may be from 5 years ago, but I fought with this problem for an hour, and this code snippet saved me. Thank you person from the past!

2 Likes

Please don’t pointlessly necro a thread, it’s against the Unity Community Code of Conduct . You can just as easily press the Like button on their post instead of Replying.

1 Like