【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,運行

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM