赞
踩
在上篇文章
游戏码农:[Unity3d手游开发笔记]角色捏脸的实现zhuanlan.zhihu.com讲述了捏脸中通过调整骨骼的位置,进而保存为bindpose,最终修改脸型的原理;
在真正游戏中,除了修改脸型,我们还需要调整眉毛,眼睛,嘴唇等部位的显示,这些一般都是通过替换贴图的方式来实现的;
我们可以通过两种方式来修改单个部位的贴图:
1:每个单独的部位作为一个Render,我们直接修改材质的贴图即可
优点:原理简单,实现容易
缺点:每个部位都是单独一个drawcall,增加绘制压力
2:整个脸型使用一张贴图,这张贴图是通过一张基本脸型+各个部位的贴图合并到一起动态生成
优点:无论脸上多少个部位贴图需要修改,只有一个drawcall
缺点:每个角色都得动态生成一张脸型贴图,内存增加
本文通过一个简单的例子来讲述第2种方式通过合并贴图的方式来实现捏脸效果
1:创建一个RenderTexture,作为脸型贴图
- private void CreateRT()
- {
- _rt = RenderTexture.GetTemporary(512, 512, 0, RenderTextureFormat.ARGB32);
- _rt.useMipMap = true;
- _rt.autoGenerateMips = true;
- }
2:创建一个CommandBuffer和用于绘制贴图的材质,Mesh,用于绘制贴图到RT上
- private void CreateCommandBuffer()
- {
- // 绘制命令
- _commandBuffer = new CommandBuffer();
- // 绘制一张贴图到RT
- // 通过绘制一个平面Mesh,并添加贴图材质的方式
- // 1:绘制的材质
- _blendMat = new Material(Shader.Find("Custom/CustomTex"));
- _blendMatProperty = new MaterialPropertyBlock();
- // 2:绘制平面Mesh
- _planeMesh = new Mesh();
- _planeMesh.SetVertices(new List<Vector3>()
- {
- new Vector3(0,0,0.1f),
- new Vector3(0,1,0.1f),
- new Vector3(1,1,0.1f),
- new Vector3(1,0,0.1f)
- });
- _planeMesh.SetTriangles(new int[]
- {
- 0, 1, 2,
- 2, 3, 0
- }, 0);
- _planeMesh.SetUVs(0, new List<Vector2>()
- {
- new Vector2(0, 0),
- new Vector2(0, 1),
- new Vector2(1, 1),
- new Vector2(1, 0)
- });
- }

3:绘制脸型贴图
- private void BlitBaseTex()
- {
- Texture baseTex = Resources.Load<Texture>("base");
- if (baseTex != null)
- {
- _commandBuffer.Blit(baseTex, _rt);
- }
- }
- private void BlendMouthTex()
- {
- Texture mouth1Tex = Resources.Load<Texture>("mouth1");
- if (mouth1Tex != null)
- {
- // 设置渲染目标为当前创建的脸型RT
- _commandBuffer.SetRenderTarget(_rt);
- // 设置正交投影
- _commandBuffer.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.Ortho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 100.0f));
- // 设置嘴型的材质
- _blendMatProperty.Clear();
- // 设置嘴型的贴图
- _blendMatProperty.SetTexture("_MainTex", mouth1Tex);
- // 设置嘴型的贴图的缩放偏移
- _blendMatProperty.SetVector("_MainTex_ST", new Vector4(0.5f, 0.5f, 0.25f, 0.05f));
- // 绘制Mesh
- _commandBuffer.DrawMesh(_planeMesh, Matrix4x4.identity, _blendMat, 0, 0, _blendMatProperty);
- }
- }

Graphics.ExecuteCommandBuffer(_commandBuffer);
4:把RT赋值到对应的材质即可,这里是用UI来绘制的
rawImage.texture = _rt;
备注:修改嘴型贴图在脸型上的位置
嘴只是脸型上的一小块贴图,但对于嘴的贴图来说UV仍是0-1,所以我们需要缩放偏移UV到嘴的位置
正常情况下,我们要使用一张大贴图上的一部分纹理时是通过设置纹理的ST,也就是缩放和偏移来实现的,在Shader中的计算方式为:
- // Transforms 2D UV by scale/bias property
- #define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
现在我们这种情况正好相反,所以反向求解即可:
- sampler2D _MainTex;
- float4 _MainTex_ST;
-
- v2f vert (appdata v)
- {
- v2f o;
- o.vertex = UnityObjectToClipPos(v.vertex);
- o.uv = (v.uv - _MainTex_ST.zw) / _MainTex_ST.xy;
- return o;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。