开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

蛮牛译馆

关注:510

当前位置:游戏蛮牛 技术专区 蛮牛译馆

查看: 1079|回复: 7

[Unity教程] UnityC#教程—六边形地图系列之不规则纹理

[复制链接]  [移动端链接]
6蛮牛粉丝
1396/1500
排名
1875
昨日变化
7

5

主题

526

帖子

1396

积分

Rank: 6Rank: 6Rank: 6

UID
143831
好友
2
蛮牛币
1796
威望
0
注册时间
2016-3-29
在线时间
353 小时
最后登录
2017-3-23

蛮牛译员活力之星七夕浪漫情人

发表于 2016-9-26 22:21:39 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 manew_JR 于 2016-9-27 09:39 编辑

六边形地图4:不规则性
采样噪声纹理。
扰动的顶点。
保持单元格平坦。

将单元格边缘细分。

本教程是一系列关于六角地图的第四部分。到目前为止,我们的网格是一个严格的结构。在这一部分中,我们将介绍不规则的行为,使我们的地图看起来更自然。
1.png
1噪声
要添加不规则行为,我们需要随机性。但不是真正的随机性。我们希望事情保持连续性,每当我们编辑我们的地图。否则,每一次我们做了一个动作会产生大的偏差。所以我们需要一种形式的重复的伪随机噪声。
Perlin噪声是一个很好的候选人。它在任何一点都是可重复的。当多个频率的结合,也会产生噪声,可以改变很多,在大的距离,但保持相当类似的小的距离。这可以产生相对平滑的扭曲。离得近的点往往粘在一起,而不会被扭曲向相反的方向
我们可以以编程方式生成Perlin噪声。噪音教程解释了如何做到这。但我们也可以从一个预生成的噪声纹理。使用一个纹理的优势在于它更容易比计算的多频率Perlin噪声快得多。缺点是,纹理占据了更多的内存,只覆盖了一个小区域的噪声。因此需要一个平铺纹理,具有足够大的区域四平铺纹理不明显。
1.1噪声纹理
我们要使用一个纹理,但是你不必通过噪音教程制作。这意味着我们需要现成的纹理。这有一个。
2.png
上面的纹理有平铺的多频Perlin噪声。它是一个灰度图像,平均值为0.5,极值接近0和1
但是稍等,这只是一个单一的点。如果我们想要一个三维的扭转,我们需要至少三个随机样本!因此,在每个不同的噪声我们需要两个额外的纹理。
我们可以这样做,或者我们可以在每个颜色通道中存储一个不同的噪声值。这使我们能够存储多达四个不同的噪声模式在一个单一的纹理。这里是这样的一个纹理。
3.png
拿到这个纹理,并将其导入到您的Unity项目中。因为我们要通过代码来示例纹理,所以它必须是可读的。切换Texture Type到Advanced,选择Read/Write Enabled。这样可以通过C #代码将纹理数据存在内存中。确保设置Format到Automatic Truecolor,否则这不会工作。无论如何,我们不想通过纹理压缩来破坏我们的噪声模式。
我们可以禁用Generate Mip Maps,因为我们不需要他们。虽然我们在这,使用了Bypass sRGB Sampling。我们不需要这个,但它是正确的。它表明,纹理不包含颜色数据在Gamma空间中。
4.png
1.2采样噪声
让我们添加噪声采样功能方法在HexMetrics,方便可以从任何地方调用。这意味着,HexMetrics有很多噪声纹理引用。
[AppleScript] 纯文本查看 复制代码
        public static Texture2D noiseSource;

因为它不是一个组件,我们不能通过编辑器将我们的纹理分配给它。我们只能使用HexGrid作为中介。当HexGrid第一个行动起来,在Awake方法中首先把纹理进行传递效果很好。
[AppleScript] 纯文本查看 复制代码
        public Texture2D noiseSource;

        void Awake () {
                HexMetrics.noiseSource = noiseSource;

                …
        }

然而,这种方法将无法通过重新编译在游戏运行模式。静态变量不能被连载在Unity。为了解决这个问题,重新分配纹理在OnEnable事件的方法以及。此方法会调用在重新编译后。
[AppleScript] 纯文本查看 复制代码
void OnEnable () {
                HexMetrics.noiseSource = noiseSource;
        }

5.png
现在,HexMetrics可以访问纹理,让我们添加一个方便噪声取样的方法。该方法取得一个世界位置并且产生的一种包含四种噪声样本的4D向量。
[AppleScript] 纯文本查看 复制代码
public static Vector4 SampleNoise (Vector3 position) {
        }

样品是通过使用双线性滤波的采样的纹理,使用X和Z的世界坐标作为UV坐标。我们的噪声源是2D的,我们忽略了第三世界坐标。如果我们的噪声源是3D的,那么我们也会使用Y世界坐标。
我们以一个颜色结束,可以当做一个四维向量。这个伪装可以是隐式的,这意味着我们可以直接返回颜色不用明确的使用四维。
[AppleScript] 纯文本查看 复制代码
public static Vector4 SampleNoise (Vector3 position) {
                return noiseSource.GetPixelBilinear(position.x, position.z);
        }

2扰动的顶点
我们把我们的规则的网格结构通过单独变动顶点来让它变得不规则。所以让我们添加一个扰动方法Perturb来做这个。它把一个不能变动的顶点变得可以动。这样做,就会把不能变动的点加到了我们噪声的样本。
[AppleScript] 纯文本查看 复制代码
Vector3 Perturb (Vector3 position) {
                Vector4 sample = HexMetrics.SampleNoise(position);
        }

让我们地把X,Y,和Z的噪声样本直接和到相应的点的坐标结合匹配起来,把这个作为结果。
[AppleScript] 纯文本查看 复制代码
        Vector3 Perturb (Vector3 position) {
                Vector4 sample = HexMetrics.SampleNoise(position);
                position.x += sample.x;
                position.y += sample.y;
                position.z += sample.z;
                return position;
        }

我们如何能迅速改变那么多的顶点在HexMesh中?通过调整每个顶点时,添加到顶点列表,在AddTriangle 和AddQuad方法中。所以,让我们来这样做。
[AppleScript] 纯文本查看 复制代码
        void AddTriangle (Vector3 v1, Vector3 v2, Vector3 v3) {
                int vertexIndex = vertices.Count;
                vertices.Add(Perturb(v1));
                vertices.Add(Perturb(v2));
                vertices.Add(Perturb(v3));
                …
        }

        void AddQuad (Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4) {
                int vertexIndex = vertices.Count;
                vertices.Add(Perturb(v1));
                vertices.Add(Perturb(v2));
                vertices.Add(Perturb(v3));
                vertices.Add(Perturb(v4));
                …
        }

6.png
它看起来不像多大的变化,除了单元格标签似乎是失踪了。这会发生,因为我们增加了噪声样本,他们总是向上覆盖的。所以所有的三角形超过了上面的标签,掩盖了他们。我们必须调整让他们可以在任何一个方向。改变噪声样本的范围从0到1变成–1−–1。
[AppleScript] 纯文本查看 复制代码
        Vector3 Perturb (Vector3 position) {
                Vector4 sample = HexMetrics.SampleNoise(position);
                position.x += sample.x * 2f - 1f;
                position.y += sample.y * 2f - 1f;
                position.z += sample.z * 2f - 1f;
                return position;
        }

7.png
2.1扰动强度
现在很清除看到我们已经可以调整了网格,但效果是非常微小的。每个维度中至多有一个1个单位的调整。所以,理论上的最大位移√3≈1.73单位,这将是极为微笑的的,如果它发生在所有的单元格上。由于我们的单元格有一个外半径为十个单位空间,这样看起来调整的幅度会比较小。
解决的办法是增加一个强度设置在HexMetrics,我们可以增大调整的幅度。让我们尝试一个5的强度。这有一个√75≈8.66套理论最大位移,这样看起来应更明显
[AppleScript] 纯文本查看 复制代码
public const float cellPerturbStrength = 5f;

把这个强度和样本相乘在HexMesh.Perturb.
[AppleScript] 纯文本查看 复制代码
Vector3 Perturb (Vector3 position) {
                Vector4 sample = HexMetrics.SampleNoise(position);
                position.x += (sample.x * 2f - 1f) * HexMetrics.cellPerturbStrength;
                position.y += (sample.y * 2f - 1f) * HexMetrics.cellPerturbStrength;
                position.z += (sample.z * 2f - 1f) * HexMetrics.cellPerturbStrength;
                return position;
        }

8.png
2.2噪声尺度
虽然网格看起来很好在编辑之前,一旦梯田出现却会出错。他们的顶点在不同的方向上被扭曲,导致混乱。这不应该是在使用Perlin噪声的时候应该发生的。
这个问题发生是因为我们直接使用世界坐标和采样噪声匹配。这将导致纹理在每一个单位起作用取样,而我们的细胞是远远大于起作用的区域。纹理在任意位置采样,破坏了它所具有的任何连贯性。
9.png
我们必须扩大噪声采样,以便纹理覆盖了一个更大的区域。让我们添加这个规模HexMetrics并将其设置为0.003,然后就按照这个参数规范取样的样本。
[AppleScript] 纯文本查看 复制代码
public const float noiseScale = 0.003f;

        public static Vector4 SampleNoise (Vector3 position) {
                return noiseSource.GetPixelBilinear(
                        position.x * noiseScale,
                        position.z * noiseScale
                );
        }

这样的话我们的纹理覆盖333⅓平方单位及其局部连贯性变得明显。
10.png
我们的新规模范围也确保噪声将需要一段时间才加上去。实际上,因为单元格有10√3单位的内径,它从来没有完全平铺在X维。然而,由于噪声的局部一致性,你仍然可以在较大尺度上检测到重复的模式,大约每20个细胞,即使细节不匹配。但这只是很明显的其他特征的地图的区别。

3中心单元格的矫正
对所有顶点的调整给我们的地图更自然的效果,但也存在一些问题。由于单元格现在是不平衡的,他们的标签和网格相交错。悬崖处的台阶的网格会有开裂。我们先把这个问题放一下,并专注于单元格表面。
11.png
解决这个问题的最简单的方法是保持细胞中心的扁平。不把HexMesh.Perturb的Y坐标调整。
[AppleScript] 纯文本查看 复制代码
        Vector3 Perturb (Vector3 position) {
                Vector4 sample = HexMetrics.SampleNoise(position);
                position.x += (sample.x * 2f - 1f) * HexMetrics.cellPerturbStrength;
//                position.y += (sample.y * 2f - 1f) * HexMetrics.cellPerturbStrength;
                position.z += (sample.z * 2f - 1f) * HexMetrics.cellPerturbStrength;
                return position;
        }

12.png
这种变化让所有的垂直位置不变,无论是对单元格中心和台阶上。需要注意这降低了最大位移到√50≈7.07,只有在XZ平面。
这并不是一个坏的变化,因为它使它更容易识别单个单元格,并防止梯田变得太混乱。但一些垂直调整也还是不错的。
3调整单元格高度
不是应用每一个顶点的垂直调整,我们是要可以应用它每一个单元格。这样,每个单元格仍然是平坦的,但仍然有单元格之间的变化。这样对于用不同的范围进行高度的调整变得有意义了,所以加一个到HexMetrics中。一个强度为1.5个单位的调整会提供了一些微妙的变化,这大致的高度一个单一的台阶高度。
[AppleScript] 纯文本查看 复制代码
        public const float elevationPerturbStrength = 1.5f;

调整HexCell.Elevation属性使它适用于单元格垂直位置的调整。
[AppleScript] 纯文本查看 复制代码
public int Elevation {
                get {
                        return elevation;
                }
                set {
                        elevation = value;
                        Vector3 position = transform.localPosition;
                        position.y = value * HexMetrics.elevationStep;
                        position.y +=
                                (HexMetrics.SampleNoise(position).y * 2f - 1f) *
                                HexMetrics.elevationPerturbStrength;
                        transform.localPosition = position;

                        Vector3 uiPosition = uiRect.localPosition;
                        uiPosition.z = -position.y;
                        uiRect.localPosition = uiPosition;
                }
        }

为了确保调整立即应用,我们必须明确设置每个单元格的高度在HexGrid.CreateCell。否则,网格将开始的过于平坦。在已经创建了UI界面后再做这一步。
[AppleScript] 纯文本查看 复制代码
        void CreateCell (int x, int z, int i) {
                …

                cell.Elevation = 0;
        }

13.png
3.2使用相同的高度
很多的裂缝出现在网格交接,因为我们不是一直使用同一个单元格的高度的时候在三角化网格时候。让我们添加一个方便的属性HexCell找到它的位置,所以我们在任何地方都可以使用它。
[AppleScript] 纯文本查看 复制代码
public Vector3 Position {
                get {
                        return transform.localPosition;
                }
        }

