【Unity3D】 合并mesh那些事 CombineMeshes

合并mesh在游戏中,经常用到。可惜身为国家一级烧钱手游甲级界面攻城狮,全力跟ugui和ngui打了一辈子的交道,竟初次接触到。

我这个界面攻城狮有幸接触到时装分部位换装这种功能(分部位换装,比如,头饰,上衣,下衣,鞋等)。以前整套的时装都是直接换一个模型,而分部位如果也是直接换整套的模型,那基本只有宇宙级大神才会那么干。我谷歌一下,CombineMeshes?哇哦。unity已经封装好方法了。直接用就是了,这时候主程也走了过来说这套项目都实现了,你直接调用就是了。我看了下代码,是挺方便的。但是,作为一级界面攻城狮,我岂是那种饭来张口之人。于是,我不死心的谷歌了一下“mesh是什么”。好吧,这篇文章的基调你应该已经get到了,这是一篇面向新手的文章。我将从最基础的知识点来研究合并mesh那些事。你可能觉得我的废话有点多,不过实在不好意思,我最近刚刚买了键盘,茶轴的,打字太爽了,不自觉的想打字。而且打字变快会产生一个问题,你的思绪会跟不上节奏,所以当我想着应该要说明一下这篇文章的基调的那0.1秒间,手下已经写下了这么多字。真是不好意思。

一切要从图形接口开始说起,DirectX和OpenGL的hello world你肯定看过,类似这种

glBegin(GL_LINES);
      glColor3f(1.0,1.0,0.0);
      glVertex2f(-0.5,0.0);
      glVertex2f(0.5,0.0);
      glColor3f(1.0,0.0,1.0);
      glVertex2f(0.0,0.5);
      glVertex2f(0.0,-0.5);
    glEnd();

SimpleVertex vertices[] =
    {
        XMFLOAT3(0.0f, 0.5f, 0.5f),
        XMFLOAT3(0.5f, -0.5f, 0.5f),
        XMFLOAT3(-0.5f, -0.5f, 0.5f),
    };

这里引出一个概念“顶点”。顶点可以组成一条直线,可以组成三角形。可以组成复杂的3d世界。其实没看过图形接口也没关系(当然,如果你想了解,我这倒是可以提供入口。OpenGl可以搜索“glut”用这个可以很方便的做几个例子,边做边查。DirectX可以下载“DirectX 11 sdk ”文档从StartUp开始看,还有很多实例可以直接运行,看代码),想象一下自己是图形学之父。你想要构建3d世界。你肯定也会从点开始。比如你想在屏幕上显示一个正方形,那只需要关键的4个点就OK了。然后4个点线连起来构建成正方形,你就可以把它渲染成你想要的颜色。后来你又想在屏幕上显示一个五角形,那好五个点,连5条线,着个颜色。再复杂一点,凹多边形,数学好的你一数,8个耶,8个点就够了,但是问题来了,随着点的增多连线这项工作越来越难。于是聪明的科学家们想到用基础形状来构建多边形,这个基础形状就是三角形。这样的话,刚才的工作就变成这样了。


这样问题就变得可靠了。3个顶点确定一个三角形。你可能会问了为啥是三角形,正方形不行么?其实这个问题可以这样想:两个点构建一条线,想构成一个图形至少要3个点,那3个点组成的自然就是三角形了。有了无数个三角形,就组成任何形状。比如下面这个


是不是很像一个张网呢。对,这个就是mesh。

现在用unity弄个mesh玩玩。


新建三个空节点


新建一个材质球,随便设置下颜色,我这里设置了红色


然后把上面三个新增得空节点都挂上一个组件:MeshRenderer。

