文档章节

翻译: 星球生成 II

FreeBlues
 FreeBlues
发布于 2016/07/21 01:44
字数 1865
阅读 35
收藏 1

翻译: 星球生成 II

本文翻译自Planet Generation - Part II

  • 译者: FreeBlues

以下为译文:

概述

前一章 我解释了如何为星球创建一个几何球体.

在本文中, 我将会解释如何为即将用来创建陆地,岛屿和海洋的顶点加上高度数据.

第一幅星球截图:

计划

本文的计划是为球体的每个面创建高度数据, 置换位置来创建陆地和海洋.

一个重要性质是生成应该是伪随机的(pseudo random), 它允许创建很多外观不同的星球, 并且也能通过提供一个唯一的 种子数(seed)来完全复现相同的生成.

已有的几何体

当前的几何体由可以折叠成一个球体的 6 个网格组成. 这个事实为我们简化了大量不得不做的工作. 如果有人想要创建一个纹理贴图, 他们可以很容易地保持住一个网格的 UV 映射并且为每个面附着一个纹理贴图或者只用立方体纹理映射.

立方体纹理贴图截图:

出于为了得到更高级别细节的原因, 我决定把我的几何体分到 6 个不同的顶点缓冲区中, 它允许我把表面上看不出的独立的位面完全捡出, 并且对每一个位面实现 LOD 算法, 就好像它是一个孤立的地形块.

for ( int j = 0; j < numRows; ++j )
{
    for ( int i = 0; i < numCols; ++i )
    {
        vertices[  j * width + i ].UV.x = (float)i / (float)(numCols - 1);
        vertices[  j * width + i ].UV.y = (float)j / (float)(numRows - 1);
    }
}

现在我们有了 UV 映射, 颜色和高度纹理能被应用了.

生成高度图

正如我上一个帖子中提到过的, 我选择过程内容生成的部分原因是用它补偿我艺术技能方面的欠缺. 换句话说, 对我来说创建一个用于星球的纹理贴图的最好的方法是创建一个将会为我创建纹理贴图的程序. 他们还说, 程序员是安全的, 而人工智能会抢走我们的工作...

我们有 6 个网格, 每个都需要高度数据, 一个特殊需求是数据要很好地沿着网格每一面的边缘包回来. 内容生成的 过往经验 让我以 perlin noise terrain generation 为关键字进行搜索, 结果找到这个教程Tutorial 8: Creating spherical planetary terrain

Libnoise 是一个可移植的, 开源的, 连贯的噪声生成 C++ 库. 对我的需求来说, 这一点听起来很不错, 当我在 Nexus 5 Android 手机上运行这些代码时, 并且这个库还支持一个 SetSeed 函数, 因此它满足了我给定一个种子能够复现相同结果的需求

生成的图可以很容易地切成立方体纹理或者对球体额每一面都独立的纹理贴图(译者注:那就是6个小纹理贴图). 这就是根据上面教程生成的纹理贴图的一个示例:

地球高度截图:

它在地形生成的教程中使用了 Perlin 噪声. Perlin 噪声作为一种很好的用于生成分形并被用于模拟云,烟雾和地形之类的自然景物的梯度噪声生成器而广为人知.

柏林噪声截图:

不幸的是, 用它经过一段时间的试验后, 我发现它生成数据太慢了, 接着我寻找了替代品. 这把我引向简单噪声(Simplex Noise), 跟 Perlin 噪声相比, 它更快并且提供了和 Perlin 噪声相似的结果. 它也可以 GPU 上运行.

使用简单噪声

现在我决定选择的噪声算法需要一个将会满足我们限制的实现. 我发现了作为一个轻量级的 C++ 解决方案的实现 Simplex Noise for C++ and Python 并且开始试验结果.

译者注: 这里是简单噪声和 Perlin 噪声的效果对比图:

效果对比图:

simplexnoise.h 文件中对我们目前情况有用的函数是 scaled_octave_noise_3d, 它允许为三维坐标生成噪声, 充分满足我们沿着星球交点包裹纹理贴图的需求.

float scaled_octave_noise_3d( const float octaves,
                            const float persistence,
                            const float scale,
                            const float loBound,
                            const float hiBound,
                            const float x,
                            const float y,
                            const float z );

对每一个把位置映射到球体的顶点, 我用下面的函数为它应用了偏移(displacement):

void CalculateHeight( Vector3& vPosition )
{
    // Get the direction vector from the center of the sphere
    Vector3 vNormalFromCenter = vPosition;
    vNormalFromCenter.Normalize();

    // Variables for the noise
    static const float HEIGHT_MAX = 24.5f; // Planet Radius is 1,000.
    static const float HEIGHT_MIN = -31.0f;
    static const float NOISE_PERSISTENCE = 0.6f;
    static const float NOISE_OCTAVES = 8.0f;
    static const float NOISE_SCALE = 1.0f;

    // Generate the noise for the position
    float fNoise = scaled_octave_noise_3d( HEIGHT_OCTAVES, HEIGHT_PERSISTENCE, NOISE_SCALE, HEIGHT_MIN, HEIGHT_MAX, vPosition.x, vPosition.y, vPosition.z );

    // Keep ocean level as base level
    if ( fNoise <= -0.0f )
        fNoise = 0.0f;

    // Displace the position
    vPosition += vNormalFromCenter * fNoise;
}

这导致一个如本页第一幅图片所示的结果. 我在 0.0f 或比它小的位置对所有高度应用了 RGB(28, 107, 160), 对所有陆地层应用了 RGB(61, 182, 29).