现在我们可以使用HexMesh.Triangulate的属性来判断单元格的中心。
[AppleScript] 纯文本查看 复制代码
void Triangulate (HexDirection direction, HexCell cell) {
                Vector3 center = cell.Position;
                …
        }

我们可以使用它在TriangulateConnection中,确定相邻单元格的垂直位置时候。
[AppleScript] 纯文本查看 复制代码
void TriangulateConnection (
                HexDirection direction, HexCell cell, Vector3 v1, Vector3 v2
        ) {
                …

                Vector3 bridge = HexMetrics.GetBridge(direction);
                Vector3 v3 = v1 + bridge;
                Vector3 v4 = v2 + bridge;
                v3.y = v4.y = neighbor.Position.y;

                …

                HexCell nextNeighbor = cell.GetNeighbor(direction.Next());
                if (direction <= HexDirection.E && nextNeighbor != null) {
                        Vector3 v5 = v2 + HexMetrics.GetBridge(direction.Next());
                        v5.y = nextNeighbor.Position.y;

                        …
                }
        }

14.png

4细分单元格边缘
当我们的单元格有很好的变化时,他们仍然是明显的六边形。这不是一个问题,但我们可以做的比这更好。
15.png
如果我们有更多的顶点,我们会看到更多的变化。因此,让我们分开每个单元格边缘分为两部分,通过引入一个边缘顶点中间在每一对角落之间。这意味着HexMesh.Triangulate必须增加两个而不是一个三角形。
[AppleScript] 纯文本查看 复制代码
        void Triangulate (HexDirection direction, HexCell cell) {
                Vector3 center = cell.Position;
                Vector3 v1 = center + HexMetrics.GetFirstSolidCorner(direction);
                Vector3 v2 = center + HexMetrics.GetSecondSolidCorner(direction);

                Vector3 e1 = Vector3.Lerp(v1, v2, 0.5f);

                AddTriangle(center, v1, e1);
                AddTriangleColor(cell.color);
                AddTriangle(center, e1, v2);
                AddTriangleColor(cell.color);

                if (direction <= HexDirection.SE) {
                        TriangulateConnection(direction, cell, v1, v2);
                }
        }


在我们的单元格的边缘增加一倍的顶点和三角形增加了更多的种类。增加三倍的顶点让边缘更加崎岖的效果。
[AppleScript] 纯文本查看 复制代码
Vector3 e1 = Vector3.Lerp(v1, v2, 1f / 3f);
                Vector3 e2 = Vector3.Lerp(v1, v2, 2f / 3f);

                AddTriangle(center, v1, e1);
                AddTriangleColor(cell.color);
                AddTriangle(center, e1, e2);
                AddTriangleColor(cell.color);
                AddTriangle(center, e2, v2);
                AddTriangleColor(cell.color);


4.1细分边缘连接
当然我们也有细分边缘连接的必要。所以,新的边缘顶点需要加到TriangulateConnection
[AppleScript] 纯文本查看 复制代码
if (direction <= HexDirection.SE) {
                        TriangulateConnection(direction, cell, v1, e1, e2, v2);
                }

在TriangulateConnection添加匹配参数让它可以适用于其他顶点。
[AppleScript] 纯文本查看 复制代码
        void TriangulateConnection (
                HexDirection direction, HexCell cell,
                Vector3 v1, Vector3 e1, Vector3 e2, Vector3 v2
        ) {
        …
}

我们还需要计算相邻单元格的额外的边缘顶点。我们可以计算这些点在和其它单元格接壤后。
[AppleScript] 纯文本查看 复制代码
Vector3 bridge = HexMetrics.GetBridge(direction);
                Vector3 v3 = v1 + bridge;
                Vector3 v4 = v2 + bridge;
                v3.y = v4.y = neighbor.Position.y;

                Vector3 e3 = Vector3.Lerp(v3, v4, 1f / 3f);
                Vector3 e4 = Vector3.Lerp(v3, v4, 2f / 3f);

