2018-12-15 11:20:19 qq_21153225 阅读数 3741

Unity中使用顶点动画模型

1.将模型导入3DsMax中

2.导出pc2文件和FBX文件,并导入到Unity中

3.在unity中使用Mega Fiers插件

    1)在导入后的gameobject上,添加point cache 组件

    2)在检视面板Inspector中选择相应按钮,点击pc2导入,完成导入动画

2013-09-12 15:43:30 ychl87 阅读数 8029

一.unity3d中加载模型时,网格顶点发生变化的解决办法。

unity3d中mesh网格为三角网格,目前unity3d直接导入模型时,会使得模型的顶定点数发生改变。解决的办法:在project中点击已经加载的模型,在Import Setting中将Normals设为None,点击Apply。然后再将Normals设为Import,重新加载,再点击Apply。


二.unity3d中BlendShape混合动画编程

主要参考了http://forum.unity3d.com/threads/15424-Morph-Target-Script

在unity3d中使用Mesh.vertices获得顶点位置,使用Mesh.normal获得顶点法线。当BS模型的权重时,需要重新计算Mesh.vertices和Mesh.normal,再使用RecalculateBounds重新计算BS模型边界。


定义BS类,记录每个BS模型的顶点位置,顶点法线


internal class BlendShapeVertex
    {
        public int originalIndex;
        public Vector3 position;
        public Vector3 normal;
    }

    internal class BlendShape
    {
        public BlendShapeVertex[] vertices;// = new Array();
    }


其中定义originalIndex是为了记录某个顶点的索引值。因为在BS模型中,很多顶点位置都与对应的基础表情顶点位置一致,所以在重新计算新的混合表情时,就不需要再计算这些点,提高运算速率。


建立BS模型数据

void BuildBlendShapes()
    {

        blendShapes = new BlendShape[attributeMeshes.Length];

        for (int i = 0; i < attributeMeshes.Length; i++)
        {
            blendShapes[i] = new BlendShape();
			
            int blendShapeCounter = 0;
            for (int j = 0; j < workingMesh.vertexCount; j++)
            {
                
                if (workingMesh.vertices[j] != attributeMeshes[i].vertices[j])
                {
                    blendShapeCounter++;
                }
            }
            
            blendShapes[i].vertices = new BlendShapeVertex[blendShapeCounter];
            blendShapeCounter = 0;
            for (int j = 0; j < workingMesh.vertexCount; j++)
            {
                if (workingMesh.vertices[j] != attributeMeshes[i].vertices[j])
                {
                    BlendShapeVertex blendShapeVertex = new BlendShapeVertex();
                    blendShapeVertex.originalIndex = j;
                    blendShapeVertex.position = attributeMeshes[i].vertices[j] - workingMesh.vertices[j];
                    blendShapeVertex.normal = attributeMeshes[i].normals[j] - workingMesh.normals[j];

                    blendShapes[i].vertices[blendShapeCounter]=blendShapeVertex;
                    blendShapeCounter++;
                }
            }
        }
    }

BS融合


public void SetMorph()
    {
        Vector3[] morphedVertices = sourceMesh.vertices;
        Vector3[] morphedNormals = sourceMesh.normals;

        for (int j = 0; j < attributeMeshes.Length; j++)
        {
            if (!Mathf.Approximately(attributeProgress[j], 0))
            {
                for (int i = 0; i < blendShapes[j].vertices.Length; i++)
                {
					int a = blendShapes[j].vertices[i].originalIndex;
					if(a!=i)
					{
						int aa = 0;
					}
                    morphedVertices[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].position * attributeProgress[j];
                    morphedNormals[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].normal * attributeProgress[j];
                }
            }
        }	
        workingMesh.vertices = morphedVertices;
        workingMesh.normals = morphedNormals;
        workingMesh.RecalculateBounds();
    }

unity3d中BlendShape融合

using UnityEngine;
using System.Collections;

public class MorphTargets : MonoBehaviour {

	internal class BlendShapeVertex
    {
        public int originalIndex;
        public Vector3 position;
        public Vector3 normal;
    }

    internal class BlendShape
    {
        public BlendShapeVertex[] vertices;
    }

    public Mesh sourceMesh; //The original mesh
    public Mesh[] attributeMeshes; //The destination meshes for each attribute.
    public float[] attributeProgress;
    private BlendShape[] blendShapes;
    private Mesh workingMesh;

    void Awake()
    {
		attributeProgress = new float[attributeMeshes.Length];
        for (int i = 0; i < attributeMeshes.Length; i++)
        {
            if (attributeMeshes[i] == null)
            {
                Debug.Log("Attribute " + i + " has not been assigned.");
                return;
            }
        }
        MeshFilter filter = gameObject.GetComponent(typeof(MeshFilter)) as MeshFilter;
        filter.sharedMesh = sourceMesh;
        workingMesh = filter.mesh;
		
        int vertexCount = sourceMesh.vertexCount;
        for (int i = 0; i < attributeMeshes.Length; i++)
        {
            if (attributeMeshes[i].vertexCount != vertexCount)
            {

                Debug.Log("Mesh " + i + " doesn't have the same number of vertices as the first mesh");
                return;
            }
        }

        BuildBlendShapes();
    }

