Unity网格——创建立方体及变形动画

前言

只记录重点,源码放最后


利用mesh类生成网格图形。参考链接1:Unity网格编程-视频版 参考链接2:Unity网格编程-英文版

1.计算顶点序列

  • 首先定义x、y、z轴向的边由几个片段组成,定制为xGridCount, yGridCount, zGridCount(4)
  • 可计算出顶点数量(4个顶点+12边上数量/不包含顶点+6个面上顶点数量),mesh的顶点数组长度等于顶点数
  • 顶点序列计算:计算xz面上点嵌套进y递增的for中,然后再计算顶面和地面的中间点xz面,y分别为0、yGridCount-1
  • 代码:
_vertices = new Vector3[GetVerticeCount()];
        int index = 0;
        //前后左右四个面的点
        for (int y = 0; y < yGridCount + 1; y++)
        {
            for (int x = 0; x < xGridCount + 1; x++, index++)
            {
                _vertices[index] = new Vector3(x, y, 0);

            }
            for (int z = 1; z < zGridCount + 1; z++, index++)
            {
                _vertices[index] = new Vector3(xGridCount, y, z);
            }
            for (int x = xGridCount - 1; x >= 0; x--, index++)
            {
                _vertices[index] = new Vector3(x, y, zGridCount);
            }
            for (int z = zGridCount - 1; z > 0; z--, index++)
            {
                _vertices[index] = new Vector3(0, y, z);
            }
        }
        //顶面中间面的点
        for (int z = 1; z < zGridCount; z++)
        {
            for (int x = 1; x < xGridCount; x++, index++)
            {
                _vertices[index] = new Vector3(x, yGridCount, z);
            }
        }
        //底面中间面的点
        for (int z = 1; z < zGridCount; z++)
        {
            for (int x = 1; x < xGridCount; x++, index++)
            {
                _vertices[index] = new Vector3(x, 0, z);
            }
        }

2.计算三角面顶点序列

  • 概述:两层顶点组成一层平面(以y轴分层),如图四周面V10=V00+1,V01=V00+Ground(Ground为xz面一圈的定点数量)

  • 在这里插入图片描述
    如图顶面或者底面V10=V00+1,V01=V00+Ground-1(Ground为xz面一圈的定点数量)
    在这里插入图片描述

  • 四周面

  • 代码:

- for (int y = 0; y < yGridCount; y++)
        {
            for (int i = 0; i < circleVerticeCount; i++,t+=6,v++)
            {
                SetQuad(t,v,v+1,v+circleVerticeCount,v+circleVerticeCount+1,circleVerticeCount);
            }
        }

在四周面一层计算到最后一个面是需要做一些限定,按照以上代码第一层最后一个面三角面序列为(15,16,31,32)但是实际需要(15,0,31,16)才可以填充最后一个面。以下两个函数,第一个生成四周面调用,顶面和地面用第二个。

 private void SetQuad(int i, int v00, int v10, int v01, int v11, int circleVerticeCount)
    {
        //v00/circleVerticeCount算出哪一行,*circleVerticeCount算出每一行第一个索引
        //+ v10%circleVerticeCount 算出属于在一行中的第几个
        v10 = (v00 / circleVerticeCount) * circleVerticeCount + v10 % circleVerticeCount;
        v11 = (v01 / circleVerticeCount) * circleVerticeCount + v11 % circleVerticeCount;
        SetQuad(i,v00,v10,v01,v11);
    }
    private void SetQuad(int i, int v00, int v10, int v01, int v11)
    {
        _triangles[i] = v00;
        _triangles[i + 1] = v01;
        _triangles[i + 2] = v10;

        _triangles[i + 3] = v01;
        _triangles[i + 4] = v11;
        _triangles[i + 5] = v10;
    }

也可以将最后一个单独拿出来计算,这样第一个SetQuad函数可以省略。

SetQuad(triangles, t, v, v - ring + 1, v + ring, v + 1);
  • 顶面
    起始点序列等于四周面最后一个顶点序列加一
    在这里插入图片描述
    代码
  for (int x = 0; x < xGridCount - 1; x++, v++, t += 6)
        {
            SetQuad(t, v, v + 1, v + circleVerticeCount - 1, v + circleVerticeCount);
        }
        //生成第一行最后一个面
        SetQuad(t, v, v + 1, v + circleVerticeCount - 1, v + 2);
        t += 6;
        //================计算中间面
        int vMin = circleVerticeCount * (yGridCount + 1) - 1;//侧面最后一个顶点,计算第一个面用
        int vMid = vMin + 1;//抽象v10
        int vMax = v + 2;//边上点,计算最后一个面用
        for (int z = 0; z < zGridCount-2; z++,vMin--,vMid++,vMax++)
        {
            //第一个面
            SetQuad(t,vMin,vMid,vMin-1,vMid+xGridCount-1);
            t += 6;
            //中间面
            for (int x = 0; x < xGridCount-2; x++,vMid++)
            {
                SetQuad(t, vMid, vMid+1, vMid + xGridCount - 1,vMid+xGridCount);
                t += 6;
            }
            //最后一个面
            SetQuad(t, vMid, vMax, vMid + xGridCount - 1, vMax+1);
            t += 6;
        }
        //============最后一个面
        //第一个面
        SetQuad(t, vMin, vMid, vMin - 1, vMin-2);
        t += 6;
        vMin -= 2;
        //中见面
        for (int x = 0; x < xGridCount - 2; x++, vMid++,vMin--)
        {
            SetQuad(t, vMid, vMid + 1, vMin, vMin-1);
            t += 6;
        }
        //最后一个面
        SetQuad(t, vMid, vMin-2, vMin, vMin-1 );
        t += 6;
  • 底面
    思路同顶面,底面起始点序列等于顶点数组长度减底面个数

3.生成圆角

在这里插入图片描述
如图,想让一个交变成圆角,圆角半径内的xy、xz、yz面上点都要移动到圆上。以图左下角举例,在圆角圆上的点坐标x、y、z都小于r,圆心为(r,r,r)。并且可以求出此点的法向量,根据法向量可求出此点在球面上的坐标。点在球面上的x、y、z可能为<r或者大于边长-r都要进行判断。

  • 代码:
    //判断顶点是否在圆上并且算出顶点的法线,返回此点对应圆心的坐标
  private Vector3 SetNormal(int i)
    {
        Vector3 vertice = _vertices[i];
        Vector3 inner = vertice;//圆角的圆心点
        if (inner.x<_r)
        {
            inner.x = _r;
        }else if (inner.x>xGridCount-_r)
        {
            inner.x = xGridCount - _r;
        }
        if (inner.y < _r)
        {
            inner.y = _r;
        }
        else if (inner.y > yGridCount - _r)
        {
            inner.y = yGridCount - _r;
        }
        if (inner.z< _r)
        {
            inner.z= _r;
        }
        else if (inner.z > zGridCount - _r)
        {
            inner.z = zGridCount - _r;
        }
        _normals[i] = (vertice - inner).normalized;
        return inner;
    }
    /// 重新设定顶点的位置
    private void ResetVerticePos(int i,Vector3 inner)
    {
      _vertices[i] = _normals[i] * _r + inner;
    }

4.变形动画

**源码工程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值