网格切割(MeshCut)

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();//将 相机使用的 矩阵 从保存中恢复

    }
    
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351