欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

程序员文章站 2022-03-03 08:24:47
目录二、hello mesh三、萌新初识mesh1、引擎内置的mesh2、mesh是什么三、mesh的创建方式2、unity建模插件:probuilder四、unity中如何显示网格1、meshfil...

一、前言

嗨,大家好,我是新发。
有同学私信我让我写一篇unity网格相关的教程,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

那我就带大家来一次unity的网格探险之旅吧~

二、hello mesh

我背着旅行背包走在unity的场景中,突然眼前出现了一棵树,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我走近一看,这棵树身上挂着meshfiltermeshrenderer组件,根据unity探险手册记载,这个meshfilter是网格过滤器,它会引用一个网格资源,我顺腾摸瓜,找到了对应的网格,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

实在太美了,我久久伫立,这就是网格啊!
正当我欣赏着网格三角形时,突然世界暗了下来,眼前出现了一团火,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我又拿出了unity探险手册,啊,这一定就是粒子系统了!它可以动态生成网格。

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

天外传来一阵打字声,场景中出现了一行看起来像文字的网格,作为一个具有多年hello world经验的程序员,我看出了第一个单词应该是hello,第二个单词…我知道了,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

hello mesh

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

(此处为震撼人心的入场音乐)

三、萌新初识mesh

1、引擎内置的mesh

网格的英文名是meshunity萌新最先接触的网格应该就是引擎内置的cube(正方体)、capsule(胶囊体)、cylinder(圆柱体)、plane(平面)、sphere(球体)、quad(四边形),如下

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

事实上,我们在unity场景中,所有能被渲染出来的物体都会带有网格,比如3d模型、粒子特效、ui、文字等等。

2、mesh是什么

从概念上讲,网格是图形硬件用来绘制复杂内容的构造。它至少包含一组定义3d空间中点的顶点,以及一组连接这些点的三角形,实际上还包含法线、顶点颜色纹理坐标等信息,这些三角形构成了网格所代表的任何表面。

我们可以看下unitymesh类,mesh的属性和方法很多,我这里列举几个比较常用的,如下

// 顶点坐标数组
public vector3[] vertices { get; set; }
// 法线向量数组
public vector3[] normals { get; set; }
// 顶点颜色数组
public color[] colors { get; set; }
// 三角形序列数组,每三个数字为一组
public int[] triangles { get; set; }
// uv坐标数组
public vector2[] uv { get; set; }
// 重新计算法线,在修改完顶点后,通常会更新法线来反映新的变化,注意,法线是根据共享的顶点计算出来的。
public void recalculatenormals();
// 从法线和纹理坐标重新计算网格的切线。修改网格的顶点和法线之后,如果网格使用引用法线贴图的着色器进行渲染,则切线需要更新。 
public void recalculatetangents();
// 重新计算从网格包围体的顶点, 在修改顶点后需要这个函数以确保包围体是正确的,赋值三角形将自动重新计算这个包围体。
public void recalculatebounds();

画个图,方便大家有个直观印象,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

三、mesh的创建方式

1、第三方建模软件

建模本质上就是建网格,我们可以事先通过第三方建模软件来创建模型网格,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

常见的建模软件比如

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

3ds max官网:https://www.autodesk.com/products/3ds-max/overview

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

maya官网:https://www.autodesk.com/products/maya/overview

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

blender官网:https://www.blender.org/

2、unity建模插件:probuilder

unity官方提供了一个可以用来创建和自定义几何体的工具probuilder,我们可以在unitypackage manager中下载到这个插件,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

使用probuilder我们可以直接在unity中创建或编辑简单的几何体,不用通过第三方建模软件,提升了效率,方便快速搭建场景原型,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

3、程序动态生成网格

网格也可以是程序动态生成的,比如粒子系统的网格就是动态生成的,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

又比如文字,也是程序动态生成网格,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

文章后面我还会手把手教你如何使用纯代码来构建网格,这里先不急着写代码,我们继续探寻网格的秘密先~

四、unity中如何显示网格

unity中,我们要显示一个网格,需要用到两个组件:meshfiltermeshrenderer

注:你也可以直接使用skinnedmeshrenderer组件,与meshfiltermeshrenderer的区别我下文会讲。

1、meshfilter:网格过滤器

meshfilter是网格过滤器,我们需要通过它设置引用的网格资源,比如这里引用的是一个cube(正方体)网格。

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我们可以看下meshfilter.cs的源码,

