从零开始的unity学习笔记

SuperJvRuo

2019-01-05 19:52:34

Personal

## Day0 Unity的安装 在unity[官方网站](https://unity3d.com/cn)上注册账号后,点上面的“产品”,选择“Personal个人版”,点“试用个人版”,接受条款。这里建议安装unity hub(就是unity的安装器)。安装unity hub后,在installs——Offical Releases里下载最新的稳定版本。 如果你在此前没装visual studio,此时会顺便给你安装上。 如果你装过,就在visual studio installer里添加“使用Unity的游戏开发”。 ![](https://cdn.luogu.com.cn/upload/pic/48397.png ) 等待安装的时候可以看一看官网。官网里的教学视频链接大多数都是youtube,需要科学上网。右上角的Asset Store就是素材商店。合作伙伴里的Vuforia是一个可以配合unity使用的AR工具,用起来很有意思。 unity要求我们使用C#,我们可以在[这里](http://www.runoob.com/csharp/csharp-tutorial.html)学习一个。会C++的应该很容易就能上手,毕竟#就是两个+叠在一起(大雾)。先打开visual studio写个A+B: ``` using System; namespace P1001 { class Program { static void Main(string[] args) { string[] vals = Console.ReadLine().Split(); Console.WriteLine(Convert.ToInt32(vals[0])+Convert.ToInt32(vals[1])); } } } ``` NOIP2018 D1T1: ``` using System; namespace P5019 { class Program { static void Main(string[] args) { int n = Convert.ToInt32(Console.ReadLine()); string[] strs = Console.ReadLine().Split(' '); int[] vals = new int[n]; int ans = 0, last = 0, dif = 0; for (int i = 0; i < n; ++i) { vals[i]= Convert.ToInt32(strs[i]); dif = vals[i] - last; last = vals[i]; ans += dif < 0 ? 0 : dif; } Console.WriteLine("{0}",ans); } } } ``` 可以先把Learn里面四个基本的交互式教程(Interactive Tutorials)过一遍,熟悉一下基本操作。 ![](https://cdn.luogu.com.cn/upload/pic/48398.png) ## Day1 滚个球-1 选择教学项目(Tutorial Projects)里的第三个:“滚个球(Roll-a-ball)”。一开始后面是download,点完后就是一个下载进度条,走完进度就变成start了。 ### 1、调整unity布局 ![](https://cdn.luogu.com.cn/upload/pic/48400.png ) 把右上角的布局(Layouts)调成2 by 3(即,左边的2:上边是场景Scene,下边是游戏Game,右边的3依次是层级Hierarchy,项目Project,审查Inspector)。 ![](https://cdn.luogu.com.cn/upload/pic/48401.png ) 不建议把语言改成中文,感觉翻译很烂,不仅翻译不完全,还有机翻的感觉。如果一定要改,先在unity hub里单机当前版本后边的三个点,选“Add Component”,拉到最下面的“语言包(language packs)”,下载简体中文。安装后,打开unity,在Edit->Preferences->Languages->Edit Language里选择Chinese。 ### 2、保存场景 File->Save即可保存场景,快捷键ctrl+S。此时会询问保存的目录。在Assets目录下,新建一个目录Scene,在这个目录下保存场景。 ![](https://cdn.luogu.com.cn/upload/pic/48402.png ) 比如把场景保存为Sample Scene.unity,存完后我们可以发现,Hierarchy下面的场景名由“Untitled”变成了“Sample Scene”。 ### 3、添加对象 先添加一个平面,小球要在平面上滚。 点GameObject->3D Object->Plane。 ![](https://cdn.luogu.com.cn/upload/pic/48447.png ) 或者Hierarchy->Create->3D Object->Plane ![](https://cdn.luogu.com.cn/upload/pic/48449.png ) 我们就有了一个平面。 ![](https://cdn.luogu.com.cn/upload/pic/48448.png ) 要更改对象的名称,可以在Hierarchy里点选这个对象,然后F2重命名,或者右键->Rename。 随时记得保存。 ### 4、调整对象的位置 在Hierarchy里点选对象后,Scene里的对象的边缘就会突出显示。 ![](https://cdn.luogu.com.cn/upload/pic/48451.png ) 在左上角的工具(Tool)里选择Move Tool。Move Tool可以让我们方便地移动对象。这一排的六个东西,快捷键由左到右依次为“QWERTY”。 ![](https://cdn.luogu.com.cn/upload/pic/48452.png ) 然后我们就可以看到三个方向上的坐标轴。 ![](https://cdn.luogu.com.cn/upload/pic/48453.png ) 鼠标拖动坐标轴,就可以拉动这个平面。 后面四个工具用法相同,可以试着玩一玩。需要注意的是Scale Tool,由于我们创造的Plane是一个平面图形,因此其在Y轴上的大小是没有意义的。我们向上拉伸Y轴,发现它的大小不变;向下拉伸Y轴,发现这个Plane消失了。 ![](https://cdn.luogu.com.cn/upload/pic/48456.png ) 在Scene的右上角找到这个小玩意,点击Y轴对面的这个圆锥,我们就能从下面仰视场景。 ![](https://cdn.luogu.com.cn/upload/pic/48458.png ) 然后我们就能看见这个Plane了。当Plane的Y轴方向尺寸为正时,它对上面可见,尺寸为负时,对下面可见。从上图可以看见小玩意的下面还有一个“Iso”,并不知道它是什么单词的缩写。它的意思应该是正交。点一下就会变成“Persp”,是“Perspective(透视投影)”的缩写。点这个就可以实现Scene视图正交与透视的切换。 ![](https://cdn.luogu.com.cn/upload/pic/48459.png ) 至于第一个工具,就是拖动镜头的工具。鼠标拖动或键盘上下左右可以实现视角的上下左右移动,鼠标滚轮实现缩放。 此时,我们已经把这个平面进行了一定的扭曲,现在我们来快速把它复原。在Hierarchy里点选对象后,Inspector里会展示它的组成。 ![](https://cdn.luogu.com.cn/upload/pic/48450.png ) 在Transform中,右上角有一个小齿轮。点击齿轮,在出现的下拉菜单中点Reset,Position和Rotation都会变为0,Scale会变为默认值。 ![](https://cdn.luogu.com.cn/upload/pic/48454.png ) 就是这个效果。 ![](https://cdn.luogu.com.cn/upload/pic/48455.png ) 想要修改对象的位置,当然也可以手动修改Transform里的数值。 再用相同的办法创建一个球(Sphere),将位置Reset到原点。按F使Scene里的视角拉到球上。我们发现球与平面重叠了。 ![](https://cdn.luogu.com.cn/upload/pic/48550.png ) Unity内置Sphere类的直径为1,因此我们将其Y坐标增加到0.5即可。 ![](https://cdn.luogu.com.cn/upload/pic/48551.png) 修改后的效果: ![](https://cdn.luogu.com.cn/upload/pic/48552.png ) ### 5、调整对象的材质 在Assets目录里新建一个Materials目录,用于存放材质。打开Materials,在里面新建一个Material,重命名为Background,作为平面的颜色。选择Background,在Inspector里有一项Albedo(百度了一下,这个词的意思是反照率),点后面的色块,就可以选择材质的颜色。 ![](https://cdn.luogu.com.cn/upload/pic/48554.png ) 我们选择三中红:8F000B。 ![](https://cdn.luogu.com.cn/upload/pic/48553.png) 要使用这个Material,只要把它从Project里边拖到Hierarchy里的Plane上就行了。效果是这样的: ![](https://cdn.luogu.com.cn/upload/pic/48555.png) ### 6、添加刚体组件 这里的球要会动,能发生碰撞,不会乱飞,我们需要给它添加一个刚体(Rigidbody)组件(Component)。选择Sphere,在Inspector的底部有一个“Add Component”,点击“Add Component”,在搜索框里输入“rigidbody”,选择不带2D的。 ![](https://cdn.luogu.com.cn/upload/pic/48556.png) By the way,每个对象里的每个组件都可以点右上角小齿轮里的“Move Up”“Move Down”来调整其在Inspector里的位置。 ![](https://cdn.luogu.com.cn/upload/pic/48558.png) ## Day2 滚个球-2 ### 1、写一个控制移动的脚本 在Assets里新建一个Scripts目录,在该目录里新建一个名为“PlayerController”的C#脚本。把Project里面的这个脚本拖到Hierarachy里的Sphere上。 双击“PlayerController”,进入Visual Studio编写脚本。首先删掉```PlayerController```类里的两个默认方法。 更新物体的状态(包括位置状态)有好几个不同的方法,暂时只讨论```Update()```和```FixedUpdate()```。 ```Update```是每一帧执行一次,```FixedUpdate```是每隔一段时间执行一次。在物理模拟时,我们应该选择```FixedUpdate```。比如我们同时在卡吧标配和图吧标配上运行“滚个球”,我们钦定每次Update移动1,那么```Update```就会导致卡吧标配的球滚得更远(每帧移动距离相同,帧数更多),```FixedUpdate```距离相同(每次更新移动距离相同,每秒更新次数相同)。所以我们在```PlayerController```类里添加一个```FixedUpdate```方法。 获取输入需要Input类。[Input类中的GetAxis方法](https://docs.unity3d.com/ScriptReference/Input.GetAxis.html)可以获取输入的移动。像这样: ``` float moveHorizontal = Input.GetAxis("Horizontal"); float moveVertical = Input.GetAxis("Vertical"); ``` 球已经被设置为刚体,对刚体施以力的作用,需要使用```Rigidbody.AddForce()```。查询文档,它的参数为```public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force) ```,或```public void AddForce(float x, float y, float z, ForceMode mode = ForceMode.Force) ```。力的模式采用默认值即可,力的大小是一个空间向量。 ``` Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical); ``` 有了力,还要有物体。这段代码已经完成得差不多了,可以参照下面的代码完成剩余细节。 ``` using UnityEngine; using System.Collections; public class PlayerController : MonoBehaviour { public float speed;//可以在Inspector中显示、变更,便于调整力的大小 private Rigidbody rb; void Start ()//在游戏的第一帧时调用 { rb = GetComponent<Rigidbody>();//这个脚本和刚体是sphere的两个组件,因此需要获取刚体的引用。 } void FixedUpdate ()//每隔固定时间调用一次 { float moveHorizontal = Input.GetAxis ("Horizontal"); float moveVertical = Input.GetAxis ("Vertical"); Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical); rb.AddForce (movement * speed); } } ``` 然后在visual studio里面点“附加到Unity”,没有CE,可以试一试了。此时在Unity里选择Sphere对象,在Inspector里的Player Controller上出现了一个可供修改的数值:speed,这就是我们代码里的那个```public float speed```。 ![](https://cdn.luogu.com.cn/upload/pic/48580.png) 先调成10试一试。点击unity界面里的Play,按WSAD控制上下左右,就可以让球动起来。 ### 2、写一个控制摄像机的脚本 球是能动了,但是摄像机还不能动。你也许想到了这样的办法:让Main Camera成为Sphere的子对象,摄像机就能和Sphere一起动了。我们可以尝试一下:在Hierarchy里把Main Camera拖动到Sphere的名字上,像这样: ![](https://cdn.luogu.com.cn/upload/pic/48582.png) 点Play试一下,我们发现摄像机会跟着球一起转。。。 ![](https://i.loli.net/2018/08/11/5b6ea9ab74ecb.jpg) 其实原因也很简单,子对象当然会跟着父对象一起转。那我们只能把Main Camera拉出来,写个脚本了。(当然,如果游戏里的对象不会转,我们可以直接把摄像机拖到对象身上) 废话不多说,上代码: ![](https://i.loli.net/2018/08/11/5b6eca17075cd.jpg) ``` using System.Collections; using System.Collections.Generic; using UnityEngine; public class CameraController : MonoBehaviour { public GameObject player;//这个摄像机附在player上 private Vector3 offset; void Start() { offset = transform.position - player.transform.position;//摄像机位置相对于球的偏移值 } void LateUpdate()//LateUpdate是指完成其它的Update后再更新摄像机的位置,每帧执行一次 { transform.position = player.transform.position + offset;//相机的新位置就是球的新位置加上偏移值 } } ``` 点“附加到Unity”。在Main Camera的Inspector里找到加进来的脚本。点Player后面的小圈,选择Sphere,这样我们就把摄像机附在了Sphere上。 ![](https://cdn.luogu.com.cn/upload/pic/48583.png) 测试一下,发现摄像机可以跟着球移动了,但是球会滚出去,然后就从Plane上掉下去了。。。 ![](https://i.loli.net/2018/08/11/5b6eca17075cd.jpg) ## Day3 滚个球-3 ### 1、完善场地 感觉Plane好像有点小,我们先调整一下Plane的大小。把在x与z方向上的大小调成2。 为了把场景围起来,需要在Plane四周加上一圈墙。为了便于管理,我们在Hierarchy中新建一个空对象“Walls”,让其成为四面墙的父对象。Reset一下Walls的位置。 ![](https://cdn.luogu.com.cn/upload/pic/48612.png) 创造一个Cube作为墙。使其成为Walls的子对象,重命名为Wall1,调整一下大小和位置。 ![](https://cdn.luogu.com.cn/upload/pic/48614.png) 复制一个Wall1,更名为Wall2,Position改为$(-10,0.5,0)$ 再复制出Wall3和Wall4,调整位置与大小。效果是这样的: ![](https://cdn.luogu.com.cn/upload/pic/48615.png) 进入Play Mode试一下,发现球可以只在里面动了。 ### 2、设置收集物 我们还要添加一些收集物,小球碰到收集物就可以得分。 先创建一个Cube,Reset一下,把Cube的大小调整为$(0.5,0.5,0.5)$,旋转调为$(45,45,45)$。 Sphere对象和Cube是重合的,看的时候很不方便。我们选择Sphere。把Sphere前的对号取消掉,这样Sphere就不会显示。为了方便管理,将收集物重命名为Pick Up。 ![](https://cdn.luogu.com.cn/upload/pic/48617.png) 我们想让收集物自己转起来,就又需要写脚本了。由于没有施力受力的物理模拟,没有必要进行```FixedUpdate()```,只要Update就行。 ``` using System.Collections; using System.Collections.Generic; using UnityEngine; public class Rotator : MonoBehaviour { void Update() { transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);//钦定一个旋转速度 } } ``` 进入Play Mode试一下感觉海星。现在我们要把收集物设为一个预设(Prefab),这样就可以很方便地使用了。 在Project中的Assets目录下新建一个Prefabs目录。把Hierarchy里的Pick Up拖进Project里的Prefabs目录里。 就像刚才的四面墙一样,我们新建一个空对象作为所有收集物的父对象。重命名为Pick Ups,Reset它的位置。 点击坐标轴的Y轴正半轴,让视线向正下方俯视。 ![](https://cdn.luogu.com.cn/upload/pic/48647.png) 像这样: ![](https://cdn.luogu.com.cn/upload/pic/48648.png) 但是,当我们调整Pick Up的位置时,我们发现它的三个移动方向都是旋转之后的。为了调正旋转方向,点击Scene上面的“Local”,使其变为Global。 ![](https://cdn.luogu.com.cn/upload/pic/48649.png) 然后就变成了: ![](https://cdn.luogu.com.cn/upload/pic/48650.png ) 我们就可以在平面上移动收集物了。要复制对象,Ctrl+C、Ctrl+V固然可以,我们还可以使用Ctrl+D。 放置成这样: ![](https://cdn.luogu.com.cn/upload/pic/48651.png) 现在我想让收集物换一种颜色。我们在Materials里对之前的Background材质Ctrl+D一下,对新材质重命名为Pick Up。将Pick Up的颜色调为$(0,32,64)$。把Pick Up拖到Hierarchy里的Pick Up上。此时只有一个收集物是蓝的。我们再点一下Inspector里的Overrides,在下拉的菜单中选择Apply All。 ![](https://cdn.luogu.com.cn/upload/pic/48652.png) 就全变蓝了: ![](https://cdn.luogu.com.cn/upload/pic/48653.png) 把之前取消掉的Sphere再打上勾,进入Play Mode试一试。 ![](https://cdn.luogu.com.cn/upload/pic/48655.png) ## Day4 滚个球-4 ### 1、小球与收集物的碰撞 下一样需要考虑的是球与收集物的碰撞。我们打开PlayerController脚本进行修改。 为了了解与碰撞(Collider)相关的信息,选中Sphere,在Inspector里的Sphere Collider上点这个: ![](https://cdn.luogu.com.cn/upload/pic/48657.png) 点“SWITCH TO SCRIPTING”切换到脚本。 ![](https://cdn.luogu.com.cn/upload/pic/48658.png) 这里我们需要的是一个[“OnTriggerEnter”](https://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html)。它会在其他物体碰撞触发器时调用。 我们试着在PlayerController类里加入一个OnTriggerEnter方法。 ``` private void OnTriggerEnter(Collider other) { if(other.gameObject.CompareTag("Pick Up"))//将这个物体的Tag与传入的string比较 { other.gameObject.SetActive(false);//相当于取消Inspector里对象名称前的对号 } } ``` 看起来似乎很正确,但是进入Play Mode发现这样布星。为什么呢? 我们添加的方法名为OnTriggerEnter,但是我们看一下收集物的Inspector,我们发现:我们没勾上“作为触发器(Is Trigger)”。 ![](https://cdn.luogu.com.cn/upload/pic/48667.png) 把Prefabs里收集物的“Is Trigger”勾上就行了。经测试,现在小球可以收集方块了。 还有一件有关优化的小事:给Prefabs里的收集物加上Rigidbody,这样收集物就会被识别为动态碰撞器。unity中的碰撞器分为静态和动态。更新静态碰撞器的位置时,unity认为它是静态的,更改会比较少,因此会存入缓存以减少计算。但收集物的位置每时每刻都在转,因此会引起大量的缓存修改,影响性能。 再测试一下,我们发现方块透过Plane掉了下去。。。这是因为方块成为了触发器,受重力作用向下掉,与Plane碰撞。我们把Rigidbody里的Use Gravity禁用掉就可以解决问题。 ![](https://cdn.luogu.com.cn/upload/pic/48669.png) 还有一种解决方法是启用“Is Kinematic”,让物体成为“运动学物体”,即不计算其受力,但仍计算其运动。 ### 2、做一个简单的UI 每收集一个收集物,我们都希望显示得分。也就是说我们要做一个简单的UI。 我们先用脚本记录以下玩家的得分:还是修改PlayerController。修改后的代码是这样的。 ``` using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { public float speed; private Rigidbody rb; private int count; void Start() { count = 0; rb = GetComponent<Rigidbody>(); } void FixedUpdate() { float moveHorizontal = Input.GetAxis("Horizontal"); float moveVertical = Input.GetAxis("Vertical"); Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical); rb.AddForce(movement * speed); } void OnTriggerEnter(Collider other) { if(other.gameObject.CompareTag("Pick Up")) { other.gameObject.SetActive(false); ++count; } } } ``` 嗯,没有CE。现在我们添加UI。在Hierarchy中添加一个UI-Text,并Reset位置。我们可以在Game中看到“New Text”的字样。 ![](https://cdn.luogu.com.cn/upload/pic/48672.png) 在Inspector里把它的内容改成“Count Text”。这几个字放在屏幕中间似乎不大合适,应该放在左上角。我们调整一下文字的“Rect Transform”。 单击“Rect Transfrom”下面的方块,按住Shift和Alt点击九宫格左上角的那个,即可把文字挪到屏幕的左上角。 ![](https://cdn.luogu.com.cn/upload/pic/48674.png) ![](https://cdn.luogu.com.cn/upload/pic/48675.png) 颜色有点暗,位置有点偏。为了不侮辱读者的智商就不细说调整方法了。直接看效果: ![](https://cdn.luogu.com.cn/upload/pic/48676.png) 每次碰到收集物,我们都应该更新得分。 ``` using System.Collections; using System.Collections.Generic; using UnityEngine.UI;//使用UI,需要使用这个命名空间 using UnityEngine; public class PlayerController : MonoBehaviour { public float speed; public Text countText;//即左上角的文本 private Rigidbody rb; private int count; void Start() { count = 0; rb = GetComponent<Rigidbody>(); SetCountText(); } void FixedUpdate() { float moveHorizontal = Input.GetAxis("Horizontal"); float moveVertical = Input.GetAxis("Vertical"); Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical); rb.AddForce(movement * speed); } void OnTriggerEnter(Collider other) { if(other.gameObject.CompareTag("Pick Up")) { other.gameObject.SetActive(false); ++count; SetCountText(); } } void SetCountText() { countText.text = "Count: " + count.ToString(); } } ``` 保存,选中Sphere,脚本里的Count Text还是空着的。 ![](https://cdn.luogu.com.cn/upload/pic/48677.png) 把Hierarchy里的Count Text拖到上面,就变成了: ![](https://cdn.luogu.com.cn/upload/pic/48678.png) 测试一下,效果不错: ![](https://cdn.luogu.com.cn/upload/pic/48679.png) 我们还希望在收集所有方块后可以有一个提示信息。再新建一个Text,重命名为Win Text,位置居中。再修改一下脚本: ``` using System.Collections; using System.Collections.Generic; using UnityEngine.UI; using UnityEngine; public class PlayerController : MonoBehaviour { public float speed; public Text countText; public Text winText; private Rigidbody rb; private int count; void Start() { count = 0; rb = GetComponent<Rigidbody>(); SetCountText(); winText.text = "";//初始为空串 } void FixedUpdate() { float moveHorizontal = Input.GetAxis("Horizontal"); float moveVertical = Input.GetAxis("Vertical"); Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical); rb.AddForce(movement * speed); } void OnTriggerEnter(Collider other) { if(other.gameObject.CompareTag("Pick Up")) { other.gameObject.SetActive(false); ++count; SetCountText(); } } void SetCountText() { countText.text = "Count: " + count.ToString(); if(count>=8) { winText.text = "You win!";//全部收集,将winText改为You win! } } } ``` 效果: ![](https://cdn.luogu.com.cn/upload/pic/48680.png) ### 3、添加BGM 在Project的Assets目录下创建一个Audios目录,把已经下载好的音乐拖进去。 在Hierarchy里创建一个Audio Source,把音乐拖进Audio Clip。启用Loop。 进入Play Mode就可以听到BGM了。 ### 4、编译游戏 在File里找到Build Settings。 ![](https://cdn.luogu.com.cn/upload/pic/48681.png) 可以看到unity支持的平台很多。似乎在印象里,unity都是做手游、web小游戏的,其实现在的unity已经越来越强大了。 ![](https://cdn.luogu.com.cn/upload/pic/48682.png) 我们选择默认的PC,Mac&Linux Standalone,把Hierarchy里的场景拖到上面的“Scene In Build”里。 ![](https://cdn.luogu.com.cn/upload/pic/48683.png) 点Build,编译到你想存的地方。编译完成后试玩一下。滚个球教程就到此结束辣! ![](https://cdn.luogu.com.cn/upload/pic/48685.png) ## Day5 MMD4Mecanim-1 ### 1、环境准备 首先当然要有MMD。 在[MMD4Mecanim下载地址](http://stereoarts.jp/)下载MMD4Mecanim的zip。 还要安装Blender或Autodesk Maya。在这个项目里,Blender要方便一些,但我对Maya比较熟,而且Maya的效果较好,所以我使用Maya。 随便找一套MMD模型(.pmx)、一套MMD动作(.vmd)、一套相机文件(.vmd)和一段对应伴奏。 Maya用户还要下载MMDBridge或MMD4Maya。 ### 2、导入插件与素材 新建一个3D项目。 解压MMD4Mecanim。这个插件名字中的Mecanim就是Unity的动画系统(Animation System)。把比较大的那个(如果有两个).unitypackage拖到Assets上,Unity会import这个package。 ![](https://cdn.luogu.com.cn/upload/pic/49152.png) 该点import的时候就点。 ![](https://cdn.luogu.com.cn/upload/pic/49153.png) 提示里面有弃用的API,你就Go ahead。 ![](https://cdn.luogu.com.cn/upload/pic/49154.png) 把存模型的目录拖到Assets目录下,发现每个.pmx的下面自动生成了一个asset。选中对应的asset,Inspector里会弹出一个利用规约,我们全都同意就行。 这个asset有三个参数(如果不点高级模式),第一个和第三个已经自动生成。我们需要填上第二个:VMD。 ![](https://cdn.luogu.com.cn/upload/pic/49156.png) 在Assets目录下新建一个存动作的Animations目录。把.vmd动作文件拉进这个目录。把这个文件拉进第二个参数栏即可。 ![](https://cdn.luogu.com.cn/upload/pic/49158.png) 单击Process后会弹出一个pmx2fbx,把.pmx文件转换为.fbx,然后会自动导入Unity。对于比较精细的模型和性能较弱的电脑来说,这一步可能会耗费很长时间。 我们这个时候可以准备一下相机的导入。首先借助MMDBridge或MMD4Maya将素材导入Maya。(我们只是要借助Maya获得相机的Alembic文件,因此不需要贴图)。 这个时候,模型大概导入完了。现在导入音乐。在Assets里新建Audios目录,把音乐拖进来。 ### 3、让模型动起来 我们把生成的.fbx文件拖到Hierarchy里: ![](https://cdn.luogu.com.cn/upload/pic/49161.png) 哇,成功了!Play一下试试! (Miku纹丝不动) 这是因为.fbx只是模型,没有动作。我们点击Project里那个.fbx左边的小三角,发现里面有一个名字很长,结尾是```_vmd```的文件。把它拖到Hierarchy里的模型上,再Play一次: 动起来了! ![](https://cdn.luogu.com.cn/upload/pic/49162.png) 怎么配音乐来着?还记得滚个球里面的方法吗?给模型加一个Audio Source。 调整模型大小和相机位置,得到合适的效果,进入Play Mode看一看。 额,头发有点不大对啊。。。 ![](https://cdn.luogu.com.cn/upload/pic/49177.png) 这就需要调整物理了。在Hierarchy中选中模型,找到MMD4Mecanim Model这个Component,进入Physics选项卡。调大Gravity Scale,发现效果好多了。 ## Day6 Octane渲染器 在尝试的过程中,发现有两个dll一直有问题,后来才发现是因为Octane渲染器需要CUDA,这两个dll应该是依赖某个与CUDA有关的dll。但本人的显卡是RX580,因此本段暂时咕咕咕。比较经济的硬件升级方案是买一块P106矿卡作CUDA计算卡,以原显卡作为主卡,然而我并不想继续折腾了。 ## Day7 Vuforia ### 1、环境准备 ## Day8 MMD4Mecanim-2