用unity实现tilt brush绘制面片功能(一)

发表于2017-04-24
评论2 6.5k浏览

相信很多人都被去年亮相的tilt brush绘图效果所惊艳,最近有些手痒,便打算自行实现一下tilt brush的绘制面片功能。由于代码量相对较大,预计会分三次实现完整的效果,并将实现思路记录在腾讯GAD中,供大家学习交流,如发现不合理的地方,请及时告知,谢谢。

由于手上没有htcvive,所以只能通过键盘输入来模拟移动,下面是移动的代码
1
2
3
4
5
6
7
8
if (Input.GetKey("q"))
        {
            transform.Rotate(new Vector3(0, 0, -rotat));
        }
        if (Input.GetKey("e"))
        {
            transform.Rotate(new Vector3(0, 0, rotat));
        }
在物体移动时,我们需要将其位置记录在一个数组当中,为了节省计算旋转后位置信息的性能开销,我便直接在物体两端绑了2个gameobject,直接上代码
1
2
3
4
5
6
7
8
9
10
if (!isprint)
        {
            if (Vector3.Distance(transform.position, pos) > 0.2f)
            {
                //将2个小球位置保存
                m_point1.Add(point1.transform.position);
                m_point2.Add(point2.transform.position);
                pos = transform.position;
            }
        }
位置记录之后便是通过这些位置生成对应的顶点,三角梅和uv数据,先上代码,后详细解释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
m_vertices = new Vector3[m_point1.Count * 2];
for(int i=0;i< m_point1.Count; i++)
{
    //逐个添加顶点
    m_vertices[i * 2] = m_point1[i];
    m_vertices[i * 2 + 1] = m_point2[i];
}
m_uv = new Vector2[m_point1.Count * 2];
for (int i = 0; i < m_point1.Count; i++)
{
    //设置uv,从左下到右上,从0到1
    m_uv[i * 2] = new Vector2(0, (float)i / (float)m_point1.Count);
    m_uv[i * 2 + 1] = new Vector2(0, (float)i / (float)m_point1.Count);
}
m_triangles = new int[m_point1.Count * 3];
for (int i = 0; i < m_point1.Count; i++)
{
    //设置三角面
    m_triangles[i * 3] = i;
    if (i % 2 == 0)
    {
        m_triangles[i * 3 + 1] = i + 1;
        m_triangles[i * 3 + 2] = i + 2;
    }
    else
    {
        m_triangles[i * 3 + 1] = i + 2;
        m_triangles[i * 3 + 2] = i + 1;
    }
}
首先是将顶点数据存储起来,这个没什么说的,挨个存储进一个vector3数组就OK
然后是存储uv,根据需求,我们在一个面片中只需要绘制一张图片,所以uv从左下到右上只能是从0到1,这样我们便可以通过i值除以数组长度来获得uv值的大小,别忘了数据类型转换喔!
最后是设置三角面,由于我们的网格是单面的,如果三角面设置顺序错误,便只能看见一半的图像,切记。
如图,该网格的三角面应该是(1,2,3),(2,4,3),(3,4,5),(4,6,5),(5,6,7),(6,8,8)找到规律了吗?
将数据保存后当然是更新我们的网格啦,直接上代码
1
2
3
4
5
6
7
8
mesh.Clear();//将原来的网格信息清除
mesh.vertices = m_vertices;
mesh.uv = m_uv;
mesh.colors = m_color;
mesh.normals = m_normals;
mesh.triangles = m_triangles;
mesh.RecalculateNormals();//重绘网格
transform.position = Vector3.zero;//为了使绘制后的物体仍在原地,将移动后的物体归位
最终是我们网格的效果图
下面是完整的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class demo : MonoBehaviour
{
    public float speed = 0.1f;
    public float rotat = 1;
    public Vector3[] m_vertices;
    public Vector2[] m_uv;
    public Color[] m_color;
    public Vector3[] m_normals;
    public int[] m_triangles;
    private List m_point1 = new List();
    private List m_point2 = new List();
    private Mesh mesh;
    private bool isprint = false;
    private Vector3 pos = Vector3.zero;
    private Transform point1;
    private Transform point2;
 
    void Start()
    {
        mesh = transform.GetComponent().mesh;//无法打出尖括号!注意,这里要先获取MeshFilter再.mesh
        point1 = transform.GetChild(0);
        point2 = transform.GetChild(1);
    }
 
    void FixedUpdate()
    {
        Move();
    }
 
    void Update()
    {
        //按下p键开始绘制网格
        if (Input.GetKeyDown("p"))
        {
            isprint = true;
            DrawMesh();
        }
    }
 
    void Move()
    {
        transform.Translate(new Vector3(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0)*speed,Space.World);
        if (Input.GetKey("q"))
        {
            transform.Rotate(new Vector3(0, 0, -rotat));
        }
        if (Input.GetKey("e"))
        {
            transform.Rotate(new Vector3(0, 0, rotat));
        }
        if (!isprint)
        {
            if (Vector3.Distance(transform.position, pos) > 0.2f)
            {
                //将2个小球位置保存
                m_point1.Add(point1.transform.position);
                m_point2.Add(point2.transform.position);
                pos = transform.position;
            }
        }
    }
 
    void DrawMesh()
    {
        m_vertices = new Vector3[m_point1.Count * 2];
        for(int i=0;i< m_point1.Count; i++)
        {
            //逐个添加顶点
            m_vertices[i * 2] = m_point1[i];
            m_vertices[i * 2 + 1] = m_point2[i];
        }
        m_uv = new Vector2[m_point1.Count * 2];
        for (int i = 0; i < m_point1.Count; i++)
        {
            //设置uv,从左下到右上从0到1
            m_uv[i * 2] = new Vector2(0, (float)i / (float)m_point1.Count);
            m_uv[i * 2 + 1] = new Vector2(0, (float)i / (float)m_point1.Count);
        }
        m_triangles = new int[m_point1.Count * 3];
        for (int i = 0; i < m_point1.Count; i++)
        {
            //设置三角面
            m_triangles[i * 3] = i;
            if (i % 2 == 0)
            {
                m_triangles[i * 3 + 1] = i + 1;
                m_triangles[i * 3 + 2] = i + 2;
            }
            else
            {
                m_triangles[i * 3 + 1] = i + 2;
                m_triangles[i * 3 + 2] = i + 1;
            }
        }
        ChangeMesh();
    }
 
    void ChangeMesh()
    {
        mesh.Clear();//将原来的网格信息清除
        mesh.vertices = m_vertices;
        mesh.uv = m_uv;
        mesh.colors = m_color;
        mesh.normals = m_normals;
        mesh.triangles = m_triangles;
        mesh.RecalculateNormals();//重绘网格
        transform.position = Vector3.zero;//为了使绘制后的物体仍在原地,将移动后的物体归位
    }
}

第一部分就到此结束了,shader部分见下次文章!

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引