注意高度的最小值和最大值. 因为地球大概 1/3 是陆地, 2/3 是水, 我决定用将会产生 33%-40% 陆地的数值来试验. 在试验过数值之后, 我发现 -31.024.5 产生很好的结果. 请随意试验. 另外, 我的星球半径是 1000, 因此这些值存在某种相关比例.

用这样一个快速解决方案来开始是相当令人满意的. 将来我希望能增加细节通过应用第二个噪声图, 更少的存留状态, 和/或 增加海平面以上的高度比例. 这将会生成额外的山脉和更少连贯的陆地板块(land masses).

下面是一个星球的示例, NOISE_SCALE = 2.5f:

截图:

应用一个种子数

正如我在本文开头所说, 生成器的一个需求是给定一个种子能够复现相同的结果. 当 libnoise 提供了一个 SetSeed 函数, 简易噪声(SimplexNoise)没有已实现的方法可用.

幸运的是实现一个方法非常容易. 在 simplexnoise.h 头文件中, 有一个数字数组用作一个排列表.

static const int perm[512] = { ... }

这个数组基本上包含了从 0255 随机生成的所有数字. 这个序列接着被复制一次来填满整个数组

通过从一个常量改变数组, 并且应用了下面这个函数, 你能轻易地为一个星球设置种子并且复制相同的结果:

// Variables
// perm - SimplexNoise's Permutation table
void set_seed( unsigned int seed )
{
    // Set the seed for random generator
    srand( seed );

    // Set up the random numbers table
    for ( int i = 0; i < 256; ++i )
    {
        // Put each number in once
        perm[ i ] = i;
    }

    // Randomize the random numbers table
    for ( int i = 0; i < 256; ++i )
    {
        // Replace current value with random value from the table
        int k = perm[ i ]; // current value

        // Random table cell
        int j = (int)random( 256 );

        // Replace two values
        perm[ i ] = perm[ j ];
        perm[ j ] = k;

        // The table repeats itself so just assign repeating values the same way
        perm[ 256 + i ] = perm[ j ];
        perm[ 256 + j ] = k;
    }
}

后续

这就是这篇文章的全部了, 在接下来的文章中, 我会关注光照, 大气散射, 生物群落生成, 星球颜色以及细节级别(Level of Details).

参考

原文: Planet Generation - Part II
Libnoise: Tutorial 8: Creating spherical planetary terrain
Perlin noise
Simplex Noise for C++ and Python
Simplex Noise Demystified pdf
GPU Gems 2: Chapter 26. Implementing Improved Perlin Noise

© 著作权归作者所有

FreeBlues
粉丝 99
博文 280
码字总数 493678
作品 0
其它
程序员
私信 提问
翻译: 星球生成 I

翻译: 星球生成 I 本文翻译自Planet Generation - Part I 译者: FreeBlues 以下为译文: 概述 我一直是一个过程内容生成的爱好者, 它允许你创建一个甚至不断改变的潜在内容无限的游戏. 它也补...

FreeBlues
2016/07/21
44
0
无鞘之刃/nomanssky2D

_ | | | | / | / || | _| | |/ | |/| |/ ` | '_ / _____ | |/ / | | || | | () | | | | (| | | | _ _) | <| || ||| _|_/|| ||_,|| ||//||_\_, | ___/ 一、前言 无人深空(NomansSky)是什么:......

无鞘之刃
2016/08/28
0
0
canvas绘制太阳系

原文地址:http://jeffzhong.space/2017/10/26/solar/ 学习canvas有一段时间了,顺便写个小项目练手,该项目用到的知识点包括: ES6面向对象 基本的三角函数 canvas部分有:坐标变换,渐变,...

Jeff.Zhong
2017/10/27
0
0
React Conf 2018 专题 —— React Today and Tomorrow PART II 视频中英双语字幕

距离React Conf 2018 已经将近一个月了,距离上个 React Conf 2018 的中英文双语视频发布也有两周的时间了,这两周,一直在进行Dan Abramov 的关于 React Hooks 提案部分演讲的字幕校对和翻译...

清秋
2018/11/27
0
0
LeetCode 136 Single Number(只出现一次的数字)

版权声明:转载请联系本人,感谢配合!本站地址:http://blog.csdn.net/nomasp https://blog.csdn.net/NoMasp/article/details/50686403 翻译 原文 分析 请参照上一题:LeetCode 260 Single...

nomasp
2016/02/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java通过ServerSocket与Socket实现通信

首先说一下ServerSocket与Socket. 1.ServerSocket ServerSocket是用来监听客户端Socket连接的类,如果没有连接会一直处于等待状态. ServetSocket有三个构造方法: (1) ServerSocket(int port);...

Blueeeeeee
今天
6
0
用 Sphinx 搭建博客时,如何自定义插件?

之前有不少同学看过我的个人博客(http://python-online.cn),也根据我写的教程完成了自己个人站点的搭建。 点此:使用 Python 30分钟 教你快速搭建一个博客 为防有的同学不清楚 Sphinx ,这...

王炳明
昨天
5
0
黑客之道-40本书籍助你快速入门黑客技术免费下载

场景 黑客是一个中文词语,皆源自英文hacker,随着灰鸽子的出现,灰鸽子成为了很多假借黑客名义控制他人电脑的黑客技术,于是出现了“骇客”与"黑客"分家。2012年电影频道节目中心出品的电影...

badaoliumang
昨天
16
0
很遗憾,没有一篇文章能讲清楚线程的生命周期!

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 简介 大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。 ...

彤哥读源码
昨天
18
0
jquery--DOM操作基础

本文转载于:专业的前端网站➭jquery--DOM操作基础 元素的访问 元素属性操作 获取:attr(name);$("#my").attr("src"); 设置:attr(name,value);$("#myImg").attr("src","images/1.jpg"); ......

前端老手
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部