Model Matrix for UI Rendering

Hello, working on a custom UI rendering system.

I’m working on a custom UI rendering system. The main idea is that each ‘Panel’ is drawn using a CommandBuffer. A ‘Panel’ contains ‘Layers,’ which are GameObjects with an Image and a RectTransform component.

Everything seems to work when I set the pivot and anchor settings to the center, but I’m having trouble rendering the layers correctly with different pivot settings. The issue is that I’m not calculating the model matrix correctly for the panel and each layer. How does Unity handle this in their UI rendering system?

How my Hierarchy setup looks like:
image

also my drawing code:

// Layer.cs
public void draw()
{
    if (visible) {
        material.SetColor("_Color", new Color(1, 1, 1, opacity));
        buffer.DrawMesh(mesh, image.rectTransform.localToWorldMatrix, material);
    }
}
// Panel.cs

void draw()
{
#if UNITY_EDITOR
    if (layers.isNull() || layers.Length == 0 || size.x <= 1 || size.y <= 1)
        return;
#endif

    if (renderTarget.isNull() || renderTarget.width != (int)rectTransform.sizeDelta.x || renderTarget.height != (int)rectTransform.sizeDelta.y) {
        if (renderTarget.isNotNull())
            RenderTexture.ReleaseTemporary(renderTarget);
        renderTarget = RenderTexture.GetTemporary((int)rectTransform.sizeDelta.x, (int)rectTransform.sizeDelta.y);
    }

    buf.Clear();
    buf.SetRenderTarget(renderTarget);
    buf.ClearRenderTarget(true, true, backgroundColor, 1.0f);

    float hWidth = width * 0.5f;
    float hHeight = height * 0.5f;

    float w = Mathf.Round(hWidth);
    float h = Mathf.Round(hHeight);

    var pm = Matrix4x4.Ortho(-w, w, -h, h, -10, 1000);

    buf.SetProjectionMatrix(pm);
    buf.SetViewMatrix(transform.worldToLocalMatrix);

    foreach (var layer in layers)
        layer.draw();

    Graphics.ExecuteCommandBuffer(buf);

    image.texture = renderTarget;
    image.color = new Color(1, 1, 1, opacity);
}

So you know, the 2D tags should only be used when discussing 2D specific features and not UI (UGUI); those have their own tags for their own areas. Using those tags puts your question in the 2D product area which isn’t correct.

I’ll go ahead and remove those tags.

Thanks.

1 Like

Solved like this

// Panel.cs

  // -------------------------------------------------------------------------
  void setViewProjectionMatrices()
  {
    float hWidth = width * 0.5f;
    float hHeight = height * 0.5f;

    float w = Mathf.Round(hWidth);
    float h = Mathf.Round(hHeight);

    var pm = Matrix4x4.Ortho(-w, w, -h, h, -10, 1000);

    buf.SetProjectionMatrix(pm);
    buf.SetViewMatrix(Matrix4x4.identity);
  }

Previously view matrix was panel’s own transform

// Layer.cs
  // -------------------------------------------------------------------------
  public void draw()
  {
    if (visible) {
      rt.ForceUpdateRectTransforms();
      material.SetColor("_Color", new Color(1, 1, 1, opacity));

      var panelTransform = panel.transform as RectTransform;
      var anchorPointInPanel = ((Vector3) Vector2.Scale(panelTransform.sizeDelta, rt.anchorMin));

      var position = (rt.anchoredPosition3D + anchorPointInPanel) - ((Vector3) panelTransform.sizeDelta * 0.5f);

      var m = Matrix4x4.TRS(position, transform.localRotation, transform.localScale);
      buf.DrawMesh(mesh, m, material);

    }
  }

I’m not sure if rt.ForceUpdateRectTransforms(); is neccessary or not.