美文网首页
网格切割(MeshCut)

网格切割(MeshCut)

作者: Qkuang | 来源:发表于2020-07-20 17:30 被阅读0次

    Unity学习一篇

    <details>
    <summary>通用快捷引导</summary>

    主页目录
    文集目录
    </details>

    目录

    Mesh 学习

    入门级代码

    相关代码已经同步至Git。现在粘贴有意的代码块:

    public class MeshExample : MonoBehaviour
    {
        // 必要的 属性:顶点 、三角形索引
        public Vector3[] newVertices;
        public Vector2[] newUV;
        /// <summary>
        /// 表示要 存在的三角面。其值为 顶点的索引。 从0 开始 每三个索引 表示一个三角面。 三角面的法线
        /// 是 三个点 以 左手手坐标系,叉乘结果方向为准。以第一个点为两个向量的起点
        /// </summary>
        public int[] newTriangles;
        public Color[] colors;
        void Start() {
            Mesh mesh = new Mesh();
            GetComponent<MeshFilter>().mesh = mesh;
            mesh.vertices = newVertices;
            mesh.uv = newUV;
            mesh.triangles = newTriangles;
            mesh.colors = colors;
        }
    }
    
    /// <summary>
    ///  可以通过脚本修改法线反向。
    /// </summary>
    public class MeshExample3 : MonoBehaviour
    {
        // Start is called before the first frame update
        
        private Mesh meshV;
        void Start()
        {
            meshV = GetComponent<MeshFilter>().mesh;
            NormalBack(meshV);
        }
        private void NormalBack(Mesh IN){
            Vector3[] vertices = IN.vertices;
            Vector3[] normals = IN.normals;
            int[] Triangles = IN.triangles;
            int buffer;
            for(int i=0;i<Triangles.Length;i+=3){
                buffer = Triangles[i+1];
                Triangles[i+1]=Triangles[i+2];
                Triangles[i+2]=buffer;
            }
                // 这里数组肯定是引用类型,但是其中通过 某种手段,看起来像值类型。因此 存在一个Clear().
            for(int i=0;i<vertices.Length;i++){
                vertices[i] *=1.2f;
            }
            IN.triangles = Triangles;
            IN.vertices = vertices;
        }
    }
    

    概念

    BlendShape 属性: 混合形状。用来做面部表情用。

    切割案例分析(核心)

    1. 两向量,计算垂直向量。


      image
    2. 计算旋转

    如图所示: 好久没动手,差点忘了,好险!


    image
    1. 切割面思路。(案例中)
    image

    入射线碰撞,+ 世界 Up 向量 确定一个平面。在该平面内 ,求得 入射线 得垂向量。 —— 利用 上面得公式即可。
    再点乘,求得切割法向量。

    1. 判断 三角面 点 是否被切割 图解:
    image

    求得黑色 “差向量”和“法向量” 点乘,通过 点乘值“0” 判断左右。

    换种理解方式:以入射线、切割法线、垂线,建立一个坐标系。求得 顶点 在该坐标系的相对位置。…… 没有进行 线性变换 的坐标系转换,这样说也不妥。 反正,要心中右这个坐标轴。不然 千辛万苦求出来干嘛。

    1. 拷贝顶点。

    只要切割 必定舍弃原来得 mesh。存在两个临时 mesh。

    因此情况一:三角面 完全再边。该三角面不需要被切割。 需要将三角面拷贝到 对应得临时 mesh 属性中。

    注意:(三角面不需要切割:) 需要拷贝得 包括:顶点、三角索引、法线。 正常情况,只要==按顺序==将 旧三角顶点索引,添加到临时 三角索引中即可。 顶点、法线也是如此。但是 顶点、法线需要判断是否已经存在。————错误!

    零时顶点集合、零时三角面集合。 临时三角面集合需要 的是 临时顶点 集合 的索引。因此,中间需要一个过度。

    代码: 关闭列表—— 字典是 关键

    //拷贝顶点
    /// <summary>
    /// 三角面、顶点、法线拷贝
    /// </summary>
    /// <param name="index1">旧顶点列表索引1</param>
    /// <param name="index2">旧顶点列表索引2</param>
    /// <param name="index3">旧顶点列表索引3</param>
    /// <param name="tempVert">临时(新)顶点列表</param>
    /// <param name="tempNormal">新法线列表</param>
    /// <param name="triangles">新三角列表</param>
    /// <param name="pointIndex">关闭列表</param>
        static void CopyVert(int index1,int index2,int index3,ref List<Vector3> tempVert,ref List<Vector3> tempNormal,ref List<int> triangles,ref Dictionary<int,int> pointIndex){
    
                //是顶点索引否存在 : 字典作为 一个 旧顶点 索引 的关闭列表。(键值对:旧顶点列表索引 —— 新顶点列表索引)
                //用于判断点是否拷贝过
            if (!pointIndex.ContainsKey (index1)) {
                tempVert.Add (targetMesh.vertices [index1]);    //不存在索引时,插入对应索引得值。——1
                tempNormal.Add (targetMesh.normals [index1]);
                pointIndex.Add (index1,tempVert.Count-1);       //这里是关键
            }
            if (!pointIndex.ContainsKey (index2)) {
                tempVert.Add (targetMesh.vertices [index2]);    //不存在索引时,插入对应索引得值。——2
                tempNormal.Add (targetMesh.normals [index2]);
    
                pointIndex.Add (index2,tempVert.Count-1);
    
            }
            if (!pointIndex.ContainsKey (index3)) {
                tempVert.Add (targetMesh.vertices [index3]);    //不存在索引时,插入对应索引得值。——3
                tempNormal.Add (targetMesh.normals [index3]);
    
                pointIndex.Add (index3,tempVert.Count-1);
    
            }
    
        
            triangles.Add (pointIndex[index1]);                 //通过 关闭列表,找到新顶点列表索引。
            triangles.Add (pointIndex[index2]);
            triangles.Add (pointIndex[index3]);
    
        }
    
    1. 切割算法核心——求切割点

    如图


    image

    ==关键点:没有,求不出来==。

    • 用于切割的 坐标轴(两两垂直)—— 这是基础条件。以后 本能这样做吧,虽然发明不了算法,但看得懂,也是能耐了。

    • 像似三角形。

    • 其他情况:我能力有限,推不出来。不过实验是成功的,所以,公式 适用于 三维空间下的 其他情况 三角面的 运算。

    • 注意求倍数时,除数为零!

    1. 平面几何和空间几何。
    • 我平面几何还行,空间几何问题有点大。

    • 假设:在平面几何中 推导的公式(完全由向量构成),那么它可以应用到空间几何。—— 祈祷这个是真理吧。

    • 两条 垂直异面直线 在同一平面内的投影 可能不垂直。 两条垂直共面直线在同一平面内的投影,垂直。—— 不知道如何证明,也不知对错。


      image
    1. 补全切面
      image

    当我们算出所有切面上的切面点时。可以求出一个中心点,然后每两个切面点和 中心点构成一个三角面。——这里 保证 (0、1)(2、3)…… 这样的顺序,才不会出现交叉面

    还需要求中心点的法线:直接就是 切面 切割法线的方向转化坐标系即可。

    1. 关于法线

    这里区分一下:三角面法线、顶点法线。 三角面法线(自己命名)
    三角面的法线:决定三角面是哪一个面被渲染可见。 只通过三角面的顶点顺序+叉乘+左手坐标系决定。
    顶点法线:决定光照渲染的值,不决定是否被渲染可见。通过直接设置获得。

    image

    如图,三角面法线向上,所以三角面 俯视可见。 其中一个顶点法线向下,因此光照计算结果为黑。

    1. 计算切面三角顺序——三角法线
    image

    关键数值: 切面切割法线、切面三角法线(随意)、切割法线和 三角法线的点积值。

    随便两个向量,先叉乘 ,再和一个从物体中心发设的向量计算。 (不论是案例,还是其他算法,切割模型的 算法都有局限性,都不能随意切割 任何模型。)

    1. 切割三角面确定三角的组合

    案例是通过 非常多的判断来确定 哪种切割点组合成为新的三角面。

    GL 使用

    GL 类是图形API类。 Gizmo是在 开发阶段使用辅助图形,那么GL 就是 游戏实际运行时绘制 使用。

    入门代码

    public class GLTest : MonoBehaviour
    {
        // Start is called before the first frame update
        public Material mat;
        public Vector3[] vectList;
        // // 相机的图片效果渲染 函数。用于后处理—— 需要挂在相机上才能调用
        // private void OnRenderImage(RenderTexture src, RenderTexture dest) {
            
        // }
    
        //相机的 渲染函数,绘制一些图形渲染(有深度测试)—— 需要挂在相机上才能调用
        private void OnPostRender() {
            if (!mat) {
                Debug.LogError("Please Assign a material on the inspector");
                return;
            }
            GL.PushMatrix(); //将 相机使用的 矩阵保存下来
            //GL.LoadOrtho();   //加载其他种类相机矩阵:正交投影矩阵、透视投影矩阵(需要自己构建矩阵值)……其他种类
            // Ortho 矩阵,是归一化矩阵正交矩阵。右上角:(1,1).
           //不写矩阵加载,使用 和相机当前设置的 “正交、透视” 有关。
            mat.SetPass(0);     // 设置本次GL 绘制的passs 通道。由于不能设置法线,因此注意使用 非光照 Shader 材质。
            //GL.Color(Color.yellow);     // 这里设置GL 颜色,但是没看到作用。
            GL.Begin(GL.TRIANGLES);     //GL 绘制的图形:三角、四边、线段……
    
            // 设置顶点。 注意:三角面 的三角法线 遵循左手坐标系。
            foreach (var item in vectList)
            {
                GL.Vertex(item);
            }
            GL.End();                  //GL 图形绘制 结束,可以进行下个GL 图形绘制。
            GL.PopMatrix();//将 相机使用的 矩阵 从保存中恢复
    
        }
        
    }
    
    

    相关文章

      网友评论

          本文标题:网格切割(MeshCut)

          本文链接:https://www.haomeiwen.com/subject/aipykktx.html