下一步,我们必须调整边缘的三角网。现在在梯田上忽略斜坡,添加三个方格不是一个。
[AppleScript] 纯文本查看 复制代码
if (cell.GetEdgeType(direction) == HexEdgeType.Slope) {
                        TriangulateEdgeTerraces(v1, v2, cell, v3, v4, neighbor);
                }
                else {
                        AddQuad(v1, e1, v3, e3);
                        AddQuadColor(cell.color, neighbor.color);
                        AddQuad(e1, e2, e3, e4);
                        AddQuadColor(cell.color, neighbor.color);
                        AddQuad(e2, v2, e4, v4);
                        AddQuadColor(cell.color, neighbor.color);
                }


4.2绑定边缘顶点
由于我们现在需要四个顶点来描述一个边缘,这就有必要把他们组合起来。这比处理四个单独的顶点更方便。这创建了一个简单的EdgeVertices结构体。它应该包含四个顶点,沿着单元格的边缘顺时针方向有序记录。
[AppleScript] 纯文本查看 复制代码
using UnityEngine;

public struct EdgeVertices {

        public Vector3 v1, v2, v3, v4;
}

写一个方便的构造方法,它需要计算中间的边缘点。
[AppleScript] 纯文本查看 复制代码
        public EdgeVertices (Vector3 corner1, Vector3 corner2) {
                v1 = corner1;
                v2 = Vector3.Lerp(corner1, corner2, 1f / 3f);
                v3 = Vector3.Lerp(corner1, corner2, 2f / 3f);
                v4 = corner2;
        }

现在我们可以添加一个单独的三角剖分方法在HexMesh中,创建单元格的中心和边缘之间的一个三角扇形。
[AppleScript] 纯文本查看 复制代码
        void TriangulateEdgeFan (Vector3 center, EdgeVertices edge, Color color) {
                AddTriangle(center, edge.v1, edge.v2);
                AddTriangleColor(color);
                AddTriangle(center, edge.v2, edge.v3);
                AddTriangleColor(color);
                AddTriangle(center, edge.v3, edge.v4);
                AddTriangleColor(color);
        }

还要添加一个方法,在两个边缘之间三角化方格的方法。
[AppleScript] 纯文本查看 复制代码
        void TriangulateEdgeStrip (
                EdgeVertices e1, Color c1,
                EdgeVertices e2, Color c2
        ) {
                AddQuad(e1.v1, e1.v2, e2.v1, e2.v2);
                AddQuadColor(c1, c2);
                AddQuad(e1.v2, e1.v3, e2.v2, e2.v3);
                AddQuadColor(c1, c2);
                AddQuad(e1.v3, e1.v4, e2.v3, e2.v4);
                AddQuadColor(c1, c2);
        }

这使我们能够简化三角化的方法
[AppleScript] 纯文本查看 复制代码
void Triangulate (HexDirection direction, HexCell cell) {
                Vector3 center = cell.Position;
                EdgeVertices e = new EdgeVertices(
                        center + HexMetrics.GetFirstSolidCorner(direction),
                        center + HexMetrics.GetSecondSolidCorner(direction)
                );

                TriangulateEdgeFan(center, e, cell.color);

                if (direction <= HexDirection.SE) {
                        TriangulateConnection(direction, cell, e);
                }
        }