[requirecomponent(typeof(transform))]
[nativeheader("runtime/graphics/mesh/meshfilter.h")]
public sealed partial class meshfilter : component
{
    [requiredbynativecode]  // meshfilter is used in the vr splash screen.
    private void dontstripmeshfilter() {}

    extern public mesh sharedmesh { get; set; }
    extern public mesh mesh {[nativename("getinstantiatedmeshfromscript")] get; [nativename("setinstantiatedmesh")] set; }
}

meshfilter只有两个属性:meshsharedmesh
我们查看unity的官方手册,看看meshsharedmesh的区别:https://docs.unity3d.com/scriptreference/meshfilter.html

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我来解读一下,mesh访问的是一个mesh资源的实例(副本),这意味着我们修改这个mesh并不会修改到原始资源本身,改的只是mesh的实例(副本)。
sharedmesh是原始资源的引用,如果修改了sharedmesh,比如修改顶点坐标,那么原始资源也会被修改。
画成图大概是这样子:

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

这里我顺手写个随机修改mesh顶点坐标的脚本,如下,将下面这个randomeshmvertices脚本挂到meshfilter组件所在的物体上即可,

// randomeshmvertices.cs
// 随机修改mesh顶点坐标
using unityengine;
public class randomeshmvertices: monobehaviour
{
    // mesh的实例
    meshfilter meshfilter;
    // 顶点的原始坐标
    vector3[] originalvertices;
    void start()
    {
        meshfilter = getcomponent<meshfilter>();
        originalvertices = meshfilter.mesh.vertices;
    }
    void update()
    {
        // 随机修改顶点坐标
        vector3[] vertices = meshfilter.mesh.vertices;
        for (int i = 0, len = originalvertices.length; i < len; ++i)
        {
            var v = originalvertices[i];
            vertices[i] = v + random.range(-0.1f, 0.1f) * vector3.one;
        }
        meshfilter.mesh.vertices = vertices;
        meshfilter.mesh.recalculatenormals();
    }
}

运行效果如下,网格顶点坐标发生了随机偏移,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

关于mesh属性的访问需要特别注意一下,我们先看看unity官方手册的说明,https://docs.unity3d.com/scriptreference/meshfilter-mesh.html

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

翻译一下就是,如果一个mesh资源已经被分配给meshfiltermesh属性,那么当我们在代码中第一次访问mesh属性时才正真创建了mesh的实例;再次访问mesh属性时则直接返回这个实例,并且一旦mesh属性被访问,则与原始共享网格的链接会丢失,此时sharedmesh变成mesh的别名,如果我们想避免这种自动生成mesh实例,可以使用sharedmesh代替。
写成伪代码的话大致是这样子:

public class meshfilter ...
{
	...
	private mesh _mesh;
	public mesh mesh
	{
		get
		{
			if (_mesh == null) 
			{
				_mesh = new mesh();
				copy(sharedmeh, _mesh);
			}
			return _mesh;
		}
	}
	...
}

还有,如果我们访问了mesh属性而导致自动创建了mesh实例,则需要在代码中主动调用resources.unloadunusedassets来销毁没有引用的mesh实例,建议是在场景切换时调用resources.unloadunusedassets

2、meshrenderer:网格渲染器

meshrenderer,顾名思义,网格渲染器。我们依旧先来看看官方手册的介绍:

https://docs.unity3d.com/manual/class-meshrenderer.html

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

翻译过来就是meshrenderer会从meshfilter那里拿到网格数据并在所在物体的位置处将其渲染出来。
如果没有meshrenderer,我们就看不见网格了,如下

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

另外,我们还需要在meshrenderermaterials中指定一个材质球,这样才能正常显示,否则模型表面就是紫色的。

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

3、skinnedmeshrenderer:蒙皮网格渲染器

skinnedmeshrenderer是蒙皮网格渲染器,可能有小伙伴就会问了,上面使用meshfiltermeshrenderer已经可以显示模型网格了,为什么又弄了一个skinnedmeshrenderer呢?
看下unity官方手册的介绍:https://docs.unity3d.com/manual/class-skinnedmeshrenderer.html

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

可以看到skinnedmeshrenderer其实是针对带 骨骼动画 的模型的渲染的。

3.1 骨骼动画

为什么需要做骨骼动画呢?

