Unity3D中网格合并示例研究

Unity3D中网格合并示例的研究:为了实现游戏人物外形的定制,专门研究了Unity示例程序 。

首先需要了解几个基本对象的结构

一、 SkinedMeshRender:该对象负责网格绘制。

主要数据成员包括:

var bones : Transform[] 骨骼

var materials : Material[] 材质

var sharedMesh : Mesh 网格

其中Mesh的主要成员是:

vertices : Vector3[] 顶点

boneWeights : BoneWeight[] 骨骼权重

boneWeights数组与vertices数组对应,表示对应下标的顶点运动受骨骼影响的权重。BoenWeight结构记录了骨骼在SkinedMeshRender.bones数组中的索引。


二、网格和材质的对应关系

一张实际的网格只能施加一个材质。因此,当render所使用的mesh包含多个实际网格(sub mesh),它对每个sub mesh所施加的材质实际上是materials数组中对应下标的材质。

三、合并网格(CombineMeshes)。函数的第二个参数是设置是否将多个子网格合并成一张实际的网格。正如前面所述,一 个实际的网格只能施加一个材质,所以只有被合并的所有网格原来使用的就是同一个材质(即共享材质)时,将它们真正合并才能正确应用材质。否则,应该将该参 数置为false,表示不实际合并这些sub mesh,而是将它们作为被合并后Mesh对象的sub mesh。

四、数组对应问题:网格顶点和骨骼、sub mesh和材质之间的对应都是通过数组下标进行的,所以操作时保证新生成的个数组下标对应关系正确是非常重要的。

这是例子中组合创建模型的主要函数,我将自己理解后的备注添加在里面。

    // Creates a character based on the currentConfiguration recycling a

    // character base, this way the position and animation of the character

    // are not changed.

    // 这个函数实际上并没有将各部分的子网格合并成一张网,而只是将他们合并到

    // 同一个Mesh下作为sub mesh。因为一张网格只能用一个材质,只有所有子网格

    // 都共享同一个材质时,合并成一张网才能保证材质应用正确。

    public GameObject Generate(GameObject root)

    {

    // The SkinnedMeshRenderers that will make up a character will be

    // combined into one SkinnedMeshRenderers using multiple materials.

    // This will speed up rendering the resulting character.

    List<CombineInstance> combineInstances = new List<CombineInstance>();

    List<Material> materials = new List<Material>();

    List<Transform> bones = new List<Transform>();

    //获得构成骨架的所有Transform

    Transform[] transforms = root.GetComponentsInChildren<Transform>();

    //一次处理构成身体的各部分

    foreach (CharacterElement element in currentConfiguration.Values)

    {

    //GetSkinnedMeshRenderer()内部Instantiat了一个由该部分肢体Assets构成的

    //GameObject,并返回Unity自动为其创建SinkedMeshRender。

    SkinnedMeshRenderer smr = element.GetSkinnedMeshRenderer();

    //注意smr.materials中包含的材质数量和顺序与下面的sub mesh是对应的

    materials.AddRange(smr.materials);

    for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++)

    {

    CombineInstance ci = new CombineInstance();

    ci.mesh = smr.sharedMesh;

    ci.subMeshIndex = sub;

    combineInstances.Add(ci);

    }

    // As the SkinnedMeshRenders are stored in assetbundles that do not

    // contain their bones (those are stored in the characterbase assetbundles)

    // we need to collect references to the bones we are using

    // 网格点与骨骼的对应关系是通过Mesh数据结构中的BoneWeight数组来实现的。该数组

    // 与网格顶点数组对应,记录了每个网格点受骨骼(骨骼记录在SinkedMeshRender的bones

    // 数组中,按下标索引)影响的权重。

    // 而此处,示例程序提供的肢体Assets并不包含骨骼,而是返回骨骼名称。因此,推断

    // GetBoneNames()返回的骨骼名称应该与实际骨骼数组的顺序相同。

    foreach (string bone in element.GetBoneNames())

    {

    foreach (Transform transform in transforms)

    {

    //通过名字找到实际的骨骼

    if (transform.name != bone) continue;

    bones.Add(transform);

    break;

    }

    }

    Object.Destroy(smr.gameObject);

    }

    // Obtain and configure the SkinnedMeshRenderer attached to

    // the character base.

    // 至此,combineInstances、bones和materials三个数组中的数据对应关系是正确的。

    // 合并时,第二个参数是fals,表示保持子网格不变,只不过将它们统一到一个Mesh里

    // 来管理,这样只需采用一个SkinedMeshRender绘制,效率较高。

    SkinnedMeshRenderer r = root.GetComponent<SkinnedMeshRenderer>();

    r.sharedMesh = new Mesh();

    r.sharedMesh.CombineMeshes(combineInstances.ToArray(), false, false);

    r.bones = bones.ToArray();

    r.materials = materials.ToArray();

    return root;

    }
原文地址:http://bbs.9ria.com/thread-193731-1-1.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值