Custom Mesh Rendering under UI Canvas

I am trying to render a custom mesh in the new GUI system. I have a UI Canvas and then a small hierarchy of game objects under them is a game object with a custom mesh. I can’t seem to get it to render…

I have made sure that my hierarchy are all using the “UI” layer and tried to add Canvas Renders at each level, including the custom mesh.

Any advice?

HI, you can add a canvas renderer and manually set the vertices. We will be adding support for making any ‘renderer’ work with the UI in a future release.

1 Like

Thanks Tim,
I have been doing that and its been working great.

Hey etoreo, would it be possible to post a small code example of how you're doing this ("manually set the vertices")? I'm not quite sure what Tim means. Thanks!

Here is some code I am using in my project (pGo is the Game Object somewhere under a canvas):

Thanks!

@Tim-C Is there a way to pass triangles through to the canvas renderer?

Because CanvasRenderer seems to want quads, and any imported mesh data that comes through is going to be in triangle form.

I know we can pass each triangle as [0] [0] [1] [2] but that is wasting a vertex per triangle?

Thanks!

@Wahooney It is my understanding that the underlying code optimizes the mesh and will eliminate that extra vertex.

@etoreo_1 in your script you do: pCanvasRenderer.SetVertices(pVertexList); what does your pVertexList look like? And where are you setting the uvs? Thanks!

No currently we dont support triangles and we always assume quads. in the future we plan on adding support for this.

Bump @Willkuerlich 's question, I'm wondering the same thing! Not sure how to get a UIVertex array from a mesh.

@phil-Unity & @Tim-C Thanks for sharing some insight into Unity's plans. I too would love to have the CanvasRender accept triangles or to just use a MeshRenderer is another way to do it.

Maybe you could answer a question I have: Why does "CanvasRenderer" appear to inherits from "Component" and not "Renderer"? I was working on a custom UI Graphic type and wanted to set (2) textures for (2) [PreRenderData] properties in my custom UI shader. I was surprised to find that I could not use SetPropertyBlock and that the SetMateral(Material, Texture) will only change the _MainTex.

@BrainAndBrain & @Willkuerlich :

UIVertex vert;
Mesh mesh;
List<UIVertex> pVertexList = new List<UIVertex>();
int[] indices = mesh.GetIndices();
for (int i=0; i<indices.Length; i+=3) {
    for (int p=0; p<3; p++) {
        vert = new UIVertex();
        vert.position = mesh.vertices[indices[i+p]];
        vert.normal = mesh.normals[indices[i+p]];
        vert.uv0 = mesh.uv0[indices[i+p]];
        //do the same for tangent, uv1, and color if you need to.
        pVertexList.Add(vert);
    }
    //This just adds the last vertex twice to fit the quad format.
    pVertexList.Add(vert);
}

@phil-Unity & @Tim-C I work on a custom system too and this is quite painfull to not inherits from Renderer.
My system was using the enabled/disabled system from renderer and with the CanvasRenderer it’s impossible ?

Some people says SetAlpha to 0 with a CanvasGroup but it’s not really a good solution cause the mesh are always rendered even if the user can’t see them.
Others people says do a SetActive to false but it’s not a viable solution for me too cause if the object has a script that need to be used for some reason the Update state will not be displayed ( except if i’m wrong on this part ? )

Why this “CanvasRenderer” that you called as Renderer doesn’t follow the Renderer functionalities ?

its not derived as the CanvasRenderer's are all batched together and then we create a meshRenderer from that. It itself is not renderable.

@phil-Unity ah ha! that would explain it. Thanks for the info.

Although, maybe it shouldn’t be called a “Renderer” then. Maybe “CanvasBatcher” or something. Probably too late for that; that ship has sailed. Alternatively, Unity should work to pass-through or emulate as much functionally from the mother MeshRenderer to the CanvasRenderer. ie. Setting triangle indices or just accept a mesh, enabled/disabled individual graphics, Setting Property Blocks beyond just the MainTex, etc.

Also, just a quick side note. UIVertex doesn’t seem to be set as serializable. That might work for you all but it would be great if I could save and reuse my List.

Thanks for your answer @phil-Unity ! That explain a lot of things :)

Oh so just one more thing :
Use a CanvasGroup to hide all the elements with alpha would change nothing cause all the UI is render as one mesh ?

But use a SetActive force your batching to regenerate one mesh ? Or did you just hide his visual and let him in the global MeshRenderer ?

@Liszt I just saw in the 4.6.3 release notes:

"UI: Optimized adding/removing Graphics to a Canvas. It should be much cheaper to enable and disable Graphics now."

Maybe that will help with your issues.

@Willkuerlich

Sorry it has taken so long to respond. My vertext list looks like this… but I should note that something about my code is not working in 4.6.3. Trying to work that out now.

Rect pDrawArea = DrawArea;
Vector3 a = new Vector3(pDrawArea.xMin, pDrawArea.yMax, 0);
Vector3 b = new Vector3(pDrawArea.xMax, pDrawArea.yMax, 0);
Vector3 c = new Vector3(pDrawArea.xMin, pDrawArea.yMin, 0);
Vector3 d = new Vector3(pDrawArea.xMax, pDrawArea.yMin, 0);

UIVertex pUIVertex = new UIVertex();

pUIVertex.position = c;
pUIVertex.uv0 = new Vector2(1, 1);
pList.Add(pUIVertex);

pUIVertex.position = a;
pUIVertex.uv0 = new Vector2(0, 0);
pList.Add(pUIVertex);

pUIVertex.position = b;
pUIVertex.uv0 = new Vector2(0, 1);
pList.Add(pUIVertex);

pUIVertex.position = d;
pUIVertex.uv0 = new Vector2(1, 0);
pList.Add(pUIVertex);

@etoreo_1 thanks for posting your code. I can render the mesh but it is all black no matter what material I use. Any ideas what might be causing this? Thanks!

EDIT: never mind, forgot to set the normals

Glad I could help ;)