就好比我们人一样,我们的骨骼会随着我们肌肉的伸缩而动,骨骼又可以带动它管辖的身体部位发生形变和移动,骨骼还会影响它所连接的其他骨骼一起发生联动。对应到模型动作上,想想一个简单的举手动作要牵涉到多少网格顶点的移动,如果没有骨骼,那动画师要每帧挨个网格顶点进行调整,即使动画做出来了,这个动画也不能复用到其他模型上,因为不同模型的顶点信息都不一样,这么低效的动画制作肯定是不行的,于是,就有了骨骼动画。

骨骼动画的原理

就是将模型分为骨骼(bone)和蒙皮(mesh)两个部分,骨骼可分为多层父子骨骼,每个骨骼都附加到周围网格的一些顶点上,在动画关键帧数据的驱动下,计算出各个父子骨骼的位置,基于骨骼的控制通过顶点混合动态计算出蒙皮网格的顶点。

动画师可以在maya软件上给模型绑定骨骼,绑定骨骼不是本文的重点,这里就不展讲开具体操作了,感兴趣的同学可以自行百科学习。

制作好导出为fbx格式,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

fbx文件导入到unity中,选中它,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

inspector视图中点击rig按钮,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我们可以看到动画类型animation typenonelegacygenerichumanoid四个,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

具体选项可以参见unity官方手册:https://docs.unity3d.com/manual/fbximporter-rig.html

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我这里演示一下人形骨骼动画,选择humanoid类型,avatar definition选择create from this model,然后点击configure

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

inspector视图中我们就可以看到对应的骨骼绑定信息了,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

如下,绿色的线段就是一根根骨骼,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我们调整一根骨骼,对应的网格也会跟着一起动,如下

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

这样做出来的人形动画是可以进行复用了,有请妹子上场,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

骨骼动画资源的话,我在之前的文章中也介绍过一个宝藏网站mixamohttps://www.mixamo.com/,上面有很多做好的人形骨骼动画,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

看,是不是挺好玩的,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我们可以把它的动作直接复用到我们自己的人形模型上,效果如下:

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)
游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)
游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

3.2 skinnedmeshrenderer组件

骨骼动画可以正常播放,要归功于skinnedmeshrenderer组件,制作好骨骼动画的fbx文件导入unity中,unity会自动帮我们挂上skinnedmeshrenderer组件,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

其中几个重要的属性我讲一下,
bounds:骨骼数据;
mesh:要渲染的网格;
root bone:根骨骼,其他骨骼都是相对根骨骼移动的;
blendshapes:一般用于制作表情融合,我之前写过一篇文章讲过blendshapes

unity通过blendshape实现面部表情过渡切换animation教程

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我们再来看看skinnedmeshrenderer脚本的属性和方法:

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

需要讲的应该就是这个bakemesh方法了,下面我就单独拎出来讲下bakemesh

3.2 使用bakemesh进行优化

假设现在场景中有100只皮卡丘,每只皮卡丘的网格、贴图、动作相同,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

如果每只皮卡丘身上都挂skinnedmeshrenderer,那就是100skinnedmeshrenderer在计算蒙皮,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

由于skinnedmeshrenderer是根据骨骼动画动态计算网格顶点坐标,这个运算开销还是不小的,有没有办法优化呢?

skinnedmeshrenderer提供了一个bakemesh方法,可以将一个蒙皮动画的某个时间点上的动作,bake成一个不带蒙皮的mesh,我们统一使用这个mesh来显示其余的皮卡丘,这样就可以大大减少了skinnedmeshrenderer的计算了,
画成图大概是这样子:

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

不过,上面这种方案的局限性是每只皮卡丘的动画是相同的,如果突然某一只皮卡丘要播放与其他皮卡丘不同的动画,那就不行了。

另一种bake方案可以是这样:
对皮卡丘的每个动画进行遍历采样,把采样到的mesh存到数组中,因为这里要bake很多网格,比较耗时,建议在加载场景时时就完成采样过程;后面要播放某个动画时直接从这个mesh数组中获取mesh来显示,此时直接使用meshfiltermeshrenderer的方式来显示网格就好了。
贴个bakemesh的示例脚本:

using unityengine;
using system.collections.generic;
/// <summary>
/// bake mesh 示例
/// </summary>
public class bakemeshtest : monobehaviour
{
    [serializefield]
    animation m_animation;
    [serializefield]
    skinnedmeshrenderer m_skinnedmeshrenderer; 
    [serializefield]
    string m_cliptobake = "idle";
    list<mesh> m_bakedmeshlist = new list<mesh>();
    /// <summary>
    /// 采样帧数
    /// </summary>
    [serializefield]
    int m_numframestobake = 30;
    void start()
    {
        // 获取要bake的动画片段
        animationstate clipstate = m_animation[m_cliptobake];
        if (clipstate == null)
        {
            debug.logerror(string.format("unable to get clip '{0}'", m_cliptobake), this);
            return;
        }
        // 开始播放动画
        m_animation.play(m_cliptobake, playmode.stopall);
        // 设置动画初始时间戳
        clipstate.time = 0.0f;
        // 采样帧间隔
        float deltatime = clipstate.length / (float)(m_numframestobake - 1);
        for (int frameindex = 0; frameindex < m_numframestobake; ++frameindex)
        {
            string framename = string.format("bakedframe{0}", frameindex);
            // 创建mesh
            mesh framemesh = new mesh();
            framemesh.name = framename;
            // 动画采样
            m_animation.sample();
            // 执行bakemesh
            m_skinnedmeshrenderer.bakemesh(framemesh);
            m_bakedmeshlist.add(framemesh);
            // 设置动画时间戳
            clipstate.time += deltatime;
        }
        // 停止播放动画
        m_animation.stop();
    }

}

需要提醒的是,这个方案是利用空间换时间,如果模型顶点数据特别多或动画时长特别长的时候,这时就会遇到内存瓶颈。

五、纯代码动态创建网格

一般情况下,网格是事先制作好的资源,但也有一些特殊的需求需要在代码中动态创建网格。
比如我之前写的一篇牙齿碎了的文章:

游戏开发unity2d图片任意形状破碎裂片效果展示

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

现在我来教大家如何使用代码从零创建网格并将网格渲染出来,下文我以创建一个正方形网格为例进行讲解。

1、创建mesh对象

第一步最简单,就是直接new一个mesh

var mesh = new mesh();

2、顶点坐标

首先分析一下,一个四边形有四个顶点,假设正方形边长为1,四个点的坐标如下,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

写成代码就是这样:

// 构建顶点坐标
var vertices = new list<vector3>();
vertices.add(new vector3(-0.5f, -0.5f, 0));
vertices.add(new vector3(-0.5f, 0.5f, 0));
vertices.add(new vector3(0.5f, 0.5f, 0));
vertices.add(new vector3(0.5f, -0.5f, 0));
// 将顶点坐标设置给mesh
mesh.setvertices(vertices);

3、uv坐标

uv坐标就是纹理贴图坐标,它将纹理上每一个点精确对应到模型物体的表面上,注意uv的取值范围是0~1
uv坐标系原点在左下角,u轴是水平轴,v轴是竖直轴,如下:

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

对应到我们的上面那个正方向网格的话,四个点的uv坐标如下:

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

写成代码就是这样:

// 构建uv坐标
var uvs = new list<vector2>();
uvs.add(new vector2(0, 0));
uvs.add(new vector2(0, 1));
uvs.add(new vector2(1, 1));
uvs.add(new vector2(1, 0));
// 将uv坐标设置给mesh
mesh.setuvs(0, uvs);

4、三角形序列

网格需要切分成三角形,我们可以这样切分,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

当然也可以这样切分,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

两种切分方法对应不同的三角形序列,假设 法线方向 是垂直于屏幕从内指向屏幕外的话,第一种切分方式的三角形序列如下:

注:法线的方向就决定了表面正面,如果你的材质是单面渲染的话,那么只有从正面看才能看到网格被渲染。

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

即三角形序列为:{ 0, 1, 2, 0, 2, 3 },注意序号是从0开始的。
为什么是这样的顺序呢?我教大家一个技巧,伸出你的左手,竖起大拇指,像这样子,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

大拇指指向法线的方向,那么此时你的其余四根手指头环绕的方向就是三角形的序号的顺序,三个序号为一组按顺序塞入数组中即可,即得到的数组就是:{ 0, 1, 2, 0, 2,3}当然,以下数组最终的效果都是等价的,只要顺序一致即可:

{ 0, 1, 2, 0, 2, 3 },
{ 1, 2, 0, 0, 2, 3 },
{ 0, 2, 3, 1, 2, 0 },

我们现在写成代码,

// 重新计算法线,注意,法线是根据共享的顶点计算出来的。
mesh.recalculatenormals();

