Skip to main content
Notice removed Draw attention by CommunityBot
Bounty Ended with no winning answer by CommunityBot
added 4419 characters in body
Source Link

Upd:

This is my progress so far:

using System.Linq;
using System.Text;
using UnityEngine;

public class BoxRenderer : MonoBehaviour
{
    public float width = 1;
    public float height = 1;

    public bool useMeshRenderer = true;
    public bool useSpriteGeometry = true;

    public Sprite sprite;

    public Vector3 position;

    [SerializeField] 
    private Mesh _mesh;
    private Matrix4x4 _matrix;
    private Material _material;

    private MeshFilter _meshFilter;
    private MeshRenderer _meshRenderer;

    private void Awake()
    {
        _mesh = new Mesh();
        _material = new Material(Shader.Find("Sprites/Default"));

        UpdateState();
    }

    private void OnValidate()
    {
        if (!Application.isPlaying || _mesh == null || !enabled)
            return;

        UpdateState();
    }

    private void UpdateState()
    {
        Mesh mesh = _mesh;
        mesh.Clear();
        
        // 0 --- 1
        // |  /  |
        // 2 --- 3

        Vector3[] vertices = new Vector3[4]
        {
            new Vector3(0, 0, 0),
            new Vector3(width, 0, 0),
            new Vector3(0, height, 0),
            new Vector3(width, height, 0)
        };

        int[] triangles = new int[6]
        {
            0, 1, 2,
            1, 3, 2,
        };

        Vector3[] normals = new Vector3[4]
        {
            -Vector3.forward,
            -Vector3.forward,
            -Vector3.forward,
            -Vector3.forward
        };

        Vector2[] uv = new Vector2[4] {new(0, 0), new(1, 0), new(0, 1), new(1, 1)};

        if (sprite != null && (sprite.uv.Length == 4 || useSpriteGeometry))
        {
            uv = sprite.uv;
            _material.mainTexture = sprite.texture;
        }

        if (sprite != null && useSpriteGeometry)
        {
            vertices = sprite.vertices.Select(v => (Vector3) v).ToArray();
            triangles = sprite.triangles.Select(t => (int) t).ToArray();
            normals = sprite.vertices.Select(_ => -Vector3.forward).ToArray();

            Vector2 pivot = sprite.pivot / sprite.pixelsPerUnit;
            float spriteHeight = sprite.rect.height / sprite.pixelsPerUnit;

            for (int i = 0; i < vertices.Length; ++i)
            {
                vertices[i].x += pivot.x;
                vertices[i].y = spriteHeight - (vertices[i].y + pivot.y);
            }
        }

        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.normals = normals;
        mesh.uv = uv;

        Camera camera = Camera.main;

        Vector3 min = camera.ViewportToWorldPoint(Vector3.zero);
        Vector3 max = camera.ViewportToWorldPoint(Vector3.one);

        float screenWidth = Mathf.Abs(max.x - min.x);
        float screenHeight = Mathf.Abs(max.y - min.y);

        Vector3 s = new Vector3(1, -1, 1);
        Vector3 t = new Vector3(-screenWidth * .5f, screenHeight * .5f);
        Matrix4x4 scale = Matrix4x4.Scale(s);
        Matrix4x4 translate = Matrix4x4.Translate(t);
        _matrix = translate * scale;

        if (useMeshRenderer)
        {
            if (_meshFilter == null)
            {
                _meshFilter = gameObject.AddComponent<MeshFilter>();
                _meshRenderer = gameObject.AddComponent<MeshRenderer>();
                _meshRenderer.transform.localScale = new Vector3(1, -1, 1);
            }
        }
        else if (_meshFilter != null)
        {
            Destroy(_meshFilter);
            Destroy(_meshRenderer);
            _meshFilter = null;
            _meshRenderer = null;
        }
    }

    private void Update()
    {
        if (useMeshRenderer)
        {
            _meshFilter.mesh = _mesh;
            _meshRenderer.sharedMaterial = _material;
            transform.position = _matrix.MultiplyPoint(position);
        }
        else
        {
            Matrix4x4 m = _matrix * Matrix4x4.Translate(position);
            Graphics.DrawMesh(_mesh, m, _material, 0);
        }
    }
}

It kind of works but... DrawMesh part looks much better, but MeshRenderer part doesn't feel good. Also it looks like I will have issues with other transformations. I will need to extract that info from matrix? This doesn't feel good. It's probably should be a better solution.

Upd:

This is my progress so far:

using System.Linq;
using System.Text;
using UnityEngine;

public class BoxRenderer : MonoBehaviour
{
    public float width = 1;
    public float height = 1;

    public bool useMeshRenderer = true;
    public bool useSpriteGeometry = true;

    public Sprite sprite;

    public Vector3 position;

    [SerializeField] 
    private Mesh _mesh;
    private Matrix4x4 _matrix;
    private Material _material;

    private MeshFilter _meshFilter;
    private MeshRenderer _meshRenderer;

    private void Awake()
    {
        _mesh = new Mesh();
        _material = new Material(Shader.Find("Sprites/Default"));

        UpdateState();
    }

    private void OnValidate()
    {
        if (!Application.isPlaying || _mesh == null || !enabled)
            return;

        UpdateState();
    }

