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

使用Point(no filter)纹理时Unity Mesh出现环形着色故障求助

问题:Unity中使用Point滤波纹理时相机周围出现同心环形变色故障

故障现象

相机(包括玩家相机与场景编辑器相机)周围会出现同心环形变色区域。

复现步骤

  • 创建新Unity项目(测试了3D(URP)和3D(HDRP)模板,均存在该问题)
  • 创建空GameObject,添加Mesh Filter和Mesh Renderer组件
  • 为该GameObject挂载以下脚本
  • 导入纹理资源,设置Filter Mode为Point(no filter),拖至GameObject
  • 运行游戏
  • 移动场景编辑器相机即可看到故障,也可将Main Camera对准生成的Mesh在游戏窗口查看

切换Filter Mode为非Point模式时故障消失,但会导致像素画模糊,因此不考虑该方案。求问故障原因及可行修复方法?

脚本代码

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

public class TerrainGenerator : MonoBehaviour
{
    public int width = 100;
    public int height = 100;

    Mesh mesh;

    List<Vector3> vertices = new List<Vector3> ();
    List<int> triangles = new List<int>();
    List<Vector2> uvs = new List<Vector2>();

    int vertexCounter = 0;

    // Start is called before the first frame update
    void Start() {
        mesh = gameObject.GetComponent<MeshFilter>().mesh;

        mesh.Clear();
        vertices.Clear ();
        triangles.Clear ();
        uvs.Clear ();

        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                addFace(i, j, 1, 1);
            }
        }

        mesh.vertices = vertices.ToArray();
        mesh.triangles = triangles.ToArray();
        mesh.uv = uvs.ToArray();

        mesh.RecalculateNormals();
    }

    private void addFace(int x, int y, int width, int height) {
        vertices.Add(new Vector3(x, 0, y));
        vertices.Add(new Vector3(x, 0, y + height));
        vertices.Add(new Vector3(x + width, 0, y));
        vertices.Add(new Vector3(x + width, 0, y + height));
        vertices.Add(new Vector3(x + width, 0, y));
        vertices.Add(new Vector3(x, 0, y + height));

        triangles.Add(vertexCounter++);
        triangles.Add(vertexCounter++);
        triangles.Add(vertexCounter++);
        triangles.Add(vertexCounter++);
        triangles.Add(vertexCounter++);
        triangles.Add(vertexCounter++);

        uvs.Add(new Vector2(0, 0));
        uvs.Add(new Vector2(0, 1));
        uvs.Add(new Vector2(1, 0));
        uvs.Add(new Vector2(1, 1));
        uvs.Add(new Vector2(1, 0));
        uvs.Add(new Vector2(0, 1));
    }
}

故障原因

这是Point滤波纹理的UV采样精度与透视投影冲突导致的:

  • 当前代码中每个小四边形面的UV都设置为(0,0)-(1,1),意味着每个面都在采样整张纹理。当相机远离Mesh时,屏幕单个像素会覆盖大量相邻的小面,Point滤波的"取最近纹理像素"逻辑,会在这些面的UV采样点间跳变;加上透视投影的非线性特性,最终形成周期性的同心环形颜色偏差。
  • 本质是透视下的UV采样走样,Point滤波无插值过渡,直接采样离散的纹理像素,多个相邻面的采样点在屏幕空间重叠时,就会出现这种视觉故障。

修复方法

方法1:修正UV映射逻辑(最优解)

让每个小面对应纹理的单个像素区域,而非整张纹理。修改addFace方法中的UV赋值逻辑:

// 先在脚本顶部添加公开纹理引用
public Texture2D pixelTexture;

// 替换addFace方法中的uv.Add代码
float uvStepX = 1f / pixelTexture.width;
float uvStepY = 1f / pixelTexture.height;

uvs.Add(new Vector2(x * uvStepX, y * uvStepY));
uvs.Add(new Vector2(x * uvStepX, (y + height) * uvStepY));
uvs.Add(new Vector2((x + width) * uvStepX, y * uvStepY));
uvs.Add(new Vector2((x + width) * uvStepX, (y + height) * uvStepY));
uvs.Add(new Vector2((x + width) * uvStepX, y * uvStepY));
uvs.Add(new Vector2(x * uvStepX, (y + height) * uvStepY));

这样每个小面仅对应纹理的一个像素区域,Point滤波能精准采样,环形故障会完全消失。

方法2:配合纹理Wrap Mode优化

在纹理的Import Settings中,将Wrap Mode设置为Clamp,避免UV边缘的采样溢出,配合方法1使用可进一步提升稳定性。

方法3:自定义Shader处理(复杂场景适配)

如果必须保留原UV逻辑,可以在URP/HDRP的自定义Shader中,添加透视校正的采样处理,或在片元着色器中对UV进行平滑过渡。该方法需要Shader编写能力,适合无法修改Mesh UV的场景。

内容的提问来源于stack exchange,提问作者jared goddard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 19:10:51