【低配】柏林噪声地形生成

渲染效果

源代码

作者将柏林噪声用了python和JavaScript两种语言实现

两种语言效果基本一样

python

import random

def ave(a, b):# 计算平均值
    return round((a + b) / 2)

def ave_list(lst):# 计算一个全为数字的列表的平均值
    return round(sum(lst) / len(lst))

def smooth_list(input_list, width)->list:# 将整个列表进行平滑处理
    result_list = input_list.copy()
    for i in range(len(input_list)):
        if i != 0 and i % width != 0 and i != len(input_list) - 1:
            neighbors_sum = input_list[i - 1] + input_list[i + 1]
            before_width = max(0, i - width)
            after_width = min(len(input_list) - 1, i + width)
            neighbors_sum += input_list[before_width] + input_list[after_width]
            result_list[i] = neighbors_sum / 4
    return result_list

def random_map(width, height, average, gaocha)->list:
    '''
    随机生成
    '''
    '''将所有输入值转换为int类型,放置后期报错'''
    average = int(average)
    width = int(width)
    height = int(height)
    gaocha = int(gaocha)

    print('开始随机生成!')# 打印一条消息方便调试
    next_value = 0# 下一个列表值的存档
    return_list = []# 返回的列表最初为空
    '''第一项:在平均值的基础上加或减一个“gaocha”范围内的数'''
    return_list.append(min(height, max(0, average + random.randint(-gaocha, gaocha))))

    '''生成列表1~256项(第一排)'''
    while len(return_list) < width:# 意思很简单,当列表长度小于宽度(256)时就重复生成
        '''控制整个列表的平均值,避免数值一直上升或下降'''
        if ave_list(return_list) >= average + gaocha:# 如果整个列表的平均值大于等于传入的平均值+高差(整体太高了)就只能在列表最后一项的基础上减去一个小于高差(当然大于0)的数
            next_value = return_list[-1] + random.randint(-gaocha, 0)
        elif ave_list(return_list) < average - gaocha:# 反之
            next_value = return_list[-1] + random.randint(0, gaocha)
        else:# 否则加或减都行
            next_value = return_list[-1] + random.randint(-gaocha, gaocha)
        next_value = min(height, max(0, next_value))
        if next_value > 0 and next_value <= height:# 为了防止亮度太高或太低(负数),检测next_value的值是否符合要求
            return_list.append(next_value)
    
    '''生成257以及以后的项'''
    while len(return_list) / width < width:# 当行数小于给定width时就不断生成
        return_list.append(return_list[-1] + random.randint(-gaocha, gaocha))
        '''分别生成每一行'''
        while len(return_list) % width != 0:
            '''根据不同的列表平均值情况“分类讨论”
            唯一的不同就是,257及以后的项需要考虑到上方一行自己对应的位置(前面第256项)和左边(上一项)'''
            if ave_list(return_list) >= average + gaocha:
                next_value = ave(return_list[-1], return_list[-1 - width]) + random.randint(-gaocha, 0)
            elif ave_list(return_list) < average - gaocha:
                next_value = ave(return_list[-1], return_list[-1 - width]) + random.randint(0, gaocha)
            else:
                next_value = ave(return_list[-1], return_list[-1 - width]) + random.randint(-gaocha, gaocha)
            if next_value > 0 and next_value <= height:
                return_list.append(next_value)
    return smooth_list(return_list, width)# 最后返回之前再次平滑一下列表

# 示例
map = random_map(256, 63, 10, 5)

JavaScript 

function random(min, max) {
   return Math.round(Math.random() * (max - min) + min)
}
function ave(a,b) {
   return Math.round((a+b)/2)
}
function ave_list(list){
   let sum = 0;
   for(let i=0;i<list.length;i++){
      sum+=list[i];
   }
   return Math.round(sum/list.length);
}
function smoothList(inputList, width) {
	let resultList = inputList.slice();  // 创建一个副本,以免修改原始列表
 
	for (let i = 0; i < inputList.length; i++) {
	  if (i !== 0 && i % width !== 0 && i !== inputList.length - 1) {  // 只处理非边缘和指定间隔的项
		 let neighborsSum = inputList[i-1] + inputList[i+1];
		 let beforeWidth = Math.max(0, i-width);
		 let afterWidth = Math.min(inputList.length-1, i+width);
		 neighborsSum += inputList[beforeWidth] + inputList[afterWidth];
		 resultList[i] = neighborsSum / 4;  // 将当前项替换为相邻项和指定间隔项的平均值
	  }
	}
	return resultList;
 }