    private void UpdateState()
    {
        Mesh mesh = _mesh;
        mesh.Clear();
        
        // 0 --- 1
        // |  /  |
        // 2 --- 3

        Vector3[] vertices = new Vector3[4]
        {
            new Vector3(0, 0, 0),
            new Vector3(width, 0, 0),
            new Vector3(0, height, 0),
            new Vector3(width, height, 0)
        };

        int[] triangles = new int[6]
        {
            0, 1, 2,
            1, 3, 2,
        };

        Vector3[] normals = new Vector3[4]
        {
            -Vector3.forward,
            -Vector3.forward,
            -Vector3.forward,
            -Vector3.forward
        };

        Vector2[] uv = new Vector2[4] {new(0, 0), new(1, 0), new(0, 1), new(1, 1)};

        if (sprite != null && (sprite.uv.Length == 4 || useSpriteGeometry))
        {
            uv = sprite.uv;
            _material.mainTexture = sprite.texture;
        }

        if (sprite != null && useSpriteGeometry)
        {
            vertices = sprite.vertices.Select(v => (Vector3) v).ToArray();
            triangles = sprite.triangles.Select(t => (int) t).ToArray();
            normals = sprite.vertices.Select(_ => -Vector3.forward).ToArray();

            Vector2 pivot = sprite.pivot / sprite.pixelsPerUnit;
            float spriteHeight = sprite.rect.height / sprite.pixelsPerUnit;

            for (int i = 0; i < vertices.Length; ++i)
            {
                vertices[i].x += pivot.x;
                vertices[i].y = spriteHeight - (vertices[i].y + pivot.y);
            }
        }

        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.normals = normals;
        mesh.uv = uv;

        Camera camera = Camera.main;

        Vector3 min = camera.ViewportToWorldPoint(Vector3.zero);
        Vector3 max = camera.ViewportToWorldPoint(Vector3.one);

        float screenWidth = Mathf.Abs(max.x - min.x);
        float screenHeight = Mathf.Abs(max.y - min.y);

        Vector3 s = new Vector3(1, -1, 1);
        Vector3 t = new Vector3(-screenWidth * .5f, screenHeight * .5f);
        Matrix4x4 scale = Matrix4x4.Scale(s);
        Matrix4x4 translate = Matrix4x4.Translate(t);
        _matrix = translate * scale;

        if (useMeshRenderer)
        {
            if (_meshFilter == null)
            {
                _meshFilter = gameObject.AddComponent<MeshFilter>();
                _meshRenderer = gameObject.AddComponent<MeshRenderer>();
                _meshRenderer.transform.localScale = new Vector3(1, -1, 1);
            }
        }
        else if (_meshFilter != null)
        {
            Destroy(_meshFilter);
            Destroy(_meshRenderer);
            _meshFilter = null;
            _meshRenderer = null;
        }
    }

    private void Update()
    {
        if (useMeshRenderer)
        {
            _meshFilter.mesh = _mesh;
            _meshRenderer.sharedMaterial = _material;
            transform.position = _matrix.MultiplyPoint(position);
        }
        else
        {
            Matrix4x4 m = _matrix * Matrix4x4.Translate(position);
            Graphics.DrawMesh(_mesh, m, _material, 0);
        }
    }
}

It kind of works but... DrawMesh part looks much better, but MeshRenderer part doesn't feel good. Also it looks like I will have issues with other transformations. I will need to extract that info from matrix? This doesn't feel good. It's probably should be a better solution.

Notice added Draw attention by ChessMax
Bounty Started worth 50 reputation by ChessMax
added 676 characters in body
Source Link

Basically I need just the same as here but for Unity. Is this called a change of basis? (I'm not sure). I've looked how it's done in LibGDX, and it looks like not only y is mirrored but z is also. Besides that texture coordinates are also mirrored, but I don't see any changes to meshes (or didn't find). How can I flip uv coordinates? In unity they are not always a rectangle, so I think, I can't just flip them somehow as it's done in LibGDX. It seems (from what I've tested) mesh vertices also should be flipped. How to this?

So how can I accomplish this?

Basically I need just the same as here but for Unity. Is this called a change of basis? (I'm not sure). I've looked how it's done in LibGDX, and it looks like not only y is mirrored but z is also. Besides that texture coordinates are also mirrored, but I don't see any changes to meshes (or didn't find). How can I flip uv coordinates? In unity they are not always a rectangle, so I think, I can't just flip them somehow as it's done in LibGDX. It seems (from what I've tested) mesh vertices also should be flipped. How to this?

So how can I accomplish this?

added 316 characters in body
Source Link

Basically I want to be able to write code like this:

var stage = new Stage();
var box = new Box();
box.width = 100;
box.height = 120;
box.color = Colors.red;
box.x = 0;
box.y = 0;
stage.addChild(box);

And if I run the code I should see my red box in top left corner of the screen. That's it.

Basically I want to be able to write code like this:

var stage = new Stage();
var box = new Box();
box.width = 100;
box.height = 120;
box.color = Colors.red;
box.x = 0;
box.y = 0;
stage.addChild(box);

And if I run the code I should see my red box in top left corner of the screen. That's it.

Source Link
Loading