// 重新计算包围体,在修改顶点后需要这个函数以确保包围体是正确的
mesh.recalculatebounds();

// 从法线和纹理坐标重新计算网格的切线(如果网格使用引用法线贴图的着色器进行渲染,则切线需要更新)
// 因为我们这里不使用法线贴图,所以就不调用它了
// mesh.recalculatetangents();

5、重新计算法线和包围体

当我们设置或修改了顶点数据后,需要调用meshrecalculate方法来重新计算一些必要的信息,比如重新计算法线、包围体,代码如下

// 重新计算法线,注意,法线是根据共享的顶点计算出来的。
mesh.recalculatenormals();

// 重新计算包围体,在修改顶点后需要这个函数以确保包围体是正确的
mesh.recalculatebounds();

// 从法线和纹理坐标重新计算网格的切线(如果网格使用引用法线贴图的着色器进行渲染,则切线需要更新)
// 因为我们这里不使用法线贴图,所以就不调用它了
// mesh.recalculatetangents();

6、完整版代码

以上代码封装成genquadmesh.cs脚本,完整代码如下:

// 使用代码生成四边形网格
using system.collections.generic;
using unityengine;
[requirecomponent(typeof(meshfilter))]
[requirecomponent(typeof(meshrenderer))]
public class genquadmesh : monobehaviour
{
    public meshfilter mf;
    private void start()
    {
        mf.mesh = build();
    }
   public static mesh build()
    {
        var mesh = new mesh();
        // 构建顶点坐标
        var vertices = new list<vector3>();
        vertices.add(new vector3(-0.5f, -0.5f, 0));
        vertices.add(new vector3(-0.5f, 0.5f, 0));
        vertices.add(new vector3(0.5f, 0.5f, 0));
        vertices.add(new vector3(0.5f, -0.5f, 0));
        // 将顶点坐标设置给mesh
        mesh.setvertices(vertices);
        // 构建uv坐标
        var uvs = new list<vector2>();
        uvs.add(new vector2(0, 0));
        uvs.add(new vector2(0, 1));
        uvs.add(new vector2(1, 1));
        uvs.add(new vector2(1, 0));
        // 将uv坐标设置给mesh
        mesh.setuvs(0, uvs);
        // 设置三角形序列
        var triangles = new int[] { 0, 1, 2, 0, 2, 3 };
        mesh.settriangles(triangles, 0);
        mesh.recalculatenormals();
        mesh.recalculatebounds();
        return mesh;
    }
}

7、测试

创建一个空物体,挂上meshfiltermeshrenderer组件。

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

再挂上我们上面写的genquadmesh脚本,赋值mf变量为meshfilter对象,如下

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

运行unity,看到一个紫色快,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

scene视图的模式设置为wireframe,如下

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

现在我们可以看到我们动态创建的网格啦,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

上面之所以显示紫色块,是因为我们没有给meshfilter设置材质球,顺手做一个炮姐的材质球吧,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

meshrenderer设置材质球对象,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

重新运行unity,效果如下,

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

8、项目源码

要用代码动态创建一个mesh,就是new一个mesh,给它塞入顶点坐标、uv坐标和三角形序列即可。再复杂的网格也可以通过这些步骤创建出来~
下面这些就是使用纯代码创建出来的几何体网格,感兴趣的同学可以下载项目源码下来学习。
项目源码:https://codechina.csdn.net/linxinfa/unity-mesh-builder

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

六、网格相关的开源项目

我再推荐一些网格相关的开源项目给大家~

1、2d网格涂鸦

项目地址:https://github.com/mattatz/unity-triangulation2d

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

2、3d网格涂鸦

项目地址:https://github.com/mattatz/unity-teddy

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

3、网格体素化

项目地址:https://github.com/scrawk/mesh-voxelization

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮) 

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

4、网格平滑算法

项目地址:https://github.com/mattatz/unity-mesh-smoothing

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

5、网格切割

项目地址:https://github.com/hugoscurti/mesh-cutter

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮) 

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

6、网格合并

项目地址:https://github.com/sanukin39/unimeshcombiner

游戏开发进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

七、未完的探险

好了,这次探险之旅就暂时到这里吧,还有很多内容需要探索,先保持体力,我们下次再见,更多关于unity网格(mesh\动态合批\骨骼动画\蒙皮)的资料请关注其它相关文章!