- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我一直在使用 Unity 游戏引擎开发一款游戏,我希望它能够将分页地形用于无限世界(如今的常见主题)。我的地形生成器专门使用 perlin 噪声。但此时,开发已被一个错误严重拖慢:页面边缘不匹配,甚至没有关闭。问题出在我生成地形的代码中,或者可能出在每次我完成页面生成时运行的另一段代码中。但问题肯定不在 unity 函数调用中,所以即使你不熟悉 unity 也可以帮助我。
可能的原因...1) 为每页的错误位置采样的 Perlin 噪音,数学失败。2) 在页面生成之间重新播种随机数生成器。3) Perlin 噪声在页面生成之间重新播种。4)?我不知道。
注意:查看所有其他代码,我几乎排除了数字 2 和 3。我只为每个生成器播种一次,Unity 不会恰好在生成器运行之间重新播种随机数。
实际上,如果您能描述一种调试方法,使这更容易,请指教。从长远来看,这对我的帮助会大得多。
这是我为每个页面运行一次的代码,带有完整注释,因此您不必了解 Unity3D...
/* x and y are the indices of the tile being loaded. The game maintains a
square of pages loaded, where the number of pages per side is equal to
loadSquares (see below). x and y are the indices of the page to generate
within that square. */
public void generate(int x, int y)
{
/* pagePos represents the world x and y coordinates of the bottom left
corner of the page being generated. This is given by...
new Vector2((-(float)loadSquares / 2.0f + x + xCoord) * tileSize,
(-(float)loadSquares / 2.0f + y + zCoord) * tileSize);
This is because the origin tile's center is at 0, 0. xCoord represents
the tile that the target object is on, which is what the loaded square
is centered around. tileSize is the length of each side of each tile.
*/
Vector2 pagePos = getPagePos(x, y);
//Here I get the number of samples x and y in the heightmap.
int xlim = td[x,y].heightmapWidth;
int ylim = td[x,y].heightmapHeight;
//The actual data
float[,] array = new float[xlim, ylim];
//These will represent the minimum and maximum values in this tile.
//I will need them to convert the data to something unity can use.
float min = 0.0f;
float max = 0.0f;
for(int cx = 0; cx < xlim; cx++)
{
for(int cy = 0; cy < ylim; cy++)
{
//Here I actually sample the perlin function.
//Right now it doesn't look like terrain (intentionally, testing).
array[cx,cy] = sample(
new Vector3((float)cx / (float)(xlim - 1) * tileSize + pagePos.x,
(float)cy / (float)(ylim - 1) * tileSize + pagePos.y,
122.79f));
//On the first iteration, set min and max
if(cx == 0 && cy == 0)
{
min = array[cx,cy];
max = min;
}
else
{
//update min and max
min = Mathf.Min(min, array[cx,cy]);
max = Mathf.Max(max, array[cx,cy]);
}
}
}
//Set up the Terrain object to receive the data
float diff = max != min ? max - min : 10.0f;
tr[x,y].position = new Vector3(pagePos.x, min, pagePos.y);
td[x,y].size = new Vector3(tileSize, diff, tileSize);
//Convert the data to fit in the Terrain object
/* Unity's terrain only accepts values between 0.0f and 1.0f. Therefore,
I shift the terrain vertically in the code above, and I
squish the data to fit below.
*/
for(int cx = 0; cx < xlim; cx++)
{
for(int cy = 0; cy < ylim; cy++)
{
array[cx,cy] -= min;
array[cx,cy] /= diff;
}
}
//Set the data in the Terrain object
td[x,y].SetHeights(0, 0, array);
}
}
有趣且可能很重要的细节:瓷砖与 x/z 方向上与其角相邻的瓷砖正确连接。每当图 block 不具有相同的 x-to-z 增量时,就会发生采样偏移。在下图中,右侧图 block 是另一个图 block 的 +x 和 +z。具有这种关系的所有图 block 都已正确连接。
这是以 zip 格式上传的项目文件。告诉我它是否不工作或什么... http://www.filefactory.com/file/4fc75xtd3yzl/n/FPS_zip
要查看地形,请在切换到 testScene 后按“播放”(如果它没有从那里开始)。 GameObject 生成数据和地形对象(它具有来自 scripts/General/附件的 RandomTerrain 脚本)。您可以从那里将参数修改为 perlin 噪声。请注意,目前只有第一个 perlin octave,o_elevator 在地形生成中处于事件状态。为了解决这个故障,所有其他公共(public) perlin octave 变量都没有影响。
最佳答案
TL;DR:您需要删除 getTargetCoords 并使用 tr[x,y].position = new Vector3(pagePos.y, 0.0f, pagePos.x)
。
如何实现上述目标:一次在一维中工作。这意味着转动这个(从你附加的统一代码):
array[cx,cy] = sample(
new Vector3((float)cx * tileSize / (float)(xlim - 1) + pagePos.x, 0.0f,
(float)cy * tileSize / (float)(ylim - 1) + pagePos.y));
进入这个:
array[cx,cy] = sample(
new Vector3(
(float)cx * tileSize / (float)(xlim - 1) + pagePos.x,
0.0f,
0.0f
)
);
我很快意识到您的 getPagePos
有问题,因为它从 getTargetCoords
添加了一个值,而该函数使用了由 设置的位置getPagePos
函数!圈子里的圈子,伙计们。
protected void getTargetCoords()
{
xCoord = Mathf.RoundToInt(target.position.x / tileSize);
zCoord = Mathf.RoundToInt(target.position.z / tileSize);
}
所以让我们丢掉那个函数和对它的引用。事实上,让我们暂时简化 getPagePos
:
protected Vector2 getPagePos(int x, int y)
{
return new Vector2( 0.0f,0.0f);
}
天哪,TAWNOS 疯了?!嗯,是的,但这不是重点。假设您的样本函数是正确的(我根据您的断言授予您一个假设),那么我们应该从获取简单值(零!)开始并验证添加的每个额外假设。
简化了getPagePos
,让我们再看一下(float)cx * tileSize/(float)(xlim - 1) + pagePos.x
。它想做什么?好吧,它似乎试图通过从图 block 的原点偏移来找到当前样本的世界坐标点。让我们验证这是一个真实的假设:xLim
样本分布在 tileSize
单位上,因此世界坐标中的每个步长大小都是 tileSize/xLim
。将其乘以当前值将得到我们的偏移量,因此这段代码看起来是正确的。
现在,让我们获取一个简单的图 block 偏移量并查看所有内容是否匹配。我不会尝试将水滴居中放置在所有图 block 的中间,而是进行一个简单的网格偏移(稍后可以对其进行调整以恢复居中)。
return new Vector2(
tileSize * (float)x,
0.0f
);
运行此程序时,您可能很快就会发现问题所在。底部边缘映射旁边的图 block 的顶部边缘,而不是右边缘与左边缘匹配。无需深入研究,这可能是由您的采样方法的工作方式引起的。我不确定。这是更新后的功能:
protected Vector2 getPagePos(int x, int y)
{
float halfTile = loadSquares / 2.0f;
return new Vector2(
(-halfTile * tileSize) + (x * tileSize),
(-halfTile * tileSize) + (y * tileSize)
);
}
public void generate(int x, int y)
{
if(x >= loadSquares || x < 0 || y >= loadSquares || y < 0) return;
t[x,y] = Terrain.CreateTerrainGameObject(new TerrainData()).GetComponent<Terrain>();
t[x,y].name = "Terrain [" + x + "," + y + "]";
td[x,y] = t[x,y].terrainData;
td[x,y].heightmapResolution = resolution;
tr[x,y] = t[x,y].transform;
Vector2 pagePos = getPagePos(x, y);
//Actual data generation happens here.
int xLim = td[x,y].heightmapWidth;
int yLim = td[x,y].heightmapHeight;
float[,] array = new float[xLim, yLim];
float min = int.MaxValue;
float max = int.MinValue;
for(int cx = 0; cx < xLim; cx++)
{
for(int cy = 0; cy < yLim; cy++)
{
array[cx,cy] = sample(
new Vector3(
(float)cx * (tileSize / (float)(xLim - 1)) + pagePos.x,
0.0f,
(float)cy * (tileSize / (float)(yLim - 1)) + pagePos.y
)
);
if(min > array[cx,cy])
min = array[cx,cy];
if(max < array[cx,cy])
max = array[cx,cy];
}
}
//Set up the Terrain object to receive the data
float diff = max != min ? max - min : 10.0f;
tr[x,y].position = new Vector3(pagePos.y, min, pagePos.x);
td[x,y].size = new Vector3(tileSize, diff, tileSize);
//Convert the data to fit in the Terrain object
for(int cx = 0; cx < xLim; cx++)
{
for(int cy = 0; cy < yLim; cy++)
{
array[cx,cy] -= min;
array[cx,cy] /= diff;
}
}
//Set the data in the Terrain object
td[x,y].SetHeights(0, 0, array);
}
关于c# - Perlin 地形页面不匹配 : elusive bug,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11453809/
示例:https://www.terraform.io/docs/providers/kubernetes/r/service_account.html 我们看到了: resource "kubern
示例:https://www.terraform.io/docs/providers/kubernetes/r/service_account.html 我们看到了: resource "kubern
我有 5 个 keyvaults,有 5 个 secret ,问题是我不希望我的 terraform 文件有 10 个这样的数据 block : data "azurerm_key_vault" "k
我之前在我的 TF 代码中使用过这个: count = "${var.whatever == "true" ? 1 : 0}" 这非常适合我想要使用的东西。但是,我正在考虑如何最好地使用类似于说的
我之前在我的 TF 代码中使用过这个: count = "${var.whatever == "true" ? 1 : 0}" 这非常适合我想要使用的东西。但是,我正在考虑如何最好地使用类似于说的
我想创建一个上面有山的地形,使用一个非常基本的原理,如这个高度映射所示: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
根据文档,使用terraform,我能够在 digital ocean 上创建一个小滴: resource "digitalocean_volume" "foobar" { region
在 Terraform 中,我正在尝试创建一个模块,其中包含一个带有变量键的 map 。我不确定这是否可能,但我尝试了以下但没有成功。 resource "aws_instance" "web" {
我正在使用Box2d进行自行车物理游戏,Box2d可以让你拥有8点或更少的凸多边形的固定装置,有人知道更简单的方法吗除了制作一大堆固定装置之外,还有复杂的凹形地形?或者这是唯一的方法? 任何想法、指示
我正在尝试在 LWJGL 中制作 2D 游戏。我在地形生成方面遇到问题。 我目前有一个生成地形的算法,但它总是随机的,我永远无法再次获得相同的世界,我想制作一个基于生成 x 和 y 坐标的算法给定的数
我在使用 libgdx 和 box2d 进行卡车游戏。 在我的游戏中 1 米 = 100 像素。 我的 2d 地形是由我生成的,由点组成。 我所做的是为整个多边形制作了一个多边形区域并使用了textu
我有一个 3D boolean 值数组,代表一些 3D 地形。目前我可以通过在数组中的 x y 和 z 指定的位置绘制一个点来绘制它,它看起来像这样。 我想不通的是如何使用三角形绘制它,所以它看起来像
我读过很多关于这个概念的教程,但我觉得它们都没有深入探讨如何做到这一点。我已经知道 3D 编程(光栅化、投影矩阵等)、光线转换(使用欧几里得几何和矢量)和光线追踪如何工作,我只需要知道如何使用柏林噪声
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 9 年前。 Improve this qu
我正在做一些地形渲染,但遇到了一些麻烦。在这个时间点,我只是镶嵌顶点补丁,然后用高度图替换它们。我目前的问题是渲染看起来很时髦。我已经调试了一段时间,看起来这是深度缓冲区的问题。除此之外,我对正在发生
在 OpenGL 中用四边形制作地形纹理的最佳方法是什么?我有大约 30 种不同的纹理我想为我的地形(每种地形类型 1 个纹理,所以 30 种地形类型)并且希望在任何两个地形之间平滑过渡。 我一直在浏
执行时 terraform plan我没有错误,但是当我执行 terraform apply 时我收到以下错误。 地形计划输出:- + aws_route53_record.alm_route_rec
执行 terraform init 时出现以下错误升级到 0.12.2 后的命令版本。早期的相同代码在 terraform 中运行良好,没有问题 0.11.10版本。 alb.tf tags {
terraform init成功初始化但卡在 terraform 计划上。 该错误与功能块有关。我不确定在哪里添加功能块: Insufficient features blocks (source c
我正在使用 terraform 版本 0.14.3。我有一个用于创建 Azure 网络接口(interface)卡的模块,如下所示: resource "azurerm_network_interfa
我是一名优秀的程序员,十分优秀!