// 柏林噪声地形生成
/**
 * @description 生成柏林噪声地形
 * @param {number} width 长
 * @param {number} height 宽
 * @param {number} average 平均高度
 * @param {number} gaocha 最大高差
 */
async function randomMap(width, height, average, gaocha) {
    await sleep(1000)
	var nextValue = 0;
    let return_list = [];
    return_list.push(Math.min(height, Math.max(0, average + random(-gaocha, gaocha))));
    while (return_list.length < width) {
		if(ave_list(return_list)>=average+gaocha){
			nextValue = return_list[return_list.length - 1] + random(-gaocha, 0);
		}
		else if(ave_list(return_list)<average-gaocha){
			nextValue = return_list[return_list.length - 1] + random(0, gaocha);
		}
		else{
			nextValue = return_list[return_list.length - 1] + random(-gaocha, gaocha);
		}
        nextValue = Math.min(height, Math.max(0, nextValue));
        if(nextValue>0&&nextValue<=height){
            return_list.push(nextValue);
        }
    }
	while(return_list.length/width < width){
		return_list.push(return_list[return_list.length-1]+random(-gaocha, gaocha))
		while(return_list.length%width!=0){
			if(ave_list(return_list)>=average+gaocha){
                nextValue = ave(return_list[return_list.length-1],return_list[return_list.length-width])+random(-gaocha, 0)
			}
			else if(ave_list(return_list)<average-gaocha){
                nextValue = ave(return_list[return_list.length-1],return_list[return_list.length-width])+random(0, gaocha)
			}
			else{
				nextValue = ave(return_list[return_list.length-1],return_list[return_list.length-width]+random(-gaocha, gaocha))
			}
            if(nextValue>0&&nextValue<=height){
                return_list.push(nextValue);
                if(return_list.length%50==0){
                    await sleep(1)
                }
            }
		}
	}
    return smoothList(return_list,width)
}

// 示例
map = randomMap(256, 63, 10, 5)

调用

ccw共创世界

将python代码进行一点小修改后弄到共创世界里面,用画笔呈现结果:

共创世界:《[开源]初级柏林噪声》

dao3.fun神奇代码岛

将JavaScript代码进行修改后弄到神奇代码岛的地图作品里面,可以实现3D渲染

神奇代码岛 (dao3.fun)(代码未开源,详情见链接)

原理

单看代码似乎不那么好理解,我们通过文字来讲解一下!

举个例子:我们将一个256*256(=65536,也可以是其他尺寸,具体尺寸依照传入的width值)的方形区域存储在一个长65536项的列表里

那么,每一项分别代表那一个地方呢?

举个栗子:第1项代表第一行的最左边的那个位置,第256项代表第一行最右边的位置;第257项代表第2行最左边的位置……第65536项代表最右下角的位置

也可以通过下方表格来理解(每个数字代表列表的第几项):

1

2

3

4

...

256

257

258

259

260

...

512

513

514

515

516

...

768

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

65281

65282

65283

65284

...

65536

那么,我们现在要做的就是生成这个超级大的列表了!

(生成列表的原理在上方python源代码中通过注释解释)

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
柏林噪声算法是一种用于生成2D地图的算法。它是由柏林数学家卡尔·维特所提出的。该算法的基本原理是通过一系列随机数生成器产生噪声,在二维空间中形成连续的噪声图案。 柏林噪声算法的过程可以简单概括为以下几个步骤: 1. 确定地图大小和分辨率:首先需要确定生成地图的大小和分辨率,即地图的宽度和高度,以及像素的数量。 2. 创建随机数生成器:使用随机数生成器产生随机数序列,这些随机数将用于生成噪声地图。柏林噪声算法通常使用梅森旋转算法或其他类似的高质量随机数生成器。 3. 生成噪声图案:按照一定的规则和算法,使用随机数生成生成噪声图案。柏林噪声算法通常使用渐变产生随机数的方法,即每个点的随机数值是由其周围点的随机数值决定的,通过对这些值进行插值计算得到最终的噪声图案。 4. 进行后处理:得到的噪声图案可能会有一些不合理或不自然的地方,需要进行后处理来修正。常见的后处理方法包括平滑、调整亮度和对比度等。 5. 输出地图:最终生成的2D地图可以输出为图片文件或其他形式的图形数据,供使用者进行进一步处理或应用。 柏林噪声算法生成的2D地图具有丰富的细节和真实感,可以应用于游戏开发、地理信息系统等领域。它是一种有效而常用的生成地图的算法,被广泛应用于计算机图形学和计算机模拟领域。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值