最近在做 3D 麻将项目时,遇到一个很典型但又很容易误判的问题:
- 贴图过滤设置成
bilinear with mipmaps时,麻将牌离摄像机稍微远一点,侧边就会明显发黑 - 贴图过滤设置成
bilinear时,黑边问题没了,但侧边又会偏白
第一眼看上去很像是灯光、法线、材质参数或者模型本身有问题,但实际排查下来,核心原因通常不是光照,而是:
Mipmaps 和透明通道一起使用时,透明区域的 RGB 颜色污染了低层级贴图。
这篇文章把这个问题完整总结一下。
一、现象描述
在 3D 场景里,麻将牌通常会有以下特点:
- 牌面贴图是带透明通道的 PNG
- 牌本体是白色或浅色
- 牌边或牌面会以贴图的方式贴到模型某个面片上
- 摄像机会以斜视角、远近变化的方式观察牌
这时会出现两种现象:
1. 开启 bilinear with mipmaps
近处看没问题,远处看牌边开始发黑,尤其是侧边、轮廓边缘最明显。
2. 设置为 bilinear
黑边明显减轻甚至消失,但远处边缘又可能偏亮、偏白,或者看起来不够稳定。
二、Mipmaps 到底做了什么?
Mipmaps 是一套"缩小版纹理链"。
例如一张 1024x1024 的贴图,开启 mipmaps 后,系统会自动生成:
512x512256x256128x12864x64- ...
当物体离摄像机较远、屏幕上占用像素较少时,GPU 不会继续硬采样原始大图,而是优先采样更小的 mip 级别。这样做有几个好处:
- 降低闪烁
- 降低锯齿
- 提升采样效率
- 让远处纹理更稳定
所以从理论上说,Mipmaps 本身是好东西。
问题出在:你的贴图是带透明通道的。
三、真正的根因:透明区域的 RGB 污染
很多人以为 PNG 透明了就"什么都没有",其实不是。
一张带 Alpha 的图片里,通常同时包含两部分信息:
- RGB 颜色
- Alpha 透明度
哪怕某个像素是完全透明的,它的 RGB 仍然是有值的。
而很多美术资源在透明区域里,RGB 默认正好是:
- 黑色
(0, 0, 0) - 或者导出时残留的深色边缘
于是问题来了。
当开启 mipmaps 时
GPU 在生成低分辨率 mip 层时,会对一片区域做缩小和平均。
如果这片区域里同时包含:
- 牌面边缘的白色像素
- 周围透明区域里的黑色 RGB
那缩小后得到的颜色就会偏灰、偏黑。
最终结果就是:
- 近处采样原图时还不明显
- 远处采样低级别 mip 时,黑色越来越明显
- 看起来像牌边"被染黑"了一样
这就是很多项目里常见的:
远处黑边、透明边发脏、轮廓发暗
四、为什么关掉 mipmaps 后又变白?
把过滤模式改成 bilinear,通常意味着不再使用 mipmaps,或者只在原始分辨率上做双线性采样。
这时候:
- 采样主要发生在最高分辨率贴图上
- 低层级 mip 中那些被平均出来的黑色不再参与
- 所以远处的"黑边"会明显减少
但为什么又会"偏白"?
因为这时边缘采样主要受以下因素影响:
- 原始贴图边缘本身是白色或浅色
- Clamp / UV 边缘取样时更容易拉到白边
- 模型侧边本来就是浅色材质
- 没有 mip 平滑后,边缘混合方式变化了
所以你看到的不是"问题完全消失",而是从"黑色污染"变成了"浅色边缘更明显"。
换句话说:
with mipmaps:黑色污染更明显bilinear only:白边或亮边更明显
本质上都是 边缘颜色和透明区 RGB 的采样结果 不理想。
五、这不是灯光问题吗?
很多人第一反应会去查:
- 法线错了?
- 模型翻面了?
- 材质受光异常?
- PBR 参数有问题?
- 环境光太弱?
这些方向不能说完全没可能,但如果你的表现是:
- 近处正常
- 远处才黑
- 关闭 mipmaps 立刻缓解
那基本就可以先判断:
优先不是灯光问题,而是贴图采样问题。
尤其是带透明通道的 UI 面片、牌面贴花、Decal、小面片纹理,最容易中招。
六、怎么确认就是这个问题?
可以按下面的方法快速排查。
1. 看贴图是否有透明通道
如果资源是 PNG,并且边缘周围是透明区域,那就要高度怀疑。
2. 开关 mipmaps 对比
直接做 A/B 测试:
bilinearbilinear with mipmaps
如果黑边只在后者明显出现,基本就对上了。
3. 观察远近变化
让牌从近到远移动:
- 近处正常
- 远处开始发黑
这就是典型的 mip level 切换现象。
4. 看透明区域的 RGB
把图放到支持查看 Alpha 和 RGB 的工具里检查一下。
很多时候你会发现:
- Alpha 是透明的
- 但 RGB 其实是黑的
这就是污染源。
七、最推荐的解决方案
下面按实际项目里最常用、最有效的方式来讲。
方案 1:开启透明边缘修复
如果引擎导入设置里有类似选项:
Fix Alpha Transparency ArtifactsAlpha BleedColor BleedAlpha is Transparency
优先开启它。
它的作用通常是:
在生成 mipmaps 前,把透明区域的 RGB 修正成周围可见像素的颜色,而不是保留黑色。
这样即使后面做 downsample,平均出来的颜色也不会发黑。
这是最省事、最工程化的做法。
方案 2:给源图做边缘颜色外扩
这是从资源侧彻底解决的方法。
做法是:
- 保持透明区域仍然透明
- 但把透明区域里的 RGB 颜色扩成和边缘一致的颜色
- 比如牌边是白色,就把边缘外扩几圈白色像素到透明区里
注意,这里说的是:
扩 RGB,不是把透明区真的画实。
这样生成 mipmaps 时,哪怕低分辨率层级把透明边和实体边混到一起,结果仍然是接近白色或接近真实边缘颜色,而不是黑色。
这个方法在游戏美术里非常常见,通常叫:
- Padding
- Dilate
- Extrude
- Alpha Bleed
方案 3:对不需要远景缩小的贴图直接关闭 mipmaps
如果某类贴图本身就不太需要 mipmaps,比如:
- 小尺寸牌面图
- 始终不会出现在超远景里的麻将牌贴花
- 很薄的小面片纹理
那可以直接关闭 mipmaps。
优点:
- 简单直接
- 黑边问题立刻缓解
缺点:
- 远处可能更容易闪烁
- 斜视角下稳定性可能差一些
- 并不是根治,只是绕开
如果这是一个固定视角麻将项目,这种方案其实很实用。
方案 4:提高各向异性过滤
如果麻将牌经常以斜角出现在镜头里,可以适当提高:
Anisotropy = 4Anisotropy = 8
它主要解决的是:
- 斜视角模糊
- 远处采样质量差
- 纹理稳定性不足
它不能根治黑边污染,但能提升整体观感,尤其对桌面类、牌类、地面类斜角贴图很有帮助。
八、为什么麻将牌这种资源特别容易出问题?
因为它刚好踩中了几个高危条件:
- 牌面常用带透明通道的 PNG
- 牌面边缘通常是浅色、白色
- 模型很薄,边缘区域视觉占比高
- 摄像机常常从斜上方看
- 同一张牌会频繁出现在不同距离
- 轮廓对比强,黑一点就特别明显
所以麻将、扑克牌、棋子、UI 面片、贴花、角色描边贴图,这些资源都特别容易出现这种问题。
九、项目里的实战建议
如果是麻将项目,我一般建议这样处理:
对"牌面贴花 / Decal / 小面片纹理"
- 优先开启透明伪影修复
- 保证透明区域 RGB 不是黑色
- 有条件就让美术做边缘外扩
- 如果资源固定、镜头稳定,也可以直接关 mipmaps
对"牌体本身的实体材质"
- 正常保留 mipmaps
- 必要时提高 anisotropy
- 重点看法线、高光、粗糙度,不要和贴花问题混在一起
对"远处仍然能看清轮廓的小牌"
- 如果边缘依然敏感,优先从资源入手
- 不要只靠改材质参数硬顶
十、一个容易忽略的关键点
很多人只看"透明不透明",但真正要关注的是:
透明区域虽然不可见,但它的 RGB 仍然会参与 mipmap 计算。
这句话几乎就是整件事的核心。
只要记住这点,很多类似问题都能迅速定位:
- 透明图远处黑边
- UI 图标缩小时边缘发脏
- 粒子贴图远处轮廓变黑
- 角色头发卡片远处发灰
本质都很接近。
十一、结论
3D 麻将贴图在开启 bilinear with mipmaps 后,远处侧边发黑,而改成 bilinear 后侧边又偏白,核心原因通常不是模型或灯光,而是:
带透明通道的贴图在生成 mipmaps 时,透明区域中的 RGB 颜色参与了缩小平均,导致边缘被污染。
可以把它简单理解成:
- 开 mipmaps:透明区里的黑色被混进来了,所以发黑
- 关 mipmaps:黑色不怎么参与了,但边缘原本的浅色更明显,所以发白
最有效的处理顺序通常是:
- 开启透明伪影修复
- 给贴图透明边做颜色外扩
- 必要时关闭这类贴图的 mipmaps
- 斜视角场景补充 anisotropy
十二、一句话总结
Mipmaps 本身没问题,问题在于透明区域的 RGB 不干净;远处发黑,本质上是低层级贴图把透明区的黑色一起算进去了。