翻译: 星球生成 II
翻译: 星球生成 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.0
到 24.5
产生很好的结果. feel free to, 另外, 我的星球半径是 1000
, 因此这些值存在某种相关比例.
用这样一个快速解决方案来开始是相当令人满意的. 将来我希望能增加细节通过应用第二个噪声图, 更少的存留状态, 和/或
增加海平面以上的高度比例. 这将会生成额外的山脉和更少连贯的陆地板块(land masses).
下面是一个星球的示例, NOISE_SCALE = 2.5f:
截图:
应用一个种子数
正如我在本文开头所说, 生成器的一个需求是给定一个种子能够复现相同的结果. 当 libnoise
提供了一个 SetSeed
函数, 简易噪声(SimplexNoise)没有已实现的方法可用.
幸运的是实现一个方法非常容易. 在 simplexnoise.h
头文件中, 有一个数字数组用作一个排列表.
static const int perm[512] = { ... }
这个数组基本上包含了从 0
到 255
随机生成的所有数字. 这个序列接着被复制一次来填满整个数组
通过从一个常量改变数组, 并且应用了下面这个函数, 你能轻易地为一个星球设置种子并且复制相同的结果:
// 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
翻译: 星球生成 II的更多相关文章
- 翻译: 星球生成 I
翻译: 星球生成 I 本文翻译自Planet Generation - Part I 译者: FreeBlues 以下为译文: 概述 我一直是一个过程内容生成的爱好者, 它允许你创建一个甚至不断改变的 ...
- 【翻译】生成 Timestamps / Watermarks
本文翻译自flink官网:https://ci.apache.org/projects/flink/flink-docs-release-1.7/dev/event_timestamps_waterm ...
- 机器指令翻译成 JavaScript —— 终极目标
上一篇,我们顺利将 6502 指令翻译成 C 代码,并演示了一个案例. 现在,我们来完成最后的目标 -- 转换成 JavaScript. 中间码输出 我们之所以选择 C,就是为了使用 LLVM.现在来 ...
- TensorFlow练习24: GANs-生成对抗网络 (生成明星脸)
http://blog.topspeedsnail.com/archives/10977 从2D图片生成3D模型(3D-GAN) https://blog.csdn.net/u014365862/ar ...
- qt中qlineedit和qtextedit右键菜单翻译成中文
没有linguist和lupdate等命令需要安装Linguist: 在Terminal中输入: sudo apt-get install qt4-dev-tools qt4-doc qt4-qtco ...
- Qt 本地化(翻译)
Qt 本地化(翻译) 翻译流程大致是这样的:首先源代码产生 ts 文件,然后送给 Qt Linguist(Qt 语言家)这个 Qt 自带的小工具进行处理产生 qm 翻译文件,最后源代码里加载这个 qm ...
- Linux内核调试方法总结
Linux内核调试方法总结 一 调试前的准备 二 内核中的bug 三 内核调试配置选项 1 内核配置 2 调试原子操作 四 引发bug并打印信息 1 BUG()和BUG_ON() 2 ...
- EF里Guid类型数据的自增长、时间戳和复杂类型的用法
通过前两章Lodging和Destination类的演示,大家肯定基本了解Code First是怎么玩的了,本章继续演示一些很实用的东西.文章的开头提示下:提供的demo为了后面演示效果,前面代码有些 ...
- 解析大型.NET ERP系统 多国语言实现
实现多国语言有许多种实现方案,无外乎是一种字符串替换技术,将界面控件的文本标签替换成相应语言的文字..NET Windows Forms实现多国语言的方法有以下几种: 1 .NET的方案,使用资源文件 ...
随机推荐
- Hibernate利用纯sql
String hql = "select * from shop where shop.strid in(select strid from moneythreeshop where mon ...
- mabatis报错 Result Maps collection already contains value for gamedataserver.dao.one.ChargeRecordMapper.BaseResultMap
1.解决这种报错看看英文"already ",也就是已经存在,其实是因为存在了两个id相同的返回,以下可以看看,根据这种例子看看自己项目是不是这种问题
- C语言:一个能自动生成小学四则运算题目的程序
完成这个程序,半个小时内完成了,这个程序,可以自动生成小学简易的四则运算,提供菜单让用户选择,然后判断加减乘除,判断答对答错的题目个数,用户同时也可以重新选择继续答题或重新选择或退出程序. 源程序: ...
- 结对作业(web)
作业源代码地址:https://git.coding.net/mal123/arithmetic.git 网页版测试地址:http://47.93.197.5:8080/mal_war_explode ...
- 【大数据应用技术】作业八|爬虫综合大作业Molly134
本次作业的要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3075 前言:本次作业是爬取CBO中国票房2010-2019年每年 ...
- #Leetcode# 817. Linked List Components
https://leetcode.com/problems/linked-list-components/ We are given head, the head node of a linked l ...
- [转帖] go的import 语法
package 的导入语法写 Go 代码的时经常用到 import 这个命令用来导入包,参考如下: import( "fmt" ) 然后在代码里面可以通过如下的方式调用: fmt. ...
- maven下载、安装、卸载以及MyEclipse配置maven
maven下载 官网下载:http://maven.apache.org/download.cgi 点击链接为官网下载页面,翻到下图所示位置,点击红框选项即可下载 maven安装 1.解压 ...
- iOS 数据库sqlite完整增删改查操作
1: 创建数据库表格 1.1 — 表格创建使用一个数据库软件快速创建:软件大小14.3M; 下载地址:http://pan.baidu.com/s/1qWOgGoc; 表格创建-> 打开软件,点 ...
- Spring点滴七:Spring中依赖注入(Dependency Injection:DI)
Spring机制中主要有两种依赖注入:Constructor-based Dependency Injection(基于构造方法依赖注入) 和 Setter-based Dependency Inje ...