• 【Unity3D】Unity3D开发《我的世界》之一、创建一个面


    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/unity_minecraft_01.html

    最近总有人问及我的游戏里跟《我的世界》一样的地形是如何实现的,所以在这里开一个系列教程总结回答一下,也算是对自己的一个梳理和记录。

     

    一、简单分析

    对《我的世界》感兴趣,且有一定Unity3D基础的人,应该都或多或少的尝试过自己去做一个吧。

    有些人是用Unity3D自带的cube,然后用三层for循环,把cube堆叠起来,但是会发现游戏几乎卡爆了,根本没办法运行。

    如果看过我以前换装系统教程人应该都知道,这是因为每一个cube都是独立的物体,一个chunk就是65536个方块,不卡爆就怪了。

    既然这样,那我们把所有的cube合并成一个物体行不行?

    也不行。

    因为在地底90%的面都是看不到的,这些面实际上不应该存在,也都应该删掉,否则对CPU和GPU都是极大的负担。

    基于以上的原因,直接用cube是肯定不行的,那就只能我们自己通过代码来生成面,而且只生成我们需要的面,这样就没有上面的问题了。《我的世界》也是这么做的。

     

     

    二、理论基础(重点)

    1、法线

    法线就是垂直于面的一条线,它有方向,没有大小。

    法线的方向就是面朝外的方向。比如我们现在盯着显示器看,从显示器的正中心会有一条法线垂直于屏幕指向我们。

    法线向外的面就是正面,相反的就是背面,一般来讲,从正面看才能看到面,背面看面是看不到的。

    2、三边面和四边面

    三边面就是三条边组成的面,四边面就是四条边组成的面。

    三边面在三维空间中是不可扭曲的,而四边面在三维空间中可以扭曲。所以Unity里只支持三边面。其他支持四边面的软件例如3dmax在导出fbx的时候,会把四边面转换成三边面。

    3、左手坐标系和右手坐标系

    我们的三维坐标系,在3dmax里是右手坐标系,而在Unity里是左手坐标系。

    左手坐标系和右手坐标系的区别可以看一下这个博客 http://www.cnblogs.com/mythou/p/3327046.html

     

    4、三边面如何组成四边面

    先看看上面这张非常传神的图,左边是Unity里的左手坐标系,右边是我们想在这个坐标系里生成的一个面以及它的各个点坐标。

    012和230这两个三边面就组成了一个四边面。

    如果我问,这个四边面有几个顶点,想必大家都会回答4个,实际上是6个,012和230这是6个顶点,不同面的顶点不公用。

    要组成2个三边面可以有很多种顺序,例如012和320、012和032、023和012等等等

    但是我们一般都是按照4个点的顺序来画2个三边面组成四边面,所以可选的只有【012和230、230和012】,以及【032和210、210和032】这两大类

    这两类画法有什么区别呢?细心的童鞋应该已经发现,这两种方式前者是逆时针,后者是顺时针。

    这种循环的方向会导致面的法线方向不同,而这个法线方向会决定这个面的朝向。

    我们要确定这个法线方向其实很简单,上面说了,Unity里是左手坐标系,我们拿出左手,伸直,拇指与其他四个指头垂直,然后四指弯曲,指尖朝向循环的方向,拇指就指向法线的方向。

    有没有觉得很熟悉?这和初中学过的左手螺旋定则一模一样。

     

    由此我们得出结论,要想生成正确的面(法线指向我们),我们只能用【032和210、210和032】

     

    这里需要注意的一点是,我们确定4个点的循环方向,和生成三边面时的循环方向无关,只要生成三边面时,用到的前4个点的index顺序没错就行了。

     

    三、代码实现

    该有的理论知识都有了,下面我们就手动生成一个面试试看

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Chunk : MonoBehaviour
    {
        private Mesh mesh;
    
        //面需要的点
        private List<Vector3> vertices = new List<Vector3>();
        //生成三边面时用到的vertices的index
        private List<int> triangles = new List<int>();
    
        void Start()
        {
            mesh = new Mesh();
    
            AddFrontFace();
    
            //为点和index赋值
            mesh.vertices = vertices.ToArray();
            mesh.triangles = triangles.ToArray();
    
            //重新计算顶点和法线
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();
    
            //将生成好的面赋值给组件
            GetComponent<MeshFilter>().mesh = mesh;
        }
    
        void AddFrontFace()
        {
            //添加4个点
            vertices.Add(new Vector3(0, 0, 0));
            vertices.Add(new Vector3(0, 0, 1));
            vertices.Add(new Vector3(0, 1, 1));
            vertices.Add(new Vector3(0, 1, 0));
    
            //第一个三角面
            triangles.Add(0);
            triangles.Add(3);
            triangles.Add(2);
    
            //第二个三角面
            triangles.Add(2);
            triangles.Add(1);
            triangles.Add(0);
        }
    }

    然后建一个空物体,把这个脚本拖上去,再添加MeshFilter和MeshRenderer组件,然后随便给一个Material,运行

     

  • 相关阅读:
    day05 集合
    day05 判断敏感字符
    day05 None类型
    day05 字典
    day04元组
    day04列表
    HDFS配额管理(实战)
    hive数据库的哪些函数操作是否走MR
    oracle 裸设备划分 --centos6.5
    redis3.0.7集群部署手册
  • 原文地址:https://www.cnblogs.com/shamoyuu/p/unity_minecraft_01.html
Copyright © 2020-2023  润新知