嗨,大家好,我是新发。
我这两天在做一个RPG
打群架的个人作品,涉及到一些渲染和人物动画控制的问题,顺手写篇教程,这里角色模型我用原神的模型来演示。
效果如下
原神模型使用守则:
◆允许完善物理,修正模型权重、表情等bug
允许改色,适度更改衣装,添加spa、toon等
◆请勿二次配布,以及拆取部件以用于改造其他模型
请勿用于18禁作品,极端宗教宣传,血腥恐怖猎奇作品,人身攻击等
请勿用于商业用途
◆他人使用本模型所造成的一切不良后果,不由模型改造者与miHoYo承担,请向使用者追究全部责任
原神的模型可以在官网直接下载到。
官网:https://ys.biligame.com/gczj/
官网:http://ys.biligame.com/pjdkx/
官网:https://ys.biligame.com/beyel
官网:https://ys.biligame.com/ysl
官网:https://www.bilibili.com/blackboard/activity-raop07Ymhm.html
官网:https://www.bilibili.com/blackboard/activity-kiOl0D1nF8.html
官网:https://www.bilibili.com/blackboard/activity-btLCSzTTsK.html
如果你不想一个个下载,可以从我的网盘下载,我已经全部打包好了,
网盘地址:https://pan.baidu.com/s/1gUCyDuu9D2Aoug6weK2WxA
提取码:bbr5
我们需要把它转为fbx
格式才能导入Unity
中使用。pmx
转fbx
可以通过Blender
来转,刚好我之前自学了Blender
,也写过几篇Blender
配合Unity
的文章,大家感兴趣的可以看看:
《【游戏开发创新】上班通勤时间太长,做一个任意门,告别地铁与塞车(Unity | 建模 | ShaderGraph | 摇杆 | 角色控制)》
《【游戏开发创新】自学Blender建模,自制孔明灯,在Unity中点亮整个星空,愿新年,胜旧年(Unity | 建模 | 粒子系统 | 预设)》
《【游戏开发创新】当我学了Blender 建模,自制3D电脑桌面,回收站爆发了,把我做的模型都吐了出来(Blender | Unity | FBX)》
回归正题,下面就来教大家如何使用Blender
将pmx
转为fbx
格式。
Blender
官网:https://www.blender.org/
中文手册:https://docs.blender.org/manual/zh-hans/2.79/about/introduction.html
由于Blender
官网的下载速度太慢,建议去Blender
中国社区下载,地址:https://www.blendercn.org/
根据你的电脑系统下载对应的版本,我是windows
系统,点击下载windows
平台的安装包,
下载完后直接傻瓜式安装即可~
Blender
是开源免费的,轻量又强大,易于上手,很适合个人独立开发者学习和使用,它具有丰富的插件生态,就像VSCode
一样,我们这里要将pmx
转为fbx
格式,就需要用到一个Cats
插件。
Cats
插件自身也是开源的,我们直接从GitHub
上下载。
地址:https://github.com/GiveMeAllYourCats/cats-blender-plugin
如下,点击Cats Blender Plugin
,下载下来的是一个zip
文件,
现在我们打开Blender
,然后点击菜单Edit / Preferences
,打开偏好设置窗口,
点击Add ons
,然后点击install
按钮,
然后选择我们刚刚下载的Cats
插件文件,点击Install Add-on
,
安装完毕后,记得勾选上它,(如果你没勾选,插件就是禁用状态的)
现在,我们就可以在编辑区的侧边栏那里看到CATS
插件了,(注:侧边栏显示和隐藏的快捷键是N
)
我们在CATS
插件中点击Import Model
按钮,
然后选择pmx
文件,点击Import Any Model
按钮,
此时导进来的模型的材质有问题,是这样子的,
我们打开侧边栏的Misc
,然后点击Shadeless
(即使用卡通材质),
此时我们就可以看到正常显示了,
看下细节
我们可以看到,模型的节点命名并不是按照Unity
骨骼映射的英文命名,
我们点击CATS
插件的Fix Model
按钮,即可自动进行修复,除此之外,它还会帮我们删除多余无用的骨骼,将使用同一张贴图的节点合并为一个Mesh
并重命名为Body
等,
修复后可以看到变成英文命名了,
点击CATS
插件的Export Model
按钮,即可导出fbx
文件,
建议导出fbx
文件放在pmx
文件同级目录中,
如下,
我们上面的fbx
文件和tex
文件夹(里面是贴图)一起拷贝到Unity
工程中,(如果你没有拷贝tex
文件夹,在Unity
中显示的就是白模)
此时我们把模型拖入场景中,看到的效果是这样的,
上面我们看到,模型的材质效果不是 卡通渲染风格,当你去定位模型的材质的时候,会发现材质是嵌在fbx
文件里的,
我们并不能对fbx
内的材质进行编辑,
没关系,我们把材质导出来。
选中fbx
文件,在Inspector
窗口中点击Materials
,设置Location
为Use External Materials (Legacy)
,然后点击Apply
按钮,
此时材质球就会从fbx
文件中导出来了,
接下来我们就可以修改材质球的shader
了,默认是Standard
,
卡通渲染不像 PBR
那样有标准流程和衡量准则,可以说卡通渲染是人们主观审美 + 现实环境抽象的结合,不同人对卡通渲染的理解理念不同,不过随着卡通渲染的不断发展,也形成了一套固定思路。
最粗暴的方式就是直接使用Unlit
材质,在贴图上表现出卡通效果。
我们把材质球的shader
全部改成Unlit/Texture
(也就是无光照模型,直接显示贴图纹理),
效果如下:
当然,这过于简单了,缺点很明显,没有光照效果。
我们对比看下原神游戏中的画面效果,是一种次时代卡通效果。我们可以看到,它是有光照效果的,太阳在右侧,人物面朝太阳方向时,光照面会有高光,背面会有阴影;当背朝太阳时则相反。
我们需要考虑光照,也就是基于光照模型的卡通渲染。
基于光照模型的卡通渲染,我在GitHub
上找到了一个项目,地址:https://github.com/Sorumi/UnityToonShader
如果你访问不了GitHub
,可以访问我的CODE CHINA
,我已将它Fork
过来了,
进入上面这个项目的Assets/Shaders
目录,可以看到一些shader
脚本,我使用的是这个ToonMultiStepShader.shader
,
shader
代码如下:
Shader "Toon/Basic/MultiSteps"
{
Properties
{
// 颜色
_Color ("Color", Color) = (1, 1, 1, 1)
_HColor ("Highlight Color", Color) = (0.8, 0.8, 0.8, 1.0)
_SColor ("Shadow Color", Color) = (0.2, 0.2, 0.2, 1.0)
// 贴图
_MainTex ("Main Texture", 2D) = "white" { }
// 渐变
_ToonSteps ("Steps of Toon", range(1, 9)) = 2
_RampThreshold ("Ramp Threshold", Range(0.1, 1)) = 0.5
_RampSmooth ("Ramp Smooth", Range(0, 1)) = 0.1
// 镜面
_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
_SpecSmooth ("Specular Smooth", Range(0, 1)) = 0.1
_Shininess ("Shininess", Range(0.001, 10)) = 0.2
// 边缘
_RimColor ("Rim Color", Color) = (0.8, 0.8, 0.8, 0.6)
_RimThreshold ("Rim Threshold", Range(0, 1)) = 0.5
_RimSmooth ("Rim Smooth", Range(0, 1)) = 0.1
}
SubShader
{
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Toon addshadow fullforwardshadows exclude_path:deferred exclude_path:prepass
#pragma target 3.0
// 基础色
fixed4 _Color;
// 高光颜色
fixed4 _HColor;
// 阴影色
fixed4 _SColor;
// 主贴图
sampler2D _MainTex;
// 渐变阈值
float _RampThreshold;
// 渐变平滑度
float _RampSmooth;
// 渐变阶数
float _ToonSteps;
// 镜面平滑度
float _SpecSmooth;
// 光滑度
fixed _Shininess;
// 边缘颜色
fixed4 _RimColor;
// 边缘阈值
fixed _RimThreshold;
// 边缘光滑度
float _RimSmooth;
struct Input
{
float2 uv_MainTex;
float3 viewDir;
};
// 线性阶跃
float linearstep(float min, float max, float t)
{
return saturate((t - min) / (max - min));
}
inline fixed4 LightingToon(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
{
half3 normalDir = normalize(s.Normal);
half3 halfDir = normalize(lightDir + viewDir);
float ndl = max(0, dot(normalDir, lightDir));
float ndh = max(0, dot(normalDir, halfDir));
float ndv = max(0, dot(normalDir, viewDir));
// 平滑阶跃
float diff = smoothstep(_RampThreshold - ndl, _RampThreshold + ndl, ndl);
float interval = 1 / _ToonSteps;
// float ramp = floor(diff * _ToonSteps) / _ToonSteps;
float level = round(diff * _ToonSteps) / _ToonSteps;
float ramp ;
if (_RampSmooth == 1)
{
ramp = interval * linearstep(level - _RampSmooth * interval * 0.5, level + _RampSmooth * interval * 0.5, diff) + level - interval;
}
else
{
ramp = interval * smoothstep(level - _RampSmooth * interval * 0.5, level + _RampSmooth * interval * 0.5, diff) + level - interval;
}
ramp = max(0, ramp);
ramp *= atten;
_SColor = lerp(_HColor, _SColor, _SColor.a);
float3 rampColor = lerp(_SColor.rgb, _HColor.rgb, ramp);
// 镜面
float spec = pow(ndh, s.Specular * 128.0) * s.Gloss;
spec *= atten;
spec = smoothstep(0.5 - _SpecSmooth * 0.5, 0.5 + _SpecSmooth * 0.5, spec);
// 边缘
float rim = (1.0 - ndv) * ndl;
rim *= atten;
rim = smoothstep(_RimThreshold - _RimSmooth * 0.5, _RimThreshold + _RimSmooth * 0.5, rim);
fixed3 lightColor = _LightColor0.rgb;
fixed4 color;
fixed3 diffuse = s.Albedo * lightColor * rampColor;
fixed3 specular = _SpecColor.rgb * lightColor * spec;
fixed3 rimColor = _RimColor.rgb * lightColor * _RimColor.a * rim;
color.rgb = diffuse + specular + rimColor;
color.a = s.Alpha;
return color;
}
// 表面着色器
void surf(Input IN, inout SurfaceOutput o)
{
fixed4 mainTex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = mainTex.rgb * _Color.rgb;
o.Alpha = mainTex.a * _Color.a;
o.Specular = _Shininess;
o.Gloss = mainTex.a;
}
ENDCG
}
FallBack "Diffuse"
}
把材质球的shader
改为Toon/Basic/MultiSteps
,如下
调整一下高光、阴影、渐变阈值、镜面、边缘等参数,
效果如下,我们在修改太阳光方向,观察不同角度的效果,
我们要给角色添加动画,加入你现在已有一些人形骨骼动画,想套用在原神的模型上,怎么弄呢?我来教你~
假设你手头上没有人形动画,这个时候,我就要推荐你一个高级网站了:Mixamo
,地址:https://www.mixamo.com/
Mixamo
是Adobe
旗下的一个产品,可以上传静态人形模型文件,在网站上绑定人形模板动画,并可以下载绑定动画后的模型文件。
我之前有写过一篇文章专门介绍这个网站:《在线免费角色动画网站:mixamo》
我们选择一个喜欢的动作,比如我选这个
格式选择FBX
,不要包含网格(选Without Skin)
,然后点击DOWNLOAD
,
这样我们就得到了一个含动画的fbx
文件,
选中动画fbx
文件,在Inspector
窗口中点击Rig
,把Animation Type
设置为Humanoid
,然后点击Apply
,
此时我们点击Configure
,可以看到人形动画Avatar
的绑定信息,
同样的,把我们原神的fbx
模型的Animation Type
也改为Humanoid
,
最后一步,把动画文件拖给模型父节点,此时会自动挂一个Animator
组件,我们设置一下Avatar
对象,如下
注意,如果要让动画循环播放,需要把动画的Loop Time
勾选上,如下
加个背景图,运行效果如下,
emmmm
,还是少一点效果,我们加上泛光屏幕后处理,如下
注:关于屏幕后处理,我在之前一些文章中与讲到,可以看我之前的文章:
《【游戏仿真实验】使用Unity仿真电视机光学三原色显示画面,我是要成为海贼王的男人》
《Unity后处理(图像优化特效技术),实现影视级别的镜头效果,辅助标签:PostProcessing》
好了,剩下的就是大家自由发挥了,添加一些其他动画,进行组合、控制。
关于Animator
动画控制,我之前写过相关教程,推荐大家看下,《Unity动画状态机Animator使用》
本文Demo
工程我已上传到CODE CHINA
,感兴趣的同学可自行下载学习,
地址:https://codechina.csdn.net/linxinfa/MiHoYoModelTest
好啦,就到这里吧~
我是林新发:https://blog.csdn.net/linxinfa
原创不易,若转载请注明出处,感谢大家~
喜欢我的可以点赞、关注、收藏,如果有什么技术上的疑问,欢迎留言或私信~