当前位置:   article > 正文

unity3d 动态合批设置_[Unity3d手游开发笔记]捏脸贴花的实现

unity 3d头像合批

在上篇文章

游戏码农:[Unity3d手游开发笔记]角色捏脸的实现​zhuanlan.zhihu.com

讲述了捏脸中通过调整骨骼的位置,进而保存为bindpose,最终修改脸型的原理;

在真正游戏中,除了修改脸型,我们还需要调整眉毛,眼睛,嘴唇等部位的显示,这些一般都是通过替换贴图的方式来实现的;

我们可以通过两种方式来修改单个部位的贴图:

1:每个单独的部位作为一个Render,我们直接修改材质的贴图即可

优点:原理简单,实现容易

缺点:每个部位都是单独一个drawcall,增加绘制压力

2:整个脸型使用一张贴图,这张贴图是通过一张基本脸型+各个部位的贴图合并到一起动态生成

优点:无论脸上多少个部位贴图需要修改,只有一个drawcall

缺点:每个角色都得动态生成一张脸型贴图,内存增加

本文通过一个简单的例子来讲述第2种方式通过合并贴图的方式来实现捏脸效果

1b6ae03df162431f42ea532ea3b094ed.gif

1:创建一个RenderTexture,作为脸型贴图

  1. private void CreateRT()
  2. {
  3. _rt = RenderTexture.GetTemporary(512, 512, 0, RenderTextureFormat.ARGB32);
  4. _rt.useMipMap = true;
  5. _rt.autoGenerateMips = true;
  6. }

2:创建一个CommandBuffer和用于绘制贴图的材质,Mesh,用于绘制贴图到RT上

  1. private void CreateCommandBuffer()
  2. {
  3. // 绘制命令
  4. _commandBuffer = new CommandBuffer();
  5. // 绘制一张贴图到RT
  6. // 通过绘制一个平面Mesh,并添加贴图材质的方式
  7. // 1:绘制的材质
  8. _blendMat = new Material(Shader.Find("Custom/CustomTex"));
  9. _blendMatProperty = new MaterialPropertyBlock();
  10. // 2:绘制平面Mesh
  11. _planeMesh = new Mesh();
  12. _planeMesh.SetVertices(new List<Vector3>()
  13. {
  14. new Vector3(0,0,0.1f),
  15. new Vector3(0,1,0.1f),
  16. new Vector3(1,1,0.1f),
  17. new Vector3(1,0,0.1f)
  18. });
  19. _planeMesh.SetTriangles(new int[]
  20. {
  21. 0, 1, 2,
  22. 2, 3, 0
  23. }, 0);
  24. _planeMesh.SetUVs(0, new List<Vector2>()
  25. {
  26. new Vector2(0, 0),
  27. new Vector2(0, 1),
  28. new Vector2(1, 1),
  29. new Vector2(1, 0)
  30. });
  31. }

3:绘制脸型贴图

  • 3.1:拷贝基本的脸型(这里做了个没有嘴型的脸)到RT
  1. private void BlitBaseTex()
  2. {
  3. Texture baseTex = Resources.Load<Texture>("base");
  4. if (baseTex != null)
  5. {
  6. _commandBuffer.Blit(baseTex, _rt);
  7. }
  8. }

8442f63de2036f7e946dec6912fdcc32.png
  • 3.2:绘制嘴型贴图到RT上
  1. private void BlendMouthTex()
  2. {
  3. Texture mouth1Tex = Resources.Load<Texture>("mouth1");
  4. if (mouth1Tex != null)
  5. {
  6. // 设置渲染目标为当前创建的脸型RT
  7. _commandBuffer.SetRenderTarget(_rt);
  8. // 设置正交投影
  9. _commandBuffer.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.Ortho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 100.0f));
  10. // 设置嘴型的材质
  11. _blendMatProperty.Clear();
  12. // 设置嘴型的贴图
  13. _blendMatProperty.SetTexture("_MainTex", mouth1Tex);
  14. // 设置嘴型的贴图的缩放偏移
  15. _blendMatProperty.SetVector("_MainTex_ST", new Vector4(0.5f, 0.5f, 0.25f, 0.05f));
  16. // 绘制Mesh
  17. _commandBuffer.DrawMesh(_planeMesh, Matrix4x4.identity, _blendMat, 0, 0, _blendMatProperty);
  18. }
  19. }

6324befe0f0f26272dbd677af69a658b.png
  • 3.3:调用绘制命令,执行绘制
Graphics.ExecuteCommandBuffer(_commandBuffer);
  • 3.4:最终RT的样子

b0d27e35edcc3b3634c41952a9322d86.png

4:把RT赋值到对应的材质即可,这里是用UI来绘制的

rawImage.texture = _rt;

备注:修改嘴型贴图在脸型上的位置

嘴只是脸型上的一小块贴图,但对于嘴的贴图来说UV仍是0-1,所以我们需要缩放偏移UV到嘴的位置

正常情况下,我们要使用一张大贴图上的一部分纹理时是通过设置纹理的ST,也就是缩放和偏移来实现的,在Shader中的计算方式为:

  1. // Transforms 2D UV by scale/bias property
  2. #define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)

现在我们这种情况正好相反,所以反向求解即可:

  1. sampler2D _MainTex;
  2. float4 _MainTex_ST;
  3. v2f vert (appdata v)
  4. {
  5. v2f o;
  6. o.vertex = UnityObjectToClipPos(v.vertex);
  7. o.uv = (v.uv - _MainTex_ST.zw) / _MainTex_ST.xy;
  8. return o;
  9. }
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号