本文的标题是一个疑问句,也是我之前学习过程中觉得挺值得思考的一个东西。如果你对unity3d了解不够深入的话,我想这个问题的答案肯定不像你想的那么简单。
第一层
有的人可能会觉得问题不是太简单了嘛。回忆一下数学里的立方体定义,一个立方体自然有且只有8个顶点。
要是这么想,那你肯定只在第一层。想知道unity3d里的cube里有几个顶点吗?直接打开编辑器查看就可以了,当然不是在运行时查看stats窗口,因为即使是空场景也包含了很多隐形的顶点,大部分隐形顶点都属于场景外面用来贴天空盒子的一个包围盒。
正确的查看方式是->我们创建一个cube然后找到cube的网格文件,然后在inspector窗口的下方就会显示这个网格有几个顶点。
接着,我们就发现这里显示有24个顶点。
第二层
我相信如果有一点好奇心的同学都会想知道为什么。
那么在解释之前我们先验证一下到底是不是24个顶点,至于怎么验证,还是要写shader。
我们简单写一个将顶点沿法线方向挤出的shader
Shader "my/jc"
{
SubShader
{
Tags
{
"RenderType"="Opaque"
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 normal:NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex + v.normal * 0.1);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return fixed4(1, 1, 1, 1);
}
ENDCG
}
}
}
然后创建一个新材质应用这个shader,最后创建一个cube使用该材质,效果如下。
可以看出,这个cube直接裂开来了。
按理来说,如果将每个顶点都按法线方向挤出的话,得到的应该是一个大一圈的模型而不是裂开的模型。
我们来找一个胶囊体试一下,创建一个capsule按照上面的方法操作。
原始的capsule
使用我们shader的capsule,直接肿了一圈(当然颜色变成了纯色,但是这是因为我们没有写光照,本篇博文的重点也不在光照所以大家理解即可)
因此我的想法是正确的,如果将每个顶点都按法线方向挤出的话,得到的应该是一个大一圈的模型而不是裂开的模型。除非实际上在一个顶点的位置上不止一个顶点而且这些顶点之间没有连接
没错,大家再思考一下前面那个cube的图片,如果那个cube不是8个顶点而是24个顶点,即在cube每个顶点的位置,实际上有三个相同的且法线垂直且互不相连的顶点,那么使用我们shader之后会裂开才说得通。
第五层
那么理解了一个cube实际上有24个顶点,就要回到unity为什么这么设计了。原因只有一个,如果一个cube有8个顶点,那么它的uv坐标将非常难设置,大家可以自己试一下,自己用网格类创建一个cube,然后尝试将一张二维纹理完整的贴在上面。
之前我写过一篇文章讲解mesh的用法 链接
只要试一下,就知道在纹理不出现非常严重的走样的情况下是不可能的。因为一个立方体展开之后是一个十字的形状。
unity采用了一种非常简单的变通方法,那就是给cube贴图的时候,实际上是每个面都重复贴一次。
如图所示,大家平时使用的时候肯定也都注意到了。
而既然unity采用这种方式,那么很明显每个顶点处的uv坐标,单单用一个顶点是设置不了的,因为每个顶点实际上都同时属于三张图片的uv坐标,也就是同时邻接于三张图片,因此必须具有三套uv坐标才可以,因此,每个顶点处其实有三个重合的顶点。
总结一下就是,将一张二维纹理完整的贴在一个立方体上且不走样很困难,
除非是精心设计一种不具有通用性的uv坐标。因此unity使用了一种贴纹理时cube每个面都重复贴一张纹理的设计。而这种设计带来的结果就是一个顶点同时属于三张图片的uv坐标,因为实际上需要三个共点的顶点才能实现这种效果,所以最后一个cube所需的顶点数是3*8=24个顶点
本文代码也传到github仓库里了,大家也可以关注一下哦~
我的github