Graphic artifacts, when rendering bunch of cubes

Good day, everyone

I have a project with tons of cubes (same meshes, standard cubes) in frame. Purpose of this project is to visualize data from server (from data.txt for now). From two sides meshes looks good as expected, but other two sides looks messed up, when I rotate the camera. You can see it on video below (video 1).

No lighting and no shadows in this projects. You can look in shader’s code or even in test project.

Maybe it’s somehow problem with opaque overdraw or floating-point precision or bad overall geometry, idk.

Strange fact: if i combining meshes manually and rotating 90 degrees on y-axis it looks almost ok. But it doesn’t work, if meshes not combined (I tried on gpu instancing). Video 2*

I divide all scales and positions by 255 to be able to decrease far and near planes, but without dividing - same result

Test project: https://drive.google.com/file/d/0B8FUjeQWCcG0cENjY3RYTGU0SnM/view?usp=sharing

Video 1:

Video 2:

Source code

Main code:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

public class BunchOfCubes : MonoBehaviour
{
    public Camera RenderCam;
    public Mesh mesh;
    public Material mat;
    public Color color0, color1;
    public MatrixConteiner[] matConteiner;
    private List<Matrix4x4> listMatrices;
    private List<Vector4> colors;
    private List<MaterialPropertyBlock> blocks;

    void Start()
    {
        Generate();
    }

    public void Generate()
    {
        listMatrices = new List<Matrix4x4>();
        colors = new List<Vector4>();
        blocks = new List<MaterialPropertyBlock>();

        float[,] data = DataReader.Inst.GetData();

        Vector2 size = new Vector2(data.GetLength(0), data.GetLength(1));

        for (int x = 0; x < size.x; x++)
        {
            for (int y = 0; y < size.y; y++)
            {
                float scaleY = data[x,y] / 255f;
                Color col = Color.Lerp(color0, color1, scaleY);
                colors.Add(col);
                listMatrices.Add(Matrix4x4.TRS(new Vector3(x / 255f, scaleY / 2, y / 255f), Quaternion.identity,
                    new Vector3(1f / 255f, scaleY, 1f / 255f)));
            }
        }

        int len = listMatrices.Count / 1000;

        if (listMatrices.Count % 1000 == 0)
            matConteiner = new MatrixConteiner[len];
        else
            matConteiner = new MatrixConteiner[len + 1];
       
        int q = 0;
        for (int i = 0; i < listMatrices.Count; i++)
        {
            if ((float)(i) % 1000 == 0)
            {
                MaterialPropertyBlock prop = new MaterialPropertyBlock();
                Matrix4x4[] mats;
               
                int count = 0;
                if (listMatrices.Count - i >= 1000) count = 1000;
                else count = listMatrices.Count - i;
                mats = new Matrix4x4[count];
                mats = listMatrices.GetRange(i, count).ToArray();
                matConteiner[q] = new MatrixConteiner(i, mats, count);

                prop.SetVectorArray("_Color", colors.GetRange(i, count));
                blocks.Add(prop);
               
                q++;
            }
        }
        Camera.main.GetComponent<GameCamera>().Init(new Vector3(size.x / 2 / 255f, 0, size.y / 2 / 255f));       
    }

     void Update ()
     {   
    
        for (int i = 0; i < matConteiner.Length; i++)
        {
            Graphics.DrawMeshInstanced(mesh, 0, mat, matConteiner[i].matrix, matConteiner[i].count, blocks[i],                 ShadowCastingMode.Off, false, 0, RenderCam);
        }
     }

    public struct MatrixConteiner
    {
        public int i;
        public Matrix4x4[] matrix;
        public int count;

        public MatrixConteiner(int _i, Matrix4x4[] _matrix, int _count)
        {
            i = _i;
            matrix = _matrix;
            count = _count;
        }
    }
   
}

Shader:

Shader "Unlit/vertexColor"
{
    SubShader
    {

        Tags { "RenderType"="Opaque" "Queue" = "Geometry" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing
            #include "UnityCG.cginc"

            struct appdata
            {
                half4 vertex : POSITION;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                half4 vertex : SV_POSITION;
                fixed4 col : TEXCOORD1;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            UNITY_INSTANCING_CBUFFER_START (Props)
            UNITY_DEFINE_INSTANCED_PROP (fixed4, _Color)
            UNITY_INSTANCING_CBUFFER_END
           
            v2f vert (appdata v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID (v);
                UNITY_TRANSFER_INSTANCE_ID (v, o);
                o.vertex = UnityObjectToClipPos (v.vertex);
                o.col = UNITY_ACCESS_INSTANCED_PROP (_Color);
                return o;
            }
           
            fixed4 frag (v2f i) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID (i);
                return i.col;
            }
            ENDCG
        }
    }
}

Any ideas how to solve this problem? I really appreciate your time
Sorry for my english and stupid questions :slight_smile:

Did you ever solved it?

I could be wrong here…or am I?
But I think some of the meshes, “normals,” might be flipped, or messed up.
That might explain, why the 2 sides of you mesh, looks messed up and strange.

If, that is the problem:
Then try to re-flip, reset, or refix the "normals," of your mesh objects.
One way of fixing normals, is to put your 3d objects, into a 3d software program.
eg. Blender or Maya or any other 3d software etc.
And use the re-calculate/reflip normals option and that will help refix the
mesh objects normals.

Hopefully, I was able to help.

Unrelated to your issue, but you can do this far more efficiently by using Unity - Scripting API: Graphics.DrawMeshInstancedIndirect

Then most of the per-frame maths is on the GPU.

1 Like

Sadly no, project was canceled and I gave up. Maybe someday I’ll go back and look into it again just for fun

@BrandyStarbrite , I’ve used standard Unity cubes and gpu instancing, so I don’t think it’s broken normals. But thanks for the answer

Thanks! Project was closed long ago, but this probably will come in handy in future projects

1 Like