Unity网格编程,写出自己想要的形状——(单面墙多门窗)

最近在学习mesh, mesh的顶点,三角面,UV的一些属性

刚开始一直搞不懂三角面和顶点的关系,后来这篇文章给了很大的启发

有几点需要注意:

对于顶点 即 mesh.vertices  是由一个Vector3[]数组 里边记录了所有的顶点位置,注意 这里边所有的Vector3在数组里的index就是下标,这里边每一个下标都是用来构成三角形的 如下图 

四个顶点分别为

V0(1, 1, 0),
V1(-1, 1, 0),
V2(1, -1, 0),
V3(-1, -1, 0)

注意:三角形的顶点顺序必须是顺时针,顺时针表示正面,逆时针表示背面,而unity3d在渲染时默认只渲染正面,背面是看不见的。

那么该三角形可以表示为:

mesh.triangles = new int[2 * 3]{0, 3, 1,   0, 2, 3};

这里是一面墙抠一个洞的情况

(暂时略过)

这里是一面墙抠2个以上的洞的情况

这是一种三角形拼接方法,单个图太大 我截图放上来 能看清楚就行 

这种方式的弊端就是如果两个洞的高低不同 其三角形的排列是不同的

所以我决定使用下边这种方式

这种方式排列顶点,万变不离其宗 嘿嘿~

废话不多说  上代码

using UnityEngine;
public class MyMesh : MonoBehaviour {
    public Material ma;
    public Vector2[] uvs;
    void Start ()
    {
        测试第二次不重复顶点();
    }
    public float 墙体高度 = 4;
    public float 墙体长度 = 10;
    /// <summary>
    /// 门窗的位置和类型x为左侧位置 y为右侧位置  z为底部位置 w为顶部位置
    /// </summary>
    public Vector4[] 门窗;
    public int factor;//UV缩放调整
    /// <summary>
    /// 根据新增门窗计算三角面和顶点数量
    /// </summary>
    void GetLength(out int san, out int ding)
    {
        san = 4; ding = 6;
        if (门窗.Length == 0) return;
        for (int i = 0; i < 门窗.Length; i++)
        {
            san += 8;
            ding += 18;
        }
    }
    void 测试第二次不重复顶点()
    {
        int nowSan = 0, nowDing = 0;//当前计算到的三角面和顶点
        int san, ding;//三角面顶点总数
        GetLength(out san, out ding);//计算下三角形数和顶点数
        Mesh mesh = new Mesh();
        MeshFilter filter = gameObject.AddComponent<MeshFilter>();
        Vector3[] vertices  = new Vector3[san];
        int[] triangle = new int[ding];
        Vector3 pos = this.transform.position;
        //计算顶点和顶点排序
        if (门窗.Length == 0)//没传门窗信息 则生成一个墙体
        {
            vertices[nowSan++] = new Vector3(pos.x, pos.y + 墙体高度, pos.z);
            vertices[nowSan++] = pos;
            vertices[nowSan++] = new Vector3(pos.x + 墙体长度, pos.y, pos.z);
            vertices[nowSan++] = new Vector3(pos.x + 墙体长度, pos.y + 墙体高度, pos.z);
            triangle = new int[2 * 3] { 3, 1,0, 1, 3, 2 };
        }
        else
        {
            //门窗数量大于1 先生成左侧两个
            vertices[nowSan] = new Vector3(pos.x, pos.y + 墙体高度, pos.z);//0
            vertices[nowSan+1] = pos;//1
            vertices[nowSan+2] = new Vector3(pos.x + 门窗[0].x, pos.y, pos.z);//2
            vertices[nowSan+3] = new Vector3(pos.x + 门窗[0].x, pos.y + 墙体高度, pos.z);//3
            triangle[nowDing++] = 3; triangle[nowDing++] = 2; triangle[nowDing++] = 1;
            triangle[nowDing++] = 1; triangle[nowDing++] = 0; triangle[nowDing++] = 3;
            nowSan = 3;
            for (int i = 0; i < 门窗.Length; i++)//再生成剩下的   循环赋值三角形和顶点信息
            {
                vertices[nowSan + 1] = new Vector3(pos.x + 门窗[i].y, pos.y, pos.z);                             //4      12
                vertices[nowSan + 2] = new Vector3(pos.x + 门窗[i].y, pos.y + 门窗[i].z, pos.z);                 //5      13
                vertices[nowSan + 3] = new Vector3(pos.x + 门窗[i].x, pos.y + 门窗[i].z, pos.z);                 //6      14
                vertices[nowSan + 4] = new Vector3(pos.x + 门窗[i].x, pos.y + 门窗[i].w, pos.z);                 //7      15
                vertices[nowSan + 5] = new Vector3(pos.x + 门窗[i].y, pos.y + 门窗[i].w, pos.z);                  //8      16
                vertices[nowSan + 6] = new Vector3(pos.x + 门窗[i].y, pos.y + 墙体高度, pos.z);                   //9     17
                vertices[nowSan + 7] = new Vector3(pos.x + ((i == 门窗.Length - 1) ? 墙体长度: 门窗[i+1].x)  , pos.y+ 墙体高度, pos.z);   //10     18
                vertices[nowSan + 8] = new Vector3(pos.x + ((i == 门窗.Length - 1) ? 墙体长度: 门窗[i+1].x)  , pos.y , pos.z);           //11     19
                //顶点顺序排序 
                triangle[nowDing++] = nowSan + (i == 0 ? -1 : 0); triangle[nowDing++] = nowSan + 2; triangle[nowDing++] = nowSan + 1;
                triangle[nowDing++] = nowSan + (i == 0 ? -1 : 0); triangle[nowDing++] = nowSan + 3; triangle[nowDing++] = nowSan + 2;
                triangle[nowDing++] = nowSan + 4; triangle[nowDing++] = nowSan + 6; triangle[nowDing++] = nowSan + 5;
                triangle[nowDing++] = nowSan + 4; triangle[nowDing++] = nowSan + (i == 0 ? 0 : -1); triangle[nowDing++] = nowSan + 6;
                triangle[nowDing++] = nowSan + 1; triangle[nowDing++] = nowSan + 6; triangle[nowDing++] = nowSan + 7;
                triangle[nowDing++] = nowSan + 1; triangle[nowDing++] = nowSan + 7; triangle[nowDing++] = nowSan + 8;
                nowSan += 8;
            }
        }
        //UV计算
        int iuv = 0, idx = 0;
        Vector3[] uvv = new Vector3[san];
        uvs = new Vector2[san];
        uvv[0] = Vector3.zero;
        for (int u = 1; u < san; u++)
            uvv[u] = vertices[idx] - vertices[idx + u];
        idx += 8;
        uvs[iuv++] = Vector2.zero;
        for (int u = 1; u < san; u++)
            uvs[iuv++] = new Vector2(uvv[u].x, -uvv[u].y) * factor;
        mesh.vertices = vertices;
        mesh.triangles = triangle;
        mesh.uv = uvs;
        mesh.MarkDynamic();
        mesh.RecalculateBounds();
        mesh.RecalculateNormals();
        MeshRenderer render = this.gameObject.AddComponent<MeshRenderer>();
        render.material = ma;
        filter.mesh = mesh;
    }
}

 

效果图如下

可以看到 生成的三角面和定点顺序和计划生成的吻合

 

 

...无奈 竟然有人复制了我的博客....这里

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值