找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

查看: 1589|回复: 6

[Unity3D] UnityC#教程:立方球体圆润度优化

[复制链接]

该用户从未签到

3

主题

13

帖子

13

积分

LV.1

Rank: 1

积分
13
QQ
发表于 2019-7-3 17:22:40 | 显示全部楼层 |阅读模式
把立方体变成一个球

以球的形式显示在unity中

严格检查转换

用数学提出一个最好的解决办法

在本教程中,我们将基于立方体创建一个球体网格,然后用数学推理去改善它。

本教程是圆形的立方体,它可以在unity5.0.1及其以上版本运行

UnityC#教程:立方球体圆润度优化 Unity3D教程 第1张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第1张

从一个形状延伸为另一个形状

1.采用圆形的立方体

你可以已经注意到,你可以创建以一个完美的球形立方体,确保它早三个维度中有相同的大小,并将大小设置为圆形大小的一半。

如果你仅仅想要一个球体,那么提供的具有灵活性的立方体只会起到阻碍作用。所以让我们给它创建一个单独的组建,复制RoundedCube 脚本并将它重命名为CubeSphere。然后用单个的girdSize取代三种尺寸并移除roundness的字段。

[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

public class CubeSphere : MonoBehaviour {

        public int gridSize;

        // No more roundness.

        private Mesh mesh;

        private Vector3[] vertices;

        private Vector3[] normals;

        private Color32[] cubeUV;

        …

        private void Generate () {

                GetComponent<MeshFilter>().mesh = mesh = new Mesh();

                mesh.name = "Procedural Sphere";

                CreateVertices();

                CreateTriangles();

                CreateColliders();

        }

        …

}

你如将三个大小字段替换为一个?

最方便的方法是使用编辑器去重构变量名。这确保了所有的引用都是重命名的,第一个重命名是将 xSize 变成gridSize,接下来是将ySize 和 zSize都进行重命名,与此同时,执行多个索搜和替换操作。

你会从gridSize + gridSize得到一些代码的片段,你可以通过重写去表述它,如果不是真的有必要我不喜欢麻烦去写。

删除roundness 字段将会导致错误,因为它仍然在一些地方使用,首先让我们看看碰撞器的创建。

我们需要多个盒子和胶囊碰撞器去代表立方球体,但是球一般只需要单个的球形碰撞器。这意味着我们可以删除AddBoxCollider 和AddCapsuleCollider方法,然后将CreateColliders 方法减少到只需要一行代码。

[C#] 纯文本查看 复制代码

?

1

2

private void CreateColliders () {

                gameObject.AddComponent<SphereCollider>();

        }

接下来是定点的位置,同样依赖于roundness

我们通过一个从角落内部指向原始的立方体的某些地方的普通向量,从而形成立方体圆度的角落。当我们转换成一个球体的时候,我们然需要这样做,其他情况下则会退化。

如果我们把球集中在它的本地原点的时候,也是很方便的。我们做网格和立方体的圆度的时候总是懒得去这样。所以我们直接让它们在中心。

创建一个单位球——球体的半径为一个单位——我们需要规范一点去做,让立方体的顶点集中在原点,为了立方体能完全包含球体,因此需要使立方体的边缘长度为2.


UnityC#教程:立方球体圆润度优化 Unity3D教程 第2张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第2张


符合边缘长度为2的单位圆。

我们可以通过除以原始坐标网格大小的方式,达到在立方体的SetVertex上创建顶点的目的,翻一倍,然后再减掉一个。

[C#] 纯文本查看 复制代码

?

1

2

3

4

5

6

7

public float radius = 1;

        private void SetVertex (int i, int x, int y, int z) {

                Vector3 v = new Vector3(x, y, z) * 2f / gridSize - Vector3.one;

                normals = v.normalized;

                vertices = normals;

                cubeUV = new Color32((byte)x, (byte)y, (byte)z, 0);

        }

这样产生一个单位球,如果你想要不同的半径的话,让我们按下述方法去做

[C#] 纯文本查看 复制代码

?

1

2

3

4

5

6

public float radius = 1f;

private void SetVertex (int i, int x, int y, int z) {

                Vector3 v = new Vector3(x, y, z) * 2f / gridSize - Vector3.one;

                normals = v.normalized;

                vertices = normals * radius;

                cubeUV = new Color32((byte)x, (byte)y, (byte)z, 0);

        }

现在所有的错误都应该清理了,让我们在场景中放入一个立方球体。我们不需要弄它或者替换一个立方体对象的圆度组件。


UnityC#教程:立方球体圆润度优化 Unity3D教程 第3张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第3张


形成一个立方球体

2.调查映射的结果

我们有一个创建球体网格的方法,但是他有多么好呢?让我们从多观点去观察球体,网格是如何统一的?


UnityC#教程:立方球体圆润度优化 Unity3D教程 第4张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第4张


不同的观点,视角和 拼写

网格单元格的大小各不相同 。最大的单元格 来自于中间的立方体表面。它们大约是立方体角落的最小的单元格的4倍。

明白为什么是这样了吧,它让我们更形想地看到如何从球映射到圆。我们将会使用一个圆,因为这比使用一个球体更容易,它只会是一个单片的问题。

我们可以在unity中创建一个可视化的小玩意。我们将在OnDrawGizmosSelected方法中使用一个自定义组件。它除了gizmos当对象被选中的时候会被画,其它的时候工作原理就和OnDrawGizmos一样。用这个方法我们可以添加一个有可视化对象的场景,除了我们选择它的情况其余都不可见。

[C#] 纯文本查看 复制代码

?

1

2

3

4

5

6

using UnityEngine;

public class CircleGizmo : MonoBehaviour {

        private void OnDrawGizmosSelected () {

        }

}

我们通过展示4边形顶点边缘的黑色球体来开始。无论怎么样我都喜欢我的解决方案,让我们从顶部到底部边缘开始吧。

[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

public int resolution = 10;

        private void OnDrawGizmosSelected () {

                float step = 2f / resolution;

                for (int i = 0; i <= resolution; i++) {

                        ShowPoint(i * step - 1f, -1f);

                        ShowPoint(i * step - 1f, 1f);

                }

        }

        private void ShowPoint (float x, float y) {

                Vector2 squARe = new Vector2(x, y);

                Gizmos.color = Color.black;

                Gizmos.DrawSphere(square, 0.025f);

        }


UnityC#教程:立方球体圆润度优化 Unity3D教程 第5张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第5张


完整的填写左边和右边的四方块,随着角落的显现,现在我们可以跳过它们了。

[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

private void OnDrawGizmosSelected () {

                float step = 2f / resolution;

                for (int i = 0; i <= resolution; i++) {

                        ShowPoint(i * step - 1f, -1f);

                        ShowPoint(i * step - 1f, 1f);

                }

                for (int i = 1; i < resolution; i++) {

                        ShowPoint(-1f, i * step - 1f);

                        ShowPoint(1f, i * step - 1f);

                }

        }


UnityC#教程:立方球体圆润度优化 Unity3D教程 第6张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第6张


                       完整的方格

接下来我们将显示每个点所相对应的顶点,使用白色球体,然后我们显示了俩个顶点和黄线之间的关系,最后一个灰色线是从圆的顶点到中心的。

[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

private void ShowPoint (float x, float y) {

                Vector2 square = new Vector2(x, y);

                Vector2 circle = square.normalized;

                Gizmos.color = Color.black;

                Gizmos.DrawSphere(square, 0.025f);

                Gizmos.color = Color.white;

                Gizmos.DrawSphere(circle, 0.025f);

                Gizmos.color = Color.yellow;

                Gizmos.DrawLine(square, circle);

                Gizmos.color = Color.gray;

                Gizmos.DrawLine(circle, Vector2.zero);

        }


UnityC#教程:立方球体圆润度优化 Unity3D教程 第7张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第7张


                   从方块到圆形

现在我们看看映射如何工作。正常的话是把顶点直线拉伸链接到中心,直到他们到达单位圆,接近方块的角落处比在主轴的地方放更多的顶点,顶点在主轴上尽量不移动,当顶点在对角线的单位时被移动。

随着所有的点被指向同一个点。使他们最终都会很接近。这就是为什么靠近对角线的单元格特别小。

3.用数学方法去做

现在我们终于知道为什么单元格最后呈现出不同的大小。我们根据这做一些什么呢?或许会有不同的映射产生更加均匀的单元格,因此,我们该如何找到这样的一个映射呢?

这真的是一个数学问题,让我们更加正式的去描述我们当前的映射吧。在这一次开始时我们只关心我们的圈,假设我们以后可以推广到别的领域。

所以我们的映射点是从方块指向圆,用向量去描述点,我们真的可以把一个向量映射到另一个上。

vs→vc

具体的说我们的圈是一个单位圆,被放在边长为2 的正方形的边缘,因此我们的映射是标准且简单的向量VS。

vc=ˆvs

通过除以自己的长度去的到一个正常的向量

ˆvs=vs||vs||

你如何得到一个二维向量的长度?它有两个坐标。

vs=[xy]

这些坐标定义一个直角三角形,你也可以用勾股定理。


UnityC#教程:立方球体圆润度优化 Unity3D教程 第8张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第8张


现在我们可以用最明确的形式去编写映射。


UnityC#教程:立方球体圆润度优化 Unity3D教程 第9张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第9张


这非常好,但实际上我们可以证明Vc在单位圆上定义了一个点吗?像这样做的话,它的长度必须是1,所以我们必须证明下列的等式成立。


UnityC#教程:立方球体圆润度优化 Unity3D教程 第10张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第10张


这操作很难,所以让它们先达到一致。


UnityC#教程:立方球体圆润度优化 Unity3D教程 第11张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第11张


把它简化成微不足道的是很容易的。


UnityC#教程:立方球体圆润度优化 Unity3D教程 第12张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第12张


最后表达式的分子和分母必须是相等的,结果必须是1。也就是说,只有在X2+Y2结果是0的情况下,结果才能没有意义。但是我们只是用我们在方块边缘我们输入的点,并且还要保证一个或者两个坐标是1或者-1,才能保证


UnityC#教程:立方球体圆润度优化 Unity3D教程 第13张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第13张


所以我们无法得到一个有意义的结果。

这个证明有用吗?他告诉我们,再我们方块的每一个点有一个收益率为1 的公式。这个公式符合从方块映射到单位圆。

我们可以找到不同的公式去做同样的事情吗?如果这样,必须有一个不同的映射。让我们逆转这个过程,在我们的方块上每一个点提出一个公式收益率为一。这个函数会是什么样子呢,如果我们尽可能使它简单吗?我们至少知道有一个坐标总是为-1或者1,我们的方块有两个坐标,我们可以得到至少有一个为1

,至少其中一个总是0,如果他们相乘的话那么肯定可以保证为0,这是我们给出的公式。


UnityC#教程:立方球体圆润度优化 Unity3D教程 第14张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第14张


为什么要减去一而不是加上呢?我们也可以使用


UnityC#教程:立方球体圆润度优化 Unity3D教程 第15张

UnityC#教程:立方球体圆润度优化 Unity3D教程 第15张

该用户从未签到

4

主题

72

帖子

61

积分

LV.2

Rank: 2

积分
61
QQ
发表于 2019-10-7 19:59:47 | 显示全部楼层
想了解下AR增强现实的相关内容来看看

该用户从未签到

5

主题

39

帖子

42

积分

LV.1

Rank: 1

积分
42
QQ
发表于 2019-10-14 11:06:44 | 显示全部楼层
楼主辛苦了,帮楼主顶起来

该用户从未签到

1

主题

18

帖子

18

积分

LV.1

Rank: 1

积分
18
QQ
发表于 2019-10-16 18:04:39 | 显示全部楼层
这里竟然还有这么一个关于AR的网站的收藏了

该用户从未签到

2

主题

61

帖子

49

积分

LV.1

Rank: 1

积分
49
QQ
发表于 2020-1-12 02:20:23 | 显示全部楼层
楼主写的很不错,关于AR的知识受教了

该用户从未签到

2

主题

23

帖子

26

积分

LV.1

Rank: 1

积分
26
QQ
发表于 2020-3-27 01:00:17 | 显示全部楼层
楼主辛苦了。。回帖是一种美德

该用户从未签到

4

主题

27

帖子

32

积分

LV.1

Rank: 1

积分
32
QQ
发表于 2020-3-28 11:34:19 | 显示全部楼层
竟然还有零回复,给我消失
您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

关闭

站长推荐上一条 /1 下一条

快速回复 返回顶部 返回列表