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

简介

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

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

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

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

下面对基础知识进行讲解

首先引入的是三个类型

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

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

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

在这里插入图片描述

上面的基础讲解可以看出主要的信息都在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<int, Vector3> _dic_v3Normal, List _list_v3Vertices, int a, int b, int c)
protected void DrawModel(ref List _list_nTriangles, ref Dictionary<int, Vector3> _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视图中是正好相反的,所以看不到面

以上我已经介绍了简单的制作一个面的概念,下面我们来扩展成体的概念
在这里插入图片描述

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面垂直,现在我们通过代码来实现这个制作

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

在这里插入图片描述

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两个点就需要有两套分别对应的是两个面,直接上代码,看代码就马上理解

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

在这里插入图片描述

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

在这里插入图片描述

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)的一张贴图的对应点,然后贴图就可以展到我们通过代码绘制的面上了.

在这里插入图片描述

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;
    }
}

六场景:

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

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

在这里插入图片描述

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;
    }




    /// <summary>
    /// 得到三角形ABC 某点的 右手定则的  法线方向
    /// </summary>
    /// <param name="a"> A点的坐标 </param>
    /// <param name="b"> B点的坐标 </param>
    /// <param name="c"> C点的坐标 </param>
    /// <param name="index"> 0:A点  1:B点  2:C点 </param>
    /// <returns></returns>
    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);
    }

    /// <summary>
    /// 添加法线
    /// </summary>
    /// <param name="_dic_v3Normal"> 法线的字典  为什么用字典的主要就是为了排除重复的点 方便找到某些点没有给出来 </param>
    /// <param name="_list_v3Vertices"> 图形的点的list  </param>
    /// <param name="a"> 要算法线的一个三角面的三个点A </param>
    /// <param name="b"> 要算法线的一个三角面的三个点B </param>
    /// <param name="c"> 要算法线的一个三角面的三个点C </param>
    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);
        }
    }

    /// <summary>
    /// 画一个四角面 面的方向也是右手定则
    /// </summary>
    /// <param name="_list_nPanel"> 法线的返回集合 面的一个list 三个索引为一个面的 右手定则 </param>
    /// <param name="_dic_v3normal"> 法线的字典集合 </param>
    /// <param name="_list_v3Vertices"> 模型上所有的点的面 </param>
    /// <param name="a"> 两个三角面的四个顶点A </param>
    /// <param name="b"> 两个三角面的四个顶点B </param>
    /// <param name="c"> 两个三角面的四个顶点C </param>
    /// <param name="d"> 两个三角面的四个顶点D </param>
    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);
    }
}

结束

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

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

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

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

  • 27
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
is CDLXX 471 is CDLXXI 472 is CDLXXII 473 is CDLXXIII 474 is CDLXXIV 475 is CDLXXV 476 is CDLXXVI 477 is CDLXXVII 478 is CDLXXVIII 479 is CDLXXIX 480 is CDLXXX 481 is CDLXXXI 482 is CDL在Unity中,可以通过代码永久替换模型材质。下面是一个简单的示例代码: ```cXXXII 483 is CDLXXXIII 484 is CDLXXXIV 485 is CDLXXXV 486 is CDLXXXsharp using UnityEngine; using System.Collections; public class MaterialChanger : MonoBehaviour { // 新的材质 public Material newVI 487 is CDLXXXVII 488 is CDLXXXVIII 489 is CDLXXXIX 490 is CDXC 491 is CDXCI 492 is CDXCII 493 is CDXCIII 494 is CDXCIV 495 is CDXMaterial; void Start () { // 获取所有Renderer组件 Renderer[] renderers = GetComponentsInChildren<Renderer>(); // 遍CV 496 is CDXCVI 497 is CDXCVII 498 is CDXCVIII 499 is CDXCIX 500 is D 501 is DI 502 is DII 503 is DIII 504 is DIV 505 is DV 506 is D历每一个Renderer foreach(Renderer renderer in renderers) { // 获取原始材质 Material[] materials = rendererVI 507 is DVII 508 is DVIII 509 is DIX 510 is DX 511 is DXI 512 is DXII 513 is DXIII 514 is DXIV 515 is DXV 516 is DXVI 517 is DXVII 518.materials; // 遍历每一个材质 for (int i = 0; i < materials.Length; i++) { is DXVIII 519 is DXIX 520 is DXX 521 is DXXI 522 is DXXII 523 is DXXIII 524 is DXXIV 525 is DXXV 526 is DXXVI 527 is DXXVII // 替换为新的材质 materials[i] = newMaterial; } // 赋值回Renderer 528 is DXXVIII 529 is DXXIX 530 is DXXX 531 is DXXXI 532 is DXXXII renderer.materials = materials; } } } ``` 上面的代码添加到场景中的一个GameObject上,并将新材质赋值给 `newMaterial` 变量。然后运行游戏即可看到模型的材质被永久替换了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谢斯

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值