You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在World Space模式的Canvas上直接绘制自定义Mesh?

解决World Space Canvas中CanvasRenderer.SetMesh()无显示的问题

你遇到的核心问题是CanvasRenderer与普通MeshRenderer的坐标空间、依赖组件要求完全不同,直接复用MeshFilter的Mesh逻辑会因为坐标不匹配、缺少必要设置而无法显示。以下是具体修复方案:

关键问题分析

  • 坐标空间差异:World Space模式的Canvas虽处于世界空间,但CanvasRenderer渲染的Mesh使用的是RectTransform的本地坐标(原点默认在RectTransform中心),你之前的顶点是基于Canvas Rect左下角(0,0)计算的,两者坐标系不匹配。
  • 缺少必要配置:CanvasRenderer需要绑定UI专用材质,且Mesh必须设置UV坐标才能让材质正确显示。
  • 性能浪费:Update中每次创建新Mesh会导致大量GC,应该复用Mesh对象。

修复步骤

1. 调整组件配置

移除物体上的MeshFilter和MeshRenderer,添加CanvasRenderer组件;确保物体是World Space Canvas的子物体,且自身带有RectTransform。

2. 修改代码逻辑

以下是修复后的完整代码,包含坐标转换、材质绑定、Mesh复用等优化:

using UnityEngine;

public class MeshCanvas : MonoBehaviour
{
    private Vector3[] vertices;
    private int[] triangles;
    private Vector2[] uv;
    private Mesh mesh;
    private RectTransform canvasRectTransform;
    private CanvasRenderer canvasRenderer;

    public float offset = 10f;
    public Material uiMaterial; // 拖拽UI材质(如内置的UI/Default)到这里

    private void Awake()
    {
        // 缓存组件,避免重复查找
        canvasRectTransform = FindObjectOfType<Canvas>().GetComponent<RectTransform>();
        canvasRenderer = GetComponent<CanvasRenderer>();
        mesh = new Mesh();
        // 初始化三角形数组(固定不变,无需重复创建)
        triangles = new int[]
        {
            0, 1, 2,
            2, 3, 0
        };
    }

    private void Update()
    {
        UpdateMesh();
    }

    private void UpdateMesh()
    {
        var canvasRect = canvasRectTransform.rect;
        float canvasWidth = canvasRect.width;
        float canvasHeight = canvasRect.height;

        // 将基于左下角的坐标转换为RectTransform本地坐标(原点在中心)
        vertices = new Vector3[]
        {
            new Vector3(-canvasWidth/2 + offset, -canvasHeight/2 + offset),
            new Vector3(-canvasWidth/2 + offset, canvasHeight/2 - offset),
            new Vector3(canvasWidth/2 - offset, canvasHeight/2 - offset),
            new Vector3(canvasWidth/2 - offset, -canvasHeight/2 + offset)
        };

        // 设置UV坐标,确保材质纹理正确映射
        uv = new Vector2[]
        {
            new Vector2(0, 0),
            new Vector2(0, 1),
            new Vector2(1, 1),
            new Vector2(1, 0)
        };

        // 更新Mesh数据
        mesh.Clear();
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.uv = uv;
        mesh.RecalculateBounds(); // 必须重新计算包围盒,否则CanvasRenderer可能不渲染

        // 绑定Mesh和材质到CanvasRenderer
        canvasRenderer.SetMesh(mesh);
        if (uiMaterial != null)
        {
            canvasRenderer.SetMaterial(uiMaterial, null);
        }
    }
}

3. 材质设置

在Inspector面板中,将Unity内置的UI/Default材质拖拽到脚本的uiMaterial字段上(如果没有该材质,可以在Project窗口右键创建UI -> Default Material)。

额外注意事项

  • 如果Canvas的尺寸动态变化,建议监听RectTransform.sizeDelta的变化,只在尺寸改变时更新Mesh,避免Update中频繁计算。
  • World Space Canvas的缩放会影响Mesh的显示大小,若需要保持Mesh相对Canvas的比例,可在计算顶点时考虑Canvas的缩放值。

内容的提问来源于stack exchange,提问作者ZoKi Mo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 11:31:04