[unity3d][通过代码]制作模型,动态生成模型,通过点画模型

代码制作模型的教程

    • 简介
    • 下面对基础知识进行讲解
    • Mesh的属性:
    • 画板
    • 通过代码制作模型的一个demo
    • 工程简介
      • 场景1
      • 二场景
      • 三场景:
      • 四场景:
      • 五场景:
      • 六场景:
  • 结束

简介

大家好 我是谢斯,今天给大家做一个关于,<代码制作模型的教程>

如何通过代码来制作一个我们想要的模型

通常我们所见到的模型,是maya或者3dmax制作并导出的fbx文件,而对于一些特殊的客户要求,这种模型无法满足条件

解决这类多变的形状的模型,如通过变化一些参数使得模型变化,这时使用maya/3dmax的模型就很难解决问题,我们需要通过写代码的方式来制作一个我们需要的模型.

下面对基础知识进行讲解

首先引入的是三个类型

Mesh 网格:模型的网格,建模就是建网格。

Mesh Filter 网格过滤器: 内包含一个Mesh组件,可以根据MeshFilter获得模型网格的组件,也可以为MeshFilter设置Mesh内容。

Mesh Renderer 网格渲染器: 是用于把网格渲染出来的组件。MeshFilter的作用就是把Mesh扔给MeshRender将模型或者说是几何体绘制显示出来。

[unity3d][通过代码]制作模型,动态生成模型,通过点画模型_第1张图片

上面的基础讲解可以看出主要的信息都在Mesh中,我们要制作模型也就是要自己做一个mesh然后放到Mesh Filter中就可以了.

下面我们再细致的了解一下mesh

Mesh的属性:

顶点坐标(vertex**)**顶点坐标数组存放Mesh的每个顶点的空间坐标,假设某mesh有n个顶点,则顶点坐标的的size为n

法线(normal**)**法线数组存放mesh每个顶点的法线,大小与顶点坐标对应,normal[i]对应顶点vertex[i]的法线

纹理坐标(uv**)**它定义了图片上每个点的位置的信息. 这些点与3D模型是相互联系的, 以决定表面纹理贴图的位置. UV就是将图像上每一个点精确对应到模型物体的表面. uv[i]对应vertex[i]

三角形序列(triangle**)*每个mesh都由若干个三角形组成,而三角形的三个点就是顶点坐标里的点,三角形的数组的size=三角形个数 3,三角形的顶点顺序必须是顺时针,顺时针表示正面,逆时针表示背面,而unity3d在渲染时默认只渲染正面,背面是看不见的。(也就是左手定责)

上面讲的都很理论下面我就用更白的话和更具体的实例来让大家明白.

画板