    void BuildBlendShapes()
    {

        blendShapes = new BlendShape[attributeMeshes.Length];

        for (int i = 0; i < attributeMeshes.Length; i++)
        {
            blendShapes[i] = new BlendShape();
			
            int blendShapeCounter = 0;
            for (int j = 0; j < workingMesh.vertexCount; j++)
            {
                
                if (workingMesh.vertices[j] != attributeMeshes[i].vertices[j])
                {
                    blendShapeCounter++;
                }
            }
            
            blendShapes[i].vertices = new BlendShapeVertex[blendShapeCounter];
            blendShapeCounter = 0;
            for (int j = 0; j < workingMesh.vertexCount; j++)
            {
                if (workingMesh.vertices[j] != attributeMeshes[i].vertices[j])
                {
                    BlendShapeVertex blendShapeVertex = new BlendShapeVertex();
                    blendShapeVertex.originalIndex = j;
                    blendShapeVertex.position = attributeMeshes[i].vertices[j] - workingMesh.vertices[j];
                    blendShapeVertex.normal = attributeMeshes[i].normals[j] - workingMesh.normals[j];

                    blendShapes[i].vertices[blendShapeCounter]=blendShapeVertex;
                    blendShapeCounter++;
                }
            }
        }
    }


    public void SetMorph()
    {
        Vector3[] morphedVertices = sourceMesh.vertices;
        Vector3[] morphedNormals = sourceMesh.normals;

        for (int j = 0; j < attributeMeshes.Length; j++)
        {
            if (!Mathf.Approximately(attributeProgress[j], 0))
            {
                for (int i = 0; i < blendShapes[j].vertices.Length; i++)
                {
					int a = blendShapes[j].vertices[i].originalIndex;
					if(a!=i)
					{
						int aa = 0;
					}
                    morphedVertices[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].position * attributeProgress[j];
                    morphedNormals[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].normal * attributeProgress[j];
                }
            }
        }	
        workingMesh.vertices = morphedVertices;
        workingMesh.normals = morphedNormals;
        workingMesh.RecalculateBounds();
    }
}




2018-10-25 22:20:01 Sam_ONE 阅读数 877