TriangulateConnection。我们现在可以使用TriangulateEdgeStrip,但需要其他一些替换。我们首先用V1,我们应该使用e1.v1。同样,V2成为e1.v4V3V4成为e2.v1e2.v4
[AppleScript] 纯文本查看 复制代码
void TriangulateConnection (
                HexDirection direction, HexCell cell, EdgeVertices e1
        ) {
                HexCell neighbor = cell.GetNeighbor(direction);
                if (neighbor == null) {
                        return;
                }

                Vector3 bridge = HexMetrics.GetBridge(direction);
                bridge.y = neighbor.Position.y - cell.Position.y;
                EdgeVertices e2 = new EdgeVertices(
                        e1.v1 + bridge,
                        e1.v4 + bridge
                );
                
                if (cell.GetEdgeType(direction) == HexEdgeType.Slope) {
                        TriangulateEdgeTerraces(e1.v1, e1.v4, cell, e2.v1, e2.v4, neighbor);
                }
                else {
                        TriangulateEdgeStrip(e1, cell.color, e2, neighbor.color);
                }
                
                HexCell nextNeighbor = cell.GetNeighbor(direction.Next());
                if (direction <= HexDirection.E && nextNeighbor != null) {
                        Vector3 v5 = e1.v4 + HexMetrics.GetBridge(direction.Next());
                        v5.y = nextNeighbor.Position.y;

                        if (cell.Elevation <= neighbor.Elevation) {
                                if (cell.Elevation <= nextNeighbor.Elevation) {
                                        TriangulateCorner(
                                                e1.v4, cell, e2.v4, neighbor, v5, nextNeighbor
                                        );
                                }
                                else {
                                        TriangulateCorner(
                                                v5, nextNeighbor, e1.v4, cell, e2.v4, neighbor
                                        );
                                }
                        }
                        else if (neighbor.Elevation <= nextNeighbor.Elevation) {
                                TriangulateCorner(
                                        e2.v4, neighbor, v5, nextNeighbor, e1.v4, cell
                                );
                        }
                        else {
                                TriangulateCorner(
                                        v5, nextNeighbor, e1.v4, cell, e2.v4, neighbor
                                );
                        }
                }

4.3细分的梯田
我们要细分的梯田。可以通过TriangulateEdgeTerraces.方法。
[AppleScript] 纯文本查看 复制代码
if (cell.GetEdgeType(direction) == HexEdgeType.Slope) {
                        TriangulateEdgeTerraces(e1, cell, e2, neighbor);
                }

现在我们要调整TriangulateEdgeTerraces,让它在边缘之间进行插值的,而不是顶点之间。让我们假设EdgeVertices提供了一个方便的静态插值方法。这让我们TriangulateEdgeTerraces简化,而不是使它更复杂。
[AppleScript] 纯文本查看 复制代码
void TriangulateEdgeTerraces (
                EdgeVertices begin, HexCell beginCell,
                EdgeVertices end, HexCell endCell
        ) {
                EdgeVertices e2 = EdgeVertices.TerraceLerp(begin, end, 1);
                Color c2 = HexMetrics.TerraceLerp(beginCell.color, endCell.color, 1);

                TriangulateEdgeStrip(begin, beginCell.color, e2, c2);

                for (int i = 2; i < HexMetrics.terraceSteps; i++) {
                        EdgeVertices e1 = e2;
                        Color c1 = c2;
                        e2 = EdgeVertices.TerraceLerp(begin, end, i);
                        c2 = HexMetrics.TerraceLerp(beginCell.color, endCell.color, i);
                        TriangulateEdgeStrip(e1, c1, e2, c2);
                }

                TriangulateEdgeStrip(e2, c2, end, endCell.color);
        }

EdgeVertices.TerraceLerp方法简单地执行所有的四对两边缘顶点之间的梯田插值。
[AppleScript] 纯文本查看 复制代码
public static EdgeVertices TerraceLerp (
                EdgeVertices a, EdgeVertices b, int step)
        {
                EdgeVertices result;
                result.v1 = HexMetrics.TerraceLerp(a.v1, b.v1, step);
                result.v2 = HexMetrics.TerraceLerp(a.v2, b.v2, step);
                result.v3 = HexMetrics.TerraceLerp(a.v3, b.v3, step);
                result.v4 = HexMetrics.TerraceLerp(a.v4, b.v4, step);
                return result;
        }



5连接悬崖和梯田
到目前为止,我们忽略了那些裂缝,悬崖和梯田接壤的地方。是处理这个问题的时候了。让我们考虑崖边坡(CSS)和坡崖坡(SCS)例子。

问题发生,因为边界的顶点发生了扰动。这意味着,他们不再处于悬崖类型的一侧,产生一个裂缝。有时,这些洞是不明显的,有时他们是明显的。
解决的办法是不要扰乱边界顶点。这意味着我们需要控制一个点是否会受到扰动。最简单的方法是创建一个AddTriangle做替代,这是不会扰动的顶点。
[AppleScript] 纯文本查看 复制代码
void AddTriangleUnperturbed (Vector3 v1, Vector3 v2, Vector3 v3) {
                int vertexIndex = vertices.Count;
                vertices.Add(v1);
                vertices.Add(v2);
                vertices.Add(v3);
                triangles.Add(vertexIndex);
                triangles.Add(vertexIndex + 1);
                triangles.Add(vertexIndex + 2);
        }

调整TriangulateBoundaryTriangle的方法。这意味着是需要调整所有顶点,除了边界顶点。
[AppleScript] 纯文本查看 复制代码
void TriangulateBoundaryTriangle (
                Vector3 begin, HexCell beginCell,
                Vector3 left, HexCell leftCell,
                Vector3 boundary, Color boundaryColor
        ) {
                Vector3 v2 = HexMetrics.TerraceLerp(begin, left, 1);
                Color c2 = HexMetrics.TerraceLerp(beginCell.color, leftCell.color, 1);

                AddTriangleUnperturbed(Perturb(begin), Perturb(v2), boundary);
                AddTriangleColor(beginCell.color, c2, boundaryColor);

                for (int i = 2; i < HexMetrics.terraceSteps; i++) {
                        Vector3 v1 = v2;
                        Color c1 = c2;
                        v2 = HexMetrics.TerraceLerp(begin, left, i);
                        c2 = HexMetrics.TerraceLerp(beginCell.color, leftCell.color, i);
                        AddTriangleUnperturbed(Perturb(v1), Perturb(v2), boundary);
                        AddTriangleColor(c1, c2, boundaryColor);
                }

                AddTriangleUnperturbed(Perturb(v2), Perturb(left), boundary);
                AddTriangleColor(c2, leftCell.color, boundaryColor);
        }

注意,因为我们不使用V2得到其他任何一点,就有可能让它立即得到调整。它是一个简单的优化,减少了代码量,所以让我们这样做。
[AppleScript] 纯文本查看 复制代码
void TriangulateBoundaryTriangle (
                Vector3 begin, HexCell beginCell,
                Vector3 left, HexCell leftCell,
                Vector3 boundary, Color boundaryColor
        ) {
                Vector3 v2 = Perturb(HexMetrics.TerraceLerp(begin, left, 1));
                Color c2 = HexMetrics.TerraceLerp(beginCell.color, leftCell.color, 1);

                AddTriangleUnperturbed(Perturb(begin), v2, boundary);
                AddTriangleColor(beginCell.color, c2, boundaryColor);

                for (int i = 2; i < HexMetrics.terraceSteps; i++) {
                        Vector3 v1 = v2;
                        Color c1 = c2;
                        v2 = Perturb(HexMetrics.TerraceLerp(begin, left, i));
                        c2 = HexMetrics.TerraceLerp(beginCell.color, leftCell.color, i);
                        AddTriangleUnperturbed(v1, v2, boundary);
                        AddTriangleColor(c1, c2, boundaryColor);
                }

                AddTriangleUnperturbed(v2, Perturb(left), boundary);
                AddTriangleColor(c2, leftCell.color, boundaryColor);
        }


这看起来更好,但我们还没有做。在TriangulateCornerTerracesCliff方法,边界点是通过插值之间的左、右点获得的。然而,这些点还没有得到调整。使边界点和最后的悬崖类型匹配,我们必须调整点之间的插值。
[AppleScript] 纯文本查看 复制代码
Vector3 boundary = Vector3.Lerp(Perturb(begin), Perturb(right), b);

TriangulateCornerCliffTerraces也是一样
[AppleScript] 纯文本查看 复制代码
        Vector3 boundary = Vector3.Lerp(Perturb(begin), Perturb(left), b);


5.1俩个悬崖和一个斜坡
剩下的问题的情况是那些有两个悬崖和一个斜坡。

这个问题在TriangulateCornerTerracesCliff.最后的else块中通过对单独三角化手动的调整来解决的。
[AppleScript] 纯文本查看 复制代码
else {
                        AddTriangleUnperturbed(Perturb(left), Perturb(right), boundary);
                        AddTriangleColor(leftCell.color, rightCell.color, boundaryColor);
                }

TriangulateCornerCliffTerraces也是一样
[AppleScript] 纯文本查看 复制代码
else {
                        AddTriangleUnperturbed(Perturb(left), Perturb(right), boundary);
                        AddTriangleColor(leftCell.color, rightCell.color, boundaryColor);
                }



6地形的不规则
我们现在有一个完全正确的调整网格。它的精确的取决于特定的噪声,它的规模,和扰动强度。在我们的例子中,扰动可能是有点太强了。虽然不规则的外观是很好的,我们不希望单元格偏离太多从规则的网格。毕竟,我们仍然使用,以确定哪些单元格我们正在编辑。如果单元格的大小变化太大,这将是很难适应他们后面的内容


强度为5的扰动看起来有点大

让我们减少到4,使它更易于管理,而地形不会变得太正常。保证在XZ面上有一个√325.66最大位移。
[AppleScript] 纯文本查看 复制代码
        public const float cellPerturbStrength = 4f;


我们可以调整的另一个值。如果我们增加它,平坦单元格中心将变得更大。这给未来留下了更多的空间。当然,他们也会变得更趋向六角形。

固定值的稍微增加到0.8会在后边的使用更方便
[AppleScript] 纯文本查看 复制代码
        public const float solidFactor = 0.8f;


最后,海拔水平之间的差异是有点陡峭时。这是方便的对于检查是否生成正确的网格,这我们已经完成了。让我们把每个台阶减少到一个单位,所以设置3
[C#] 纯文本查看 复制代码
        public const float elevationStep = 3f;


我们还可以调整高度的扰动强度。通常设定为1.5,现在相当于半个台阶高度,这是好的效果。
一个较小的海拔也可以使用我们所有的七个海拔高度。这使我们能够添加更多的地形类型到我们的地图。


》》译馆招募新译员啦!《《
     蛮牛译林军福利多多哦!

扫描下方二维码关注游戏蛮牛官方微信~每日都有精选干货与你分享呦~
155547iluo7umxezrb2ekr.png
本文由蛮牛驿馆倾情奉献,翻译:蛮牛译员 tian123,如有问题请及时联系,除 合作社区 及 合作媒体 外,禁止转载。




回复

使用道具 举报

7日久生情
1710/5000
排名
1107
昨日变化
5

5

主题

288

帖子

1710

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
137142
好友
1
蛮牛币
7568
威望
0
注册时间
2016-2-21
在线时间
677 小时
最后登录
2017-3-23
发表于 2016-9-27 12:26:44 | 显示全部楼层
mark 这个有意思

回复

使用道具 举报

5熟悉之中
999/1000
排名
3292
昨日变化
20

6

主题

229

帖子

999

积分

Rank: 5Rank: 5

UID
159103
好友
5
蛮牛币
2435
威望
0
注册时间
2016-8-29
在线时间
418 小时
最后登录
2017-3-23

活力之星

发表于 2016-9-27 17:20:58 | 显示全部楼层
这个可以  谢谢楼主分享

回复 支持 反对

使用道具 举报

7日久生情
2239/5000
排名
238
昨日变化

0

主题

199

帖子

2239

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
43022
好友
0
蛮牛币
9246
威望
0
注册时间
2014-9-1
在线时间
656 小时
最后登录
2017-3-14
发表于 2016-9-28 08:46:30 | 显示全部楼层
666666666666

回复

使用道具 举报

7日久生情
2761/5000
排名
95
昨日变化

5

主题

264

帖子

2761

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
2352
好友
6
蛮牛币
5013
威望
0
注册时间
2013-8-21
在线时间
715 小时
最后登录
2017-3-23

社区QQ达人

发表于 2016-9-28 09:15:54 | 显示全部楼层
挺有意思~

回复

使用道具 举报

6蛮牛粉丝
1390/1500
排名
959
昨日变化
2

0

主题

377

帖子

1390

积分

Rank: 6Rank: 6Rank: 6

UID
111260
好友
0
蛮牛币
4457
威望
0
注册时间
2015-6-30
在线时间
219 小时
最后登录
2017-3-23
发表于 2016-10-6 14:48:30 | 显示全部楼层
挺有意思~
[发帖际遇]: 一个袋子砸在了 漫无边际 头上,漫无边际 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

3偶尔光临
289/300
排名
7260
昨日变化
10

0

主题

93

帖子

289

积分

Rank: 3Rank: 3Rank: 3

UID
24931
好友
0
蛮牛币
463
威望
0
注册时间
2014-5-13
在线时间
90 小时
最后登录
2017-1-10
发表于 2016-10-26 09:03:16 | 显示全部楼层
把这个系列弄个目录呗

回复 支持 反对

使用道具 举报

排名
33356
昨日变化
113

0

主题

9

帖子

28

积分

Rank: 1

UID
129132
好友
0
蛮牛币
49
威望
0
注册时间
2015-11-17
在线时间
16 小时
最后登录
2017-3-5
发表于 2017-2-6 18:19:32 | 显示全部楼层
把这个系列弄个目录呗

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

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