新闻中心

c++如何实现一个简单的程序化生成(Procedural Generation)算法_c++柏林噪声应用【游戏开发】

2025-12-08
浏览次数:
返回列表
柏林噪声是一种可重复、平滑连续、可缩放的伪随机函数,适合生成自然地形与纹理;其核心是通过哈希坐标获取梯度、双线性插值及fade函数实现平滑过渡,并支持fbm多层叠加模拟多尺度特征。

c++如何实现一个简单的程序化生成(procedural generation)算法_c++柏林噪声应用【游戏开发】

用 C++ 实现简单的程序化生成,核心是用柏林噪声(Perlin Noise)生成自然、连续、可重复的伪随机地形或纹理。它比纯随机数更“有机”,适合做地形高度图、云层、火焰、纹理扰动等。

一、先理解柏林噪声的关键特性

柏林噪声不是“随机”,而是:
- 可重复:相同坐标输入,永远返回相同浮点值(利于多线程或重载世界);
- 平滑连续:输出值在空间中渐变,没有突兀跳跃;
- 可缩放(oct*e 控制):通过叠加不同频率/振幅的噪声层(fbm),模拟山脉、小丘、岩石细节等多尺度特征。

二、手写一个轻量级 2D 柏林噪声(适合学习和小项目)

不依赖外部库,用经典 Ken Perlin 原始思路简化实现(非最高效,但逻辑清晰):

  • 定义一个 256 项的随机排列表(perm),用于哈希坐标 → 随机梯度方向;
  • 对每个整数格子角点预设一个单位梯度向量(如 (1,1), (-1,1) 等);
  • 对输入点 (x, y),找到它所在的单位格子(floor(x), floor(y));
  • 计算该点到四个角点的向量,并与对应梯度点乘,得到四个“影响值”;
  • 用平滑插值函数(如 3t²−2t³)混合这四个值,得到最终噪声值 ∈ [-1, 1]。

代码片段(精简版,含注释):

#include <cmath>
#include <vector>
#include <random>
<p>class SimplexNoise { // 注:这里用“SimplexNoise”名更准确,但初学可用 Perlin 思路理解
std::vector<int> perm = { /<em> 256 个 0~255 的 shuffle 后排列 </em>/ };</p><pre class='brush:php;toolbar:false;'>float fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); }
float lerp(float a, float b, float t) { return a + t * (b - a); }
float grad(int hash, float x, float y) {
    int h = hash & 3;
    float u = h < 2 ? x : y;
    float v = h < 2 ? y : x;
    return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}

