https://zhuanlan.zhihu.com/p/126752791
前文所说,贴图多UV,直接命名对应贴图就可以。
模型的多套UV,则需要在3DMAX里编辑。
这篇文章主要解决两个问题:
- 如何正确使用多模型UV? 从3DMAX导出,到shader使用
- 如何优化模型导出的内存占用?
1.模型导出会有几套UV?
如果在3d模型中只做了一套uv,将模型导入unity的时候,在导入设置中勾选Generate Lightmap UVs, unity会自动为我们生成用于光照贴图的uv1,和用于动态光照的uv2
比如Unity自带的物体box,sphere就自带两套uv
第一套是正常的,比如方块可以每个面是同一个uv,
但是第二套需要烘焙光照信息,所以默认是全展开,纹理看出来要小些。
也有一些材质会用到四套UV,比如Unity的speedtree。
2.模型多UV有什么作用
做很多效果时,使用多UV可以避免使用多材质,或者多贴图,性能更好。
其实额外的UV可以替代很多mask贴图实现的效果。
3. 如何自己在模型中添加第二套UV
3DMax和maya等软件都能对模型加多套uv
注意模型在fbx里可以保留多套uv,但是obj里只能保留默认的第一套
另外unity里现在貌似支持最多四套
开始在3DMAX里制作两套UV
uv0
UV1
这是我们刚才操作过的茶壶,现在它多出了个MAP2,也就是我们的第二套UV。
我们使用下面的Shader在Unity里测试:
Shader "UV/multiTextureUV" {
Properties{
_MainTex("Texture", 2D) = "white" { }
}
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma target 3.0
sampler2D _MainTex; uniform float4 _MainTex_ST;
struct appdata {
float4 vertex : POSITION;
// 多套uv的语义声明
float2 texUV0 : TEXCOORD0;
float2 texUV1 : TEXCOORD1;
float2 uv3 : TEXCOORD2;
float2 uv4 : TEXCOORD3;
float2 uv5 : TEXCOORD4;
};
struct v2f {
float4 pos : SV_POSITION;
float2 uv_MainTex : TEXCOORD0;
float2 uv2_Tex_002 : TEXCOORD1;
};
//顶点函数
v2f vert(appdata input)
{
v2f o;
o.pos = UnityObjectToClipPos(input.vertex);
o.uv_MainTex = input.texUV0;
o.uv2_Tex_002 = input.texUV1;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed2 main_uv = i.uv_MainTex;
fixed2 _Tex_2_uv = i.uv2_Tex_002;
//在这里替换测试
//如果没有多套uv 后面的值还是会返回uv0
//return tex2D(_MainTex, _Tex_2_uv);
return tex2D(_MainTex, main_uv);
}
ENDCG
}
}
}


结果如上,我们实现了 不同模型UV的采样。
当然这个是会影响烘焙光照的。 因为Unity默认使用第二套UV作为lightmap的采样UV。
如果我们导入的模型使用了第二套UV,Unity就不会自动给模型加入第二套UV了。
4.解决unity导入模型内存占用
4. 1删除color
经过验证,在3DMAX里,制作一个模型导出,一般情况,美术人员没有手动修改,只会多出一个color,然而我们大多数情况不需要,可以删除。
如果想去掉color通道的话直接去掉alpha通道就行。
我们把刚才茶壶的color通道删除,惊喜的发现,模型变小了,并且它占用Unity的内存也会变小。
4. 2删除多层UV通道
某些时候,因为美术的一些意外操作,会引入多个我们不需要的UV通道。
由于unity的光照贴图会自动占用uv2通道,如果你的项目中又使用的是动态加载光照贴图的方式的话,最好不要在导入模型的时候把UV2设置为null,如果你这样做了有可能会导致光照贴图显示不出来的问题。
如果物体不需要烘培,你自己也不使用uv2,则可以删除该通道。
方法一:
在max中进行设置把没有必要的通道全部clear掉,具体的操作请看下面的截图:
方法二:
程序这边进行处理,做一个工具,对每个导入到unity中的模型代码中清除相应的通道,具体的代码如下
public class ClearModelUV:AssetPostprocessor
{
void OnPostprocessModel(GameObject rImaportModel)
{
this.ClearMeshUVAndColorChannel(rImaportModel);
}
private void ClearMeshUVAndColorChannel(GameObject rImportModel)
{
List<Vector2> rNewUV = null;
List<Color32> rNewColor = null;
var rFilters= rImportModel.GetComponentsInChildren<MeshFilter>();
for (int filter_index = 0; filter_index < rFilters.Length; filter_index++)
{
rFilters[filter_index].sharedMesh.SetColors(rNewColor);
rFilters[filter_index].sharedMesh.SetUVs(1, rNewUV);
rFilters[filter_index].sharedMesh.SetUVs(2, rNewUV);
rFilters[filter_index].sharedMesh.SetUVs(3, rNewUV);
}
}
}