首先要知道顶点函数中的一个顶点会包含以下信息:

  1. float3类型的顶点法线方向
  2. float3类型的顶点位置
  3. 甚至可能包含这个顶点的颜色信息(float4类型,注意:导入模型的默认材质不会显示顶点颜色的,我们需要自己编写一个着色器提取顶点颜色)

      (参考官方文档: https://docs.unity3d.com/Manual/SL-VertexProgramInputs.html

然后是使用正弦波来动态修改网格上每个顶点的位置,代码:

Shader "Sam'Shader编程/顶点动画(波形上下)" {

    Properties{

        _MainTex("主贴图(RGB)", 2D) = "white"{}
        _TintAmount("Tint Amount" ,Range(0,1)) = 0.5
        _ColorA("ColorA", Color) = (1,1,1,1)
        _ColorB("ColorB", Color) = (1,1,1,1)
        _Speed("Wave Speed", Range(0.1,80)) = 5
        _Frequency("Wave Frequency", Range(0,5)) = 2
        _Amplitude("Wave Amplitude", Range(-1,1)) = 1

    }

        SubShader{

            //Tags{"RenderMode" = "Opaque"}

            Pass{

            CGPROGRAM

#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"

        sampler2D _MainTex;
        float4 _MainTex_ST;
        float _TintAmount;
        fixed4 _ColorA;
        fixed4 _ColorB;
        float _Speed;
        float _Frequency;
        float _Amplitude;

            struct appdata 
            {
                float4 texcoord : TEXCOORD0;
                float4 vertex : POSITION;//顶点位置
                //float3 normal : NORMAL;
            };


            struct v2f
            {
                float2 uv : TEXCOORD1;
                float3 vertColor : TEXCOORD2;
                float4 vertex : SV_POSITION;
            };


            v2f vert(appdata v)
            {
                v2f o;
                float time = _Time.y * _Speed;
                float waveValueA = sin(time + v.vertex.x *_Frequency)* _Amplitude;
                //sin(time + v.vertex.x) * _Amplitude;// + v.vertex.y + v.vertex.z

                //**2 得出的时间正弦值用的xyz(其中之一时) 不能与次出的因子为相同的轴 如:float3(v.vertex.x* waveValueA, v.vertex.y, v.vertex.z);

                //***或者 时间正弦值 直接用xyz的三个值相加计算 如shader顶点动画(波形水平) 中
                v.vertex.xyz = float3(v.vertex.x, v.vertex.y + waveValueA, v.vertex.z);

                //v.vertex = float4(v.vertex.x, v.vertex.y* waveValueA, v.vertex.z, v.vertex.w);
                o.vertex = UnityObjectToClipPos(v.vertex);

                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

                // uv流动效果
                //o.uv += float2(0, time);

                // 颜色
                //o.vertColor = float3(waveValueA, waveValueA, waveValueA);



                return o;

            }

            fixed4 frag(v2f i) : SV_Target{

                fixed4 col = tex2D(_MainTex, i.uv);
                float3 tintColor = lerp(_ColorA, _ColorB, i.vertColor).rgb;
                col = fixed4(col.rgb * (tintColor * _TintAmount), col.a);
                return col;
            }

            ENDCG
            }
        }
}

效果(没怎么细调,可能看上去比较low):

2018-06-05 20:52:39 Dylan_Day 阅读数 288

1、针对Unity中实现正确动画效果的角色,首先需要在3D建模软件中实现骨骼化操作。

骨骼化是指底层骨骼结构添加至设计师创建的模型中,且各快骨骼与网格顶点间实现了加权操作

可使用MakeHuman软件快速生成骨骼化角色


2、①  导入骨骼化角色,定义缩放因子

② 切换到Object Inspector中的Rig选项卡,在Animation Type下拉框选择Humanoid

    默认时,如果网格包含骨骼化信息,该值为Generic;否则,该值表示None

    Generic用于骨骼化非人物角色网格,如动物、起重机等

③ Apply后,一个勾选符号将显示在Object Inspector中Configure按钮一侧

表明Mecanim是否可在网格文件中成功地识别人物角色的骨骼信息,也可通过人工方式进行配置


3、Avatar和重定位

人工配置Avatar网格,单击Configure按钮并显示Avatar编辑器

利用Mapping和Muscles&Settings进行调整和设置   





4、动画的重定位操作

可根据不同的角色或文件获取动画数据,并将其应用于包含正确配置的Avatar的其他角色上

可导入游戏角色资源包 Assets | Import Package | Characters

包含了第一人称和第三人称控制器,以及行走和跑动循环的角色动画


将角色网格从Project面板中拖拽至场景中,Unity会自动添加Animator组件

将系统自带的行走动画赋给角色,Unity会自动配置Animation Controller


5、根节点运动

根运动:应用于网格层次结构最上方(根)对象的位置和旋转

针对骨骼和各部件,导入的角色网格包含了多个子对象

然而,作用于最上层对象的动画视为根运动,默认情况下启动根运动

如角色处于运动状态行走,而不是原地踏步

可取消选中 Object Inspector 的 Animator 组件的 Apply Root Motion 复选框


根运动使得角色运动更具有真实感,该过程访问了动画曲线数据,对应角色运动方式通过插值计算高效实现

禁用根运动则会生成快速、灵活的运动行为,适用于街机和动作类游戏


6、修复运动偏移

偏移的原因在于,存在某一偏差使得一段时间内角色偏移路径,主要存在于动画的根运动中,与场景和角色无关

在 Project 面板的 Animation 选项卡查看文件的动画数据

偏差的问题主要源于角速度,在Average Velocity向量表示角色在其动画生命周期内的方向和朝向


解决:选中Root Transform Rotation 的 Bake Into Pose 复选框,调整Offset字段,直至Average Velocity值为0

另外,如果角色在地面行走实际位置高于或低于中心位置,将Root Transform Position(Y)中

Based Upon(at Start)字段调整为Feet




2016-12-03 10:21:03 u013354943 阅读数 1035

这篇文章你一定要看要去实践,这是一个非常好的利用顶点着色来做贴图混合控制及顶点动画控制!

插件Advanced Vertex Painting ,喜欢的请到unity商店购买.

基本使用

下载后导入unity,选中要设置顶点色的模型后开始着色:

红色箭头部分都是重点提示,具体使用网上看看教程,翻墙看看也有很多的。


Color Settings 就是颜色设置,Red就设置为红色R通道为255其他通道都为0,以此类推。Tool Settings  的 Paint就是画图上色, Erase就是去除颜色,Smooth平滑过渡颜色!后面调整画笔大小力度还有layer分层处理等,具体参数使用看教程啦~

这个Vpaint窗口不小心关掉了还可以选中 最左侧箭头的new Vpaint Group后点击最右侧图中V paint Group 组件中的第一个 open vpaint按钮!


主要原理

就是利用顶点的颜色通道控制顶点动画的顶点偏移大小!

例:

offset.y =  sin( _Time.z  + v.vertex.x ) * v.color.a;   //根据顶点着色插件写入的顶点颜色Alpha通道来控制摆动幅度   !


 地形纹理混合原理

//顶点颜色控制贴图的混合
fixed4 col = tex2D(_TexR,i.uv2) * i.color.r;
 col += tex2D(_TexG,i.uv2) * i.color.g;
 col += tex2D(_TexB,i.uv2) * i.color.b;
 col += tex2D(_TexA,i.uv2) * i.color.a;

正常视图下的效果:

RGB三个通道顶点色混合后的图:(随手混的,别喷我。。)


没有更多推荐了,返回首页