并设置Materals 得size为1.然后把red材质球拖到上面(注意shader我设置成了GUI/ TextShader,这样会渲染到最上层,关于shader如果有缘的话,后面想多研究一下,多写点。毕竟我这个界面程序员在数学方面自我感觉良好

下面开始写脚本 Client.cs 

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Client : MonoBehaviour {

	// Use this for initialization
	void Start () {
        DrawMesh_1_rectangle( 3, 2 );
	}

    private void DrawMesh_1_rectangle(int width,int height) {
        GameObject go = GameObject.Find( "Mesh1" );
        MeshFilter mf = go.AddComponent<MeshFilter>();
        Mesh mesh = mf.mesh;

        Vector3[] v = new Vector3[4];

        v[0] = new Vector3( 0, 0, 0 );
        v[1] = new Vector3( 0, height, 0 );
        v[2] = new Vector3( width, 0, 0 );
        v[3] = new Vector3( width, height, 0 );

        mesh.vertices = v;

        int[] triangles = new int[6];
        triangles[0] = 0;
        triangles[1] = 1;
        triangles[2] = 2;

        triangles[3] = 3;
        triangles[4] = 2;
        triangles[5] = 1;

        mesh.triangles = triangles;
        
    }
    
}

写完后,拖拽到Main Camera上


运行游戏:

(这个水印真是打击我分享知识的积极性)

是的,这样你就完成了4个顶点,2个三角形,的绘制。这里涉及到MeshFilter和MeshRenderer这两个组建。这里可以不用细究。我们用到了MeshFilter.mesh 然后MeshRenderer充当一个渲染器成像。

好,现在我们继续完善。多绘制几个mesh


参照上面两张图,补充我们的脚本(建议自己去观察三个重复性的mesh代码的共同点,来理解顶点和三角形。所以这段代码没什么好讲的)


using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Client : MonoBehaviour {

    // Use this for initialization
    void Start() {
        DrawMesh_1_rectangle( 2, 1 );
        DrawMesh_2_pentagon( -2, 0 );
        DrawMesh_3_concave( 3, 0 );
    }

    private void DrawMesh_3_concave( int posX, int posY ) {
        GameObject go = GameObject.Find( "Mesh3" );
        MeshFilter mf = go.AddComponent<MeshFilter>();
        Mesh mesh = mf.mesh;

        Vector3[] v = new Vector3[10];

        v[0] = new Vector3( posX, posY, 0 );
        v[1] = new Vector3( posX + 0.5f, posY, 0 );
        v[2] = new Vector3( posX + 1, posY, 0 );
        v[3] = new Vector3( posX + 1.5f, posY, 0 );
        v[4] = new Vector3( posX + 1.5f, posY + 1, 0 );
        v[5] = new Vector3( posX + 1, posY + 1, 0 );
        v[6] = new Vector3( posX + 1, posY + 0.5f, 0 );
        v[7] = new Vector3( posX + 0.5f, posY + 0.5f, 0 );
        v[8] = new Vector3( posX + 0.5f, posY + 1, 0 );
        v[9] = new Vector3( posX, posY + 1, 0 );

        mesh.vertices = v;

        int[] triangles = new int[18];
        triangles[0] = 0;
        triangles[1] = 8;
        triangles[2] = 9;

        triangles[3] = 8;
        triangles[4] = 0;
        triangles[5] = 1;

        triangles[6] = 1;
        triangles[7] = 7;
        triangles[8] = 6;

        triangles[9] = 6;
        triangles[10] = 1;
        triangles[11] = 2;

        triangles[12] = 2;
        triangles[13] = 5;
        triangles[14] = 4;

        triangles[15] = 4;
        triangles[16] = 2;
        triangles[17] = 3;

        mesh.triangles = triangles;
    }

    private void DrawMesh_2_pentagon( int posX, int posY ) {
        GameObject go = GameObject.Find( "Mesh2" );
        MeshFilter mf = go.AddComponent<MeshFilter>();
        Mesh mesh = mf.mesh;

        Vector3[] v = new Vector3[5];

        v[0] = new Vector3( posX, posY, 0 );
        v[1] = new Vector3( posX, posY + 1, 0 );
        v[2] = new Vector3( posX + 1, posY, 0 );
        v[3] = new Vector3( posX + 1, posY + 1, 0 );
        v[4] = new Vector3( posX + 0.5f, posY + 1.5f, 0 );

        mesh.vertices = v;

        int[] triangles = new int[9];
        triangles[0] = 0;
        triangles[1] = 1;
        triangles[2] = 4;

        triangles[3] = 4;
        triangles[4] = 0;
        triangles[5] = 2;

        triangles[6] = 2;
        triangles[7] = 4;
        triangles[8] = 3;

        mesh.triangles = triangles;
    }

    private void DrawMesh_1_rectangle( int width, int height ) {
        GameObject go = GameObject.Find( "Mesh1" );
        MeshFilter mf = go.AddComponent<MeshFilter>();
        Mesh mesh = mf.mesh;

        Vector3[] v = new Vector3[4];

        v[0] = new Vector3( 0, 0, 0 );
        v[1] = new Vector3( 0, height, 0 );
        v[2] = new Vector3( width, 0, 0 );
        v[3] = new Vector3( width, height, 0 );

        mesh.vertices = v;

        int[] triangles = new int[6];
        triangles[0] = 0;
        triangles[1] = 1;
        triangles[2] = 2;

        triangles[3] = 3;
        triangles[4] = 2;
        triangles[5] = 1;

        mesh.triangles = triangles;

    }

}

运行unity:


嘻嘻。自己创建了三个mesh。开心不开心。

现在终于要回归本文的中心了。CombineMeshes


新建一个空节点


把三个mesh节点放在其下面(子节点)


在Combine创建一个脚本 CombineMeshs.cs

写代码:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class CombineMeshes : MonoBehaviour {
    void Update() {
        if ( Input.GetKeyDown( KeyCode.A ) ) {
            CombineMeshs();
        }
    }

    void CombineMeshs() {
        //获取MeshRender;  
        MeshRenderer[] meshRenders = GetComponentsInChildren<MeshRenderer>();

        //材质;  
        Material[] mats = new Material[meshRenders.Length];
        for ( int i = 0; i < meshRenders.Length; i++ ) {
            mats[i] = meshRenders[i].sharedMaterial;
        }

        //合并Mesh;  
        MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter>();

        CombineInstance[] combine = new CombineInstance[meshFilters.Length];

        for ( int i = 0; i < meshFilters.Length; i++ ) {
            combine[i].mesh = meshFilters[i].sharedMesh;
            combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
            meshFilters[i].gameObject.SetActive( false );
        }

        MeshRenderer mr = gameObject.AddComponent<MeshRenderer>();
        MeshFilter mf = gameObject.AddComponent<MeshFilter>();
        mf.mesh = new Mesh();
        mf.mesh.CombineMeshes( combine, false );
        gameObject.SetActive( true );
        mr.sharedMaterials = mats;
    }
}

可以看到 我们按键 A 会触发 合并mesh动作。他会将三个子节点的mesh合并到自己mesh上


如图,合并后的meshRender 汇总了三个material 你可以尝试下,三个mesh使用不同material是什么效果。

好了,简单的CombineMeshes终于被我啰里啰唆的讲完了。

但是,总求进取的界面程序员又在想,这合并前后,看着没什么区别啊。就算是我准备制作游戏里的时装界面了。我完全可以更换子节点的mesh。看上去就是换装了。我为什么还要合并他,有什么意义?

接下一篇(https://blog.csdn.net/TW_345/article/details/79806483

  • 5
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值