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.