public: SimplexNoise() { std::vector p(256); for (int i = 0; i

float noise(float x, float y) const {
    int X = (int)floor(x) & 255;
    int Y = (int)floor(y) & 255;
    x -= floor(x); y -= floor(y);
    float u = fade(x), v = fade(y);

    int A = perm[X] + Y, AA = perm[A] & 255, AB = perm[A+1] & 255;
    int B = perm[X+1] + Y, BA = perm[B] & 255, BB = perm[B+1] & 255;

    float x1 = grad(perm[AA], x, y);
    float x2 = grad(perm[BA], x-1, y);
    float y1 = lerp(x1, x2, u);

    float x3 = grad(perm[AB], x, y-1);
    float x4 = grad(perm[BB], x-1, y-1);
    float y2 = lerp(x3, x4, u);

    return lerp(y1, y2, v);
}

// fbm:叠加多层噪声(oct*es)
float fbm(float x, float y, int oct*es = 4, float lacunarity = 2.0f, float persistence = 0.5f) const {
    float total = 0.0f;
    float frequency = 1.0f;
    float amplitude = 1.0f;
    float norm = 0.0f;
    float sum = 0.0f;

    for (int i = 0; i < oct*es; ++i) {
        sum += noise(x * frequency, y * frequency) * amplitude;
        norm += amplitude;
        amplitude *= persistence;
        frequency *= lacunarity;
    }
    return sum / norm;
}

};

标贝悦读AI配音 标贝悦读AI配音

在线文字转语音软件-专业的配音网站

标贝悦读AI配音 78 查看详情 标贝悦读AI配音

三、生成地形高度图(2D 数组示例)

用 fbm 填充一个 128×128 的 heightmap:

  • 遍历每个 (i, j),映射为世界坐标(如 i*0.05f, j*0.05f);
  • 调用 fbm(x, y),结果归一化到 [0.0, 1.0] 或 [-0.5, 0.5];
  • 可加偏移/缩放控制山峰高度,例如:height[i][j] = (fbm(i*0.03f,j*0.03f) + 0.7f) * 0.5f;
  • 后续可按高度阈值划分:0.6→岩石/雪地。

四、实用技巧 & 注意事项

  • 种子控制:把 perm 表的 shuffle 种子(如 default_random_engine(1234))换成可配置参数,就能切换不同世界;
  • 性能优化:实际项目建议用开源库如 webgl-noise 的 C++ 移植版 或 stegu/perlin-noise,支持 SIMD 和 3D/4D;
  • 避免“网格感”:确保采样间距远小于噪声基频(比如用 0.01–0.05 缩放因子),否则会看到明显方块;
  • 结合其他技术:噪声输出可作为 mask 输入到 Voronoi、Worley 噪声,或驱动 Marching Squares 生成等高线。

基本上就这些。从一个可运行的 fbm 函数开始,再叠加规则(如河流侵蚀、生物群系分布),就能搭建出有表现力的程序化世界。不复杂但容易忽略的是——噪声只是“原料”,真正让生成有意义的,是你怎么解释和组合它。

以上就是c++++如何实现一个简单的程序化生成(Procedural Generation)算法_c++柏林噪声应用【游戏开发】的详细内容,更多请关注其它相关文章!


# 的是  # seo效能  # seo logo  # 物流网络推广有哪些网站  # seo企业有必要做吗  # 单页网站建设的介绍  # 蚌埠网站优化多少钱  # 专业网站优化seo  # 高青网站建设哪家好  # 婚纱摄影怎么做网站推广  # 诚人网站建设方案  # 插值  # c++  # 清空  # 如何将  # 转换为  # 自定义  # 就能  # 多线程  # 如何实现  # 排列  # 游戏开发  # 程序化生成 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: age动漫网站入口 age动漫官网直接访问入口  CSS条件样式无法按设备触发怎么排查_media条件语句正确设置解决触发问题  如何在低配置电脑上搭建轻量级J*a环境_占用更小的环境选择技巧  海棠电脑版入口_通过电脑访问海棠官网阅读  Golang如何实现Web文件静态资源服务器_Golang静态资源服务器开发与实践  抖音创作助手登录入口_抖音创作辅助工具官网直达  Sublime怎么配置Nim语言环境_Sublime Nim代码高亮与补全  sublime怎么格式化代码_sublime代码美化与一键排版插件配置  如何将HTML表格多行数据保存到Google Sheets  Go语言中JSON数据解析与字段访问教程  深入理解Go语言中的指针类型:以*string为例  php源码怎么在电脑上测试_电脑测试php源码方法步骤【教程】  J*a实现学校排课程序_面向对象结构化项目示例  如何将HTML表格多行数据保存到Google Sheet  怎样使用“本地安全策略”提升Windows安全性_Secpol.msc配置指南【高手】  邮编格式怎么匹配地址_根据邮编格式快速匹配详细地址的技巧  蛙漫漫画官网在线入口 蛙漫全本漫画免费阅读平台  Golang如何处理RPC请求负载均衡_Golang RPC请求负载均衡策略与实践  夸克AO3官网入口_AO3镜像网站2025推荐  C++指针和引用有什么区别_C++内存管理核心概念深度解析  Win10桌面图标出现小盾牌怎么办 Win10去除UAC图标教程【解决】  黑猫投诉统一入口官网 消费者权益保护投诉平台  TikTok搜索结果不显示如何解决 TikTok搜索刷新优化方法  Win10文件资源管理器“此电脑”分组怎么关 Win10恢复经典视图【技巧】  深入理解J*a编译器的兼容性选项:从-source到--release  铁路12306官网网页端快速入口 铁路12306官方首页登录教程  c++20的std::jthread是什么_c++可中断线程与RAII式管理  马斯克:Optimus 人形机器人复数形式为 Optimi  J*a里如何使用N*igableMap进行导航操作_可导航Map操作技巧解析  俄罗斯Yandex搜索引擎入口_Yandex官网免登录一键访问  Golang如何使用net/url解析URL_Golang URL解析与处理方法  Windows7怎么硬盘安装 Windows7提取ISO镜像到非系统盘并运行setup.exe实现硬盘直装【教程】  J*aScript动态修改指定div内所有a标签样式指南  Win11怎么设置鼠标主按键_Win11鼠标左右键功能互换  深入理解与实现最大堆的Heapify过程:常见错误与修正  《北京人工智能产业白皮书(2025)》发布:全年核心产值预计突破 4500 亿元  J*aScript类型检查_j*ascript代码规范  Win11怎么关闭快速启动_Win11彻底关机设置教程  jQuery Mask 插件中实现电话号码固定前导零的教程  深入理解Go语言中Map值与方法接收器的交互:为什么需要临时变量  如何修改开机登录密码_Windows账户安全设置超详细教程【必学】  Go语言中Map值调用指针接收器方法的限制与应对  msn官网入口地址手机版 msn官方网站手机最新链接  俄罗斯方块最新版入口 俄罗斯方块在线玩官网入口  DLsite中文平台入口 DLsite官网内容在线查看  React Router v6 教程:构建认证保护的私有路由与重定向策略  LINUX怎么设置定时任务_LINUX crontab配置教程  中兴BladeV30怎样用测距估书架层高_iPhone中兴BladeV30测距估书架层高【家装参考】  如何使用Node.js csv 包按条件移除含空字段的CSV记录  《明末:渊虚之羽》设计师谈设计角色:那会刚毕业 充满激情 

搜索