首先让我们来了解一下模型的本质,模型实际上就是点组成的.两个点连接起来就是一条线,而三个点互相连接就是一个面了,根据这三个点的连接顺序,我们就能得到一个方向,这个就是渲染的方向,也就是我们常说的unity的面,而unity的面是单面,而不是双面的,渲染的面的方向是有规则的,就是左手定则(我们看起来是顺时针 表示正面,逆时针 表示背面,正面是可以看到的,而背面是不可以被看到的,所以对于unity中的模型,其最基本的就是点,可以说对于模型来说所有的信息都记录在点上.

通过代码制作模型的一个demo

在SCRIPT6中的代码可以当做是一个模板
private Vector3 Faxian(Vector3 a, Vector3 b, Vector3 c, int index = 0)
private void AddCorss(ref Dictionary _dic_v3Normal, List _list_v3Vertices, int a, int b, int c)
protected void DrawModel(ref List _list_nTriangles, ref Dictionary _dic_v3Normal, List _list_v3Vertices, int a, int b, int c, int d)
这三个是一起的 但是只使用DrawModel就可以,其他的函数是辅助这个函数的
在这里插入图片描述

工程简介

场景1

下面我分6步来来给大家逐步深入的学习

我们先来设置三个点A® B(g) C(b)

然后把三个点按照A->C->B>A的顺序连接起来

根据连接的方向,我们可以得到这是一个逆时针,那么现在我们看到的这个面就是反面,在unity中以现在的视角是看不到面的

但是我们按照A->B->C->A的顺序来连接起来,通过左手定责,它就是一个朝向我们的面了,在unity中就可以看得到.

并且我们加入一个任意模型以这个模型做基础来修改他的点线面来制作

从图中可以很清晰的看出来,摄像机的那个面是顺时针方向,所以可以看到面,而scene视图中是正好相反的,所以看不到面

以上我已经介绍了简单的制作一个面的概念,下面我们来扩展成体的概念
[unity3d][通过代码]制作模型,动态生成模型,通过点画模型_第2张图片

using UnityEngine;

public class SCRIPT1 : MonoBehaviour
{
    public MeshFilter m_meshFilter; //meshfilter组件
    public Mesh m_mesh;
    public GameObject m_objA; //A点
    public GameObject m_objB; //B点
    public GameObject m_objC; //C点

    // 加载脚本实例时调用 Awake
    private void Awake()
    {
        m_meshFilter = GetComponent<MeshFilter>(); //得到meshfilter组件
        m_mesh = new Mesh(); //new 一个mesh

        Vector3[] vertices = new Vector3[] //顶点列表的变量
        {
            m_objA.transform.position, //加入A点坐标
            m_objB.transform.position, //加入B点坐标
            m_objC.transform.position  //加入C点坐标
        };

        int[] triangles = new int[] { 0, 1, 2 }; //按照A->B->C->A的顺序连接 放入三角序列中
        
        m_mesh.vertices = vertices; //把顶点列表 放到mesh中
        m_mesh.triangles = triangles; //把三角序列 放到mesh中

        m_meshFilter.mesh = m_mesh;   //把mesh放到meshfilter中   meshfilter会把它抛给renderer
    }
}

二场景

体就是多个面,多个三角形,多个角度,我们用一个简单的一个带90度折角的模型来展示一下如图

其中ABC 和ACD面垂直,现在我们通过代码来实现这个制作

现在我们发现这个面已经有了,但是没有菱角,没有立体感

[unity3d][通过代码]制作模型,动态生成模型,通过点画模型_第3张图片

using UnityEngine;

public class SCRIPT2 : MonoBehaviour
{
    public MeshFilter m_meshFilter;
    public Mesh m_mesh;
    public GameObject m_objA;
    public GameObject m_objB;
    public GameObject m_objC;
    public GameObject m_objD; //新增 D点

    // 加载脚本实例时调用 Awake
    private void Awake()
    {
        m_meshFilter = GetComponent<MeshFilter>();
        m_mesh = new Mesh();

        Vector3[] vertices = new Vector3[]
        {
            m_objA.transform.position,
            m_objB.transform.position,
            m_objC.transform.position,
            m_objD.transform.position //新增 D点坐标加入到 顶点序列 中
        };

        int[] triangles = new int[] 
        {
            0, 1, 2, //第一个三角面 A->B->C->A
            0, 2, 3  //第二个三角面A->C->D->A
        };
        
        m_mesh.vertices = vertices;
        m_mesh.triangles = triangles;

        m_meshFilter.mesh = m_mesh;
    }
}

三场景:

这就要引入我们的新的概念,法线概念,有了法线才有立体感,法线就是这个面的朝向的方向,而这些信息并不记录在线和面上,我上面说过,模型的信息都以点为基础记录.所以法线的信息也记录在点上.

而这样就会出现矛盾,上面的两个面 四个点,而A点和C点在两个面上,一个点只可以有一个法线呀,所有这里我们要做的是一个面上的点我们要互相独立.也就是说我们做两个面的时候需要使用6个点

这样就可以达到每个点都有自己的法线方向.A点和C两个点就需要有两套分别对应的是两个面,直接上代码,看代码就马上理解

这样我们就因为添加了六个点的法线方向而让这两个面有了棱角,有了立体的感觉

[unity3d][通过代码]制作模型,动态生成模型,通过点画模型_第4张图片

using UnityEngine;

public class SCRIPT3 : MonoBehaviour
{
    public MeshFilter m_meshFilter;
    public Mesh m_mesh;
    public GameObject m_objA;
    public GameObject m_objB;
    public GameObject m_objC;
    public GameObject m_objD;

    // 加载脚本实例时调用 Awake
    private void Awake()
    {
        m_meshFilter = GetComponent<MeshFilter>();
        m_mesh = new Mesh();

        Vector3[] vertices = new Vector3[]
        {
            m_objA.transform.position,
            m_objB.transform.position,
            m_objC.transform.position,
            m_objA.transform.position, //新增   第二个面的A点
            m_objC.transform.position, //新增   第二个面的C点
            m_objD.transform.position
        };

        int[] triangles = new int[] 
        {
            0, 1, 2,
            3, 4, 5  //修改  第二个面的序列发生了变化
        };

        Vector3[] normals = new Vector3[] //新增 法线序列 
        { 
            new Vector3(0,0,-1), //新增 第一个面A点的法线方向
            new Vector3(0,0,-1), //新增 第一个面B点的法线方向
            new Vector3(0,0,-1), //新增 第一个面C点的法线方向
            new Vector3(-1,0,0), //新增 第二个面A点的法线方向
            new Vector3(-1,0,0), //新增 第二个面C点的法线方向
            new Vector3(-1,0,0)  //新增 第二个面D点的法线方向
        };

        m_mesh.vertices = vertices;
        m_mesh.triangles = triangles;
        m_mesh.normals = normals; //新增 法线列表 放入mesh中

        m_meshFilter.mesh = m_mesh;
    }
}

四场景:

当然还有一个概念是UV的概念,UV是一个vector2数组,对于比较复杂的图形我们的UV没法很好的设置,原因是设置UV的对应值非常复杂,所以我在这里就简单的介绍一下,实用性并不高,但说不定要用的,

首先UV为什么是vector2呢,是因为对应的是一张1*1贴图,我们随便引入一个贴图

我们看到,加上贴图后,正常的cube是已经有的了 为什么我们代码生成的模型的没有贴图,因为我们UV点都是空的或者说都是原点,现在我么把这个UV加进去 同样UV点和vertices是一一对应的.

,然后把上面的模型ACD面的不加UV,只把A的这个加UV

这样我们的这个面就加入了贴图,原因就是有了UV

[unity3d][通过代码]制作模型,动态生成模型,通过点画模型_第5张图片

using UnityEngine;

public class SCRIPT4 : MonoBehaviour
{
    public MeshFilter m_meshFilter;
    public Mesh m_mesh;
    public GameObject m_objA;
    public GameObject m_objB;
    public GameObject m_objC;
    public GameObject m_objD;

    // 加载脚本实例时调用 Awake
    private void Awake()
    {
        m_meshFilter = GetComponent<MeshFilter>();
        m_mesh = new Mesh();

        Vector3[] vertices = new Vector3[]
        {
            m_objA.transform.position,
            m_objB.transform.position,
            m_objC.transform.position,
            m_objA.transform.position,
            m_objC.transform.position,
            m_objD.transform.position,
        };

        int[] triangles = new int[]
        {
            0, 1, 2,
            3, 4, 5
        };

        Vector3[] normals = new Vector3[]
        {
            new Vector3(0,0,-1),
            new Vector3(0,0,-1),
            new Vector3(0,0,-1),
            new Vector3(-1,0,0),
            new Vector3(-1,0,0),
            new Vector3(-1,0,0)
        };

        Vector2[] uv = new Vector2[] //新增 纹理列表
        {  
            new Vector2(0,1), //新增 第一个面 A点在贴图的位置
            new Vector2(1,1), //新增 第一个面 B点在贴图的位置
            new Vector2(0,0), //新增 第一个面 C点在贴图的位置
            new Vector2(0,0), //新增 第二个面 A点在贴图的位置
            new Vector2(0,0), //新增 第二个面 C点在贴图的位置
            new Vector2(0,0)  //新增 第二个面 D点在贴图的位置
        };

        m_mesh.vertices = vertices; 
        m_mesh.triangles = triangles;
        m_mesh.normals = normals;
        m_mesh.uv = uv; //新增 把UV列表 放到mesh中

        m_meshFilter.mesh = m_mesh;
    }
}

五场景:

下面我们把ACD面也加入UV,为了让大家方便学习,换一些值,

看了上面的两个例子,这里简单的总结一下,就是UV的点和vertices 也是一一对应的,对应的vector2的值是(0,0)到(1,1)的一张贴图的对应点,然后贴图就可以展到我们通过代码绘制的面上了.

[unity3d][通过代码]制作模型,动态生成模型,通过点画模型_第6张图片

using UnityEngine;

public class SCRIPT5 : MonoBehaviour
{
    public MeshFilter m_meshFilter;
    public Mesh m_mesh;
    public GameObject m_objA;
    public GameObject m_objB;
    public GameObject m_objC;
    public GameObject m_objD;

    // 加载脚本实例时调用 Awake
    private void Awake()
    {
        m_meshFilter = GetComponent<MeshFilter>();
        m_mesh = new Mesh();

        Vector3[] vertices = new Vector3[]
        {
            m_objA.transform.position,
            m_objB.transform.position,
            m_objC.transform.position,
            m_objA.transform.position,
            m_objC.transform.position,
            m_objD.transform.position,
        };

        int[] triangles = new int[] 
        {
            0, 1, 2,
            3, 4, 5
        };

        Vector3[] normals = new Vector3[] 
        {
            new Vector3(0,0,-1),
            new Vector3(0,0,-1),
            new Vector3(0,0,-1),
            new Vector3(-1,0,0),
            new Vector3(-1,0,0),
            new Vector3(-1,0,0)
        };

        Vector2[] uv = new Vector2[] 
        {
            new Vector2(0,1),
            new Vector2(1,1),
            new Vector2(0,0),
            new Vector2(0.75f,0.75f),  //修改 第二个面 A点在贴图的位置
            new Vector2(0.75f,0.25f),  //修改 第二个面 C点在贴图的位置
            new Vector2(0.25f,0.75f)   //修改 第二个面 D点在贴图的位置
        };

        m_mesh.vertices = vertices;
        m_mesh.triangles = triangles;
        m_mesh.normals = normals;
        m_mesh.uv = uv;

        m_meshFilter.mesh = m_mesh;
    }
}

六场景:

最后我们制作一个圆柱体,不需要贴图的,但是要有法线的,为了让大家理解制作的过程,我会在代码中加入延时和演示的功能,

这个例子我只演示一遍,我不给大家做代码的分析,里面是没有难点的,至少我认为对于正常的高中生水平来说应该也是可以理解的,只要多看几次代码就可以理解透了.

[unity3d][通过代码]制作模型,动态生成模型,通过点画模型_第7张图片

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

public class SCRIPT6 : MonoBehaviour
{
    public GameObject m_objLocation;
    public MeshFilter m_meshFilter;
    public Mesh m_mesh;

    [Header("内圆半径")]
    public float m_fInnerRadius = 1.0f;
    [Header("外圆半径")]
    public float m_fOuterRadius = 1.5f;
    [Header("圆柱体半高")]
    public float m_fHalfHeight = 1.0f;

    [Header("内圆")]
    public List<Vector3> m_list_v3InnerRadius;
    [Header("外圆")]
    public List<Vector3> m_list_v3OuterRadius;

    public List<Vector3> m_list_v3Vertices;
    public List<int> m_list_nTriangles;
    public Dictionary<int, Vector3> m_dic_v3Normal = new Dictionary<int, Vector3>();
    public List<Vector3> m_list_v3Normal;



    // 加载脚本实例时调用 Awake
    private void Awake()
    {
        m_meshFilter = GetComponent<MeshFilter>();
        m_mesh = new Mesh();
    }

    // 仅在首次调用 Update 方法之前调用 Start
    private IEnumerator Start()
    {
        int v_nBegin = 0;
        int v_nA;
        int v_nB;
        int v_nC;
        int v_nD;

        int v_nPolygon = 12;
        float v_fAngle = 360f / v_nPolygon;//圆形的一个边的所占的角度
        for (int i = 0; i < v_nPolygon; i++)
        {
            //内圆
            m_list_v3InnerRadius.Add(new Vector3(Mathf.Cos(v_fAngle * (i + 1) * Mathf.PI / 180) * m_fInnerRadius, 0, Mathf.Sin(v_fAngle * (i + 1) * Mathf.PI / 180) * m_fInnerRadius));

            //外圆
            m_list_v3OuterRadius.Add(new Vector3(Mathf.Cos(v_fAngle * (i + 1) * Mathf.PI / 180) * m_fOuterRadius, 0, Mathf.Sin(v_fAngle * (i + 1) * Mathf.PI / 180) * m_fOuterRadius));
        }

        //设置上半部分的内圆和外圆
        v_nBegin = m_list_v3Vertices.Count;
        for (int i = 0; i < v_nPolygon; i++)
        {
            m_list_v3Vertices.Add(m_list_v3InnerRadius[i] + new Vector3(0, m_fHalfHeight, 0));
            GameObject v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);
        }

        for (int i = v_nBegin; i < v_nBegin + v_nPolygon; i++)
        {
            m_list_v3Vertices.Add(m_list_v3OuterRadius[i] + new Vector3(0, m_fHalfHeight, 0));
            GameObject v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);
        }

        for (int i = v_nBegin; i < v_nBegin + v_nPolygon; i++)
        {
            v_nA = i;
            v_nB = i == v_nPolygon - 1 ? 0 : i + 1;
            v_nC = i + v_nPolygon;
            v_nD = i == v_nPolygon - 1 ? v_nPolygon : i + 1 + v_nPolygon;
            DrawModel(ref m_list_nTriangles, ref m_dic_v3Normal, m_list_v3Vertices, v_nA, v_nB, v_nC, v_nD);
            Draw();
            yield return new WaitForSeconds(1.0f);
        }


        //设置下半部分的内圆和外圆
        v_nBegin = m_list_v3Vertices.Count;
        for (int i = 0; i < v_nPolygon; i++)
        {
            m_list_v3Vertices.Add(m_list_v3InnerRadius[i] - new Vector3(0, m_fHalfHeight, 0));
            GameObject v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);
        }
        for (int i = 0; i < v_nPolygon; i++)
        {
            m_list_v3Vertices.Add(m_list_v3OuterRadius[i] - new Vector3(0, m_fHalfHeight, 0));
            GameObject v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);
        }

        for (int i = v_nBegin; i < v_nBegin + v_nPolygon; i++)
        {
            v_nA = i;
            v_nB = i + v_nPolygon;
            v_nC = i == v_nBegin + v_nPolygon - 1 ? v_nBegin : i + 1;
            v_nD = i == v_nBegin + v_nPolygon - 1 ? v_nBegin + v_nPolygon : i + 1 + v_nPolygon;
            DrawModel(ref m_list_nTriangles, ref m_dic_v3Normal, m_list_v3Vertices, v_nA, v_nB, v_nC, v_nD);
            Draw();
            yield return new WaitForSeconds(1.0f);
        }


        //设置内圆
        v_nBegin = m_list_v3Vertices.Count;
        for (int i = 0; i < v_nPolygon; i++)
        {
            m_list_v3Vertices.Add(m_list_v3InnerRadius[i] + new Vector3(0, m_fHalfHeight, 0));
            GameObject v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);

            m_list_v3Vertices.Add(m_list_v3InnerRadius[i] - new Vector3(0, m_fHalfHeight, 0));
            v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);

            m_list_v3Vertices.Add(m_list_v3InnerRadius[i] + new Vector3(0, m_fHalfHeight, 0));
            v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);

            m_list_v3Vertices.Add(m_list_v3InnerRadius[i] - new Vector3(0, m_fHalfHeight, 0));
            v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);
        }

        for (int i = v_nBegin; i < v_nBegin + v_nPolygon * 4; i += 4)
        {
            v_nA = i + 2;
            v_nB = i + 3;
            v_nC = i == v_nBegin + v_nPolygon * 4 - 4 ? v_nBegin : i + 4;
            v_nD = i == v_nBegin + v_nPolygon * 4 - 4 ? v_nBegin + 1 : i + 5;
            DrawModel(ref m_list_nTriangles, ref m_dic_v3Normal, m_list_v3Vertices, v_nA, v_nB, v_nC, v_nD);
            Draw();
            yield return new WaitForSeconds(1.0f);
        }


        //设置外圆
        v_nBegin = m_list_v3Vertices.Count;
        for (int i = 0; i < v_nPolygon; i++)
        {
            m_list_v3Vertices.Add(m_list_v3OuterRadius[i] + new Vector3(0, m_fHalfHeight, 0));
            GameObject v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);

            m_list_v3Vertices.Add(m_list_v3OuterRadius[i] - new Vector3(0, m_fHalfHeight, 0));
            v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);

            m_list_v3Vertices.Add(m_list_v3OuterRadius[i] + new Vector3(0, m_fHalfHeight, 0));
            v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);

            m_list_v3Vertices.Add(m_list_v3OuterRadius[i] - new Vector3(0, m_fHalfHeight, 0));
            v_obj = Instantiate(m_objLocation, gameObject.transform);
            v_obj.transform.position = m_list_v3Vertices[m_list_v3Vertices.Count - 1];
            yield return new WaitForSeconds(1.0f);
        }

        for (int i = v_nBegin; i < v_nBegin + v_nPolygon * 4; i += 4)
        {
            v_nA = i + 2;
            v_nB = i == v_nBegin + v_nPolygon * 4 - 4 ? v_nBegin : i + 4;
            v_nC = i + 3;
            v_nD = i == v_nBegin + v_nPolygon * 4 - 4 ? v_nBegin + 1 : i + 5;
            DrawModel(ref m_list_nTriangles, ref m_dic_v3Normal, m_list_v3Vertices, v_nA, v_nB, v_nC, v_nD);
            Draw();
            yield return new WaitForSeconds(1.0f);
        }

        Draw();
        yield return null;
    }

    private void Draw()
    {
        //模型的绘制
        m_mesh = new Mesh
        {
            vertices = m_list_v3Vertices.ToArray()//把点放到mesh中
        };

        m_list_v3Normal.Clear();
        for (int i = 0; i < m_list_v3Vertices.Count; i++)
        {
            if (m_dic_v3Normal.ContainsKey(i))
            {
                m_list_v3Normal.Add(m_dic_v3Normal[i]);
            }
            else
            {
                m_list_v3Normal.Add(Vector3.zero);
            }
        }

        m_mesh.triangles = m_list_nTriangles.ToArray();//画模型,每三个为一组,为一个面
        m_mesh.normals = m_list_v3Normal.ToArray();//法线   法线的向量和 vertices 一一对应

        m_meshFilter.mesh = m_mesh;
    }




    /// 
    /// 得到三角形ABC 某点的 右手定则的  法线方向
    /// 
    ///  A点的坐标 
    ///  B点的坐标 
    ///  C点的坐标 
    ///  0:A点  1:B点  2:C点 
    /// 
    private Vector3 Faxian(Vector3 a, Vector3 b, Vector3 c, int index = 0)
    {
        a *= 100;
        b *= 100;
        c *= 100;

        Vector3 left = b - a;
        Vector3 right = c - a;
        if (index != 0 && index == 1)
        {
            left = c - b;
            right = a - b;
        }

        if (index != 0 && index == 2)
        {
            left = a - c;
            right = b - c;
        }
        return Vector3.Cross(left, right);
    }

    /// 
    /// 添加法线
    /// 
    ///  法线的字典  为什么用字典的主要就是为了排除重复的点 方便找到某些点没有给出来 
    ///  图形的点的list  
    ///  要算法线的一个三角面的三个点A 
    ///  要算法线的一个三角面的三个点B 
    ///  要算法线的一个三角面的三个点C 
    private void AddCorss(ref Dictionary<int, Vector3> _dic_v3Normal, List<Vector3> _list_v3Vertices, int a, int b, int c)
    {
        Vector3 v_v2FaA = Faxian(_list_v3Vertices[a], _list_v3Vertices[b], _list_v3Vertices[c], 0);
        if (_dic_v3Normal.ContainsKey(a))
        {
            if (v_v2FaA != Vector3.zero)
            {
                _dic_v3Normal[a] = v_v2FaA;
            }
        }
        else
        {
            _dic_v3Normal.Add(a, v_v2FaA);
        }

        Vector3 v_v2FaB = Faxian(_list_v3Vertices[a], _list_v3Vertices[b], _list_v3Vertices[c], 1);
        if (_dic_v3Normal.ContainsKey(b))
        {
            if (v_v2FaB != Vector3.zero)
            {
                _dic_v3Normal[b] = v_v2FaB;
            }
        }
        else
        {
            _dic_v3Normal.Add(b, v_v2FaB);
        }

        Vector3 v_v2FaC = Faxian(_list_v3Vertices[a], _list_v3Vertices[b], _list_v3Vertices[c], 2);
        if (_dic_v3Normal.ContainsKey(c))
        {
            if (v_v2FaC != Vector3.zero)
            {
                _dic_v3Normal[c] = v_v2FaC;
            }
        }
        else
        {
            _dic_v3Normal.Add(c, v_v2FaC);
        }
    }

    /// 
    /// 画一个四角面 面的方向也是右手定则
    /// 
    ///  法线的返回集合 面的一个list 三个索引为一个面的 右手定则 
    ///  法线的字典集合 
    ///  模型上所有的点的面 
    ///  两个三角面的四个顶点A 
    ///  两个三角面的四个顶点B 
    ///  两个三角面的四个顶点C 
    ///  两个三角面的四个顶点D 
    protected void DrawModel(ref List<int> _list_nTriangles, ref Dictionary<int, Vector3> _dic_v3Normal, List<Vector3> _list_v3Vertices, int a, int b, int c, int d)
    {
        _list_nTriangles.Add(a);
        _list_nTriangles.Add(b);
        _list_nTriangles.Add(c);
        AddCorss(ref _dic_v3Normal, _list_v3Vertices, a, b, c);

        _list_nTriangles.Add(c);
        _list_nTriangles.Add(b);
        _list_nTriangles.Add(d);
        AddCorss(ref _dic_v3Normal, _list_v3Vertices, c, b, d);
    }
}

结束

先关注我 然后给我点赞 你今年就会
在这里插入图片描述 序列-01

git地址:https://github.com/js305492881/MakeAModelFrom-code

csdn博客地址:https://blog.csdn.net/JianShengShuaiest

bilibili地址:[https://space.bilibili.com/15766978](

你可能感兴趣的:(unity3d基础-功能代码,unity,unity3d,3d,游戏开发)