使用(4D?)噪声为 UV 球体制作动画
Animate an UV sphere with (4D?) noise
我正在使用 libnoise 的 C# 端口和 XNA(我知道它已经死了)来生成行星。
libnoise中有一个function接收球面顶点坐标(经纬度)和returns一个随机值(从-1到1)
因此,使用该值,我可以更改球体表面每个顶点的高度(高度),创建一些高度,模拟行星表面(我不是简单地在周围包裹纹理球体,我实际上是从头开始创建每个顶点)。
我所拥有的示例:
现在我想为球体设置动画,like this
但事实是,libnoise 仅适用于 3D 噪声。
"planet" 函数将纬度和经度映射到立方体的 XYZ 坐标。
而且我相信,要像我想要的那样为球体设置动画,我需要一个额外的坐标作为 "time" 维度。我对吗?或者是否可以使用 libnoise 提供的功能来做到这一点?
OBS:正如我提到的,我使用的是 UV 球体,而不是 icosphere 或球形立方体。
编辑:这是 libnoise 用来将 lat/long 映射到 XYZ 的算法:
public double GetValue(double latitude, double longitude) {
double x=0, y=0, z=0;
double PI = 3.1415926535897932385;
double DEG_TO_RAD = PI / 180.0;
double r = System.Math.Cos(DEG_TO_RAD * lat);
x = r * System.Math.Cos(DEG_TO_RAD * lon);
y = System.Math.Sin(DEG_TO_RAD * lat);
z = r * System.Math.Sin(DEG_TO_RAD * lon);
return GetNoiseValueAt(x, y, z);
}
一个n维的噪声函数有n个独立的输入(i0, i1, ..., in-1, in) & returns 一个值v,因此3D噪声足以生成随时间变化的高度图。在您的情况下,输入是经度、纬度和时间,输出是高度偏移。
简单的通用算法是:
at each time step (t){
for each vertex (v) on a sphere centered on some point (c){
calculate the longitude & latitude
get the scalar noise value (n) for the longitude, latitude & time
calculate the new vertex position (p) as follows p = ((v-c)n)+c
}
}
注意:这假设您不是 replacing/modifiying 原始顶点值。您可以保存它们的副本(使用更少的计算,但更多的内存)或根据与 c 的距离重新计算它们(使用更少的内存,但更多的计算)。此外,您可能会通过计算 2 个(或更多)较大的时间步长并进行插值以获得中间帧来获得更流畅的动画。
据我所知,此解决方案适用于 UV 球体、棱角球体或球形立方体。
好的,我想我做到了。
我刚刚将时间参数添加到映射的 XYZ 坐标中。
使用相同的纬度和经度但将时间增加 0.01d 给了我一个不错的结果。
这是我的代码:
public double GetValue(double latitude, double longitude, double time) {
double x=0, y=0, z=0;
double PI = 3.1415926535897932385;
double DEG_TO_RAD = PI / 180.0;
double r = System.Math.Cos(DEG_TO_RAD * lat);
x = r * System.Math.Cos(DEG_TO_RAD * lon);
y = System.Math.Sin(DEG_TO_RAD * lat);
z = r * System.Math.Sin(DEG_TO_RAD * lon);
return GetNoiseValueAt(x + time, y + time, z + time);
}
如果有人有更好的解决方案请分享!
抱歉回答晚了,但我在网上其他地方找不到满意的答案,所以我写这篇文章是为了以后遇到这个问题的人。
对我有用的是使用多个 3d perlin 噪声源,并将它们组合成 1 个噪声源。将时间添加到 xyz 坐标只会产生非常明显的地形在 (-1,-1,-1) 方向上移动的效果。
平均超过 4 个不相关的噪声源确实会稍微改变噪声特性,因此您可能需要根据您的用例调整一些因素。
这个解决方案仍然不完美,但我没有看到任何视觉伪影。
代码是 C++ libnoise,但它应该同样可以很好地翻译成其他语言。
noise::module::Perlin perlin_noise[4];
float get_height(ofVec3f p, float time) {
p*=2;
time /= 10 ;
return (perlin_noise[0].GetValue(p.x, p.y, p.z) +
perlin_noise[1].GetValue(p.x, p.y, time) +
perlin_noise[2].GetValue(p.x, time, p.z) +
perlin_noise[3].GetValue(time, p.y, p.z))/2;
}
理想情况下,对于单个 3d 噪声源,您想将 x、y、z 坐标与 t 的单调函数相乘,以便它探索噪声源的不断扩展的球面,但我没有我还没有想出数学..
编辑:我使用的框架 (openframeworks) 内置了 4d perlin 噪声函数 ofSignedNoise(glm::vec4)
我正在使用 libnoise 的 C# 端口和 XNA(我知道它已经死了)来生成行星。
libnoise中有一个function接收球面顶点坐标(经纬度)和returns一个随机值(从-1到1)
因此,使用该值,我可以更改球体表面每个顶点的高度(高度),创建一些高度,模拟行星表面(我不是简单地在周围包裹纹理球体,我实际上是从头开始创建每个顶点)。
我所拥有的示例:
现在我想为球体设置动画,like this
但事实是,libnoise 仅适用于 3D 噪声。 "planet" 函数将纬度和经度映射到立方体的 XYZ 坐标。
而且我相信,要像我想要的那样为球体设置动画,我需要一个额外的坐标作为 "time" 维度。我对吗?或者是否可以使用 libnoise 提供的功能来做到这一点?
OBS:正如我提到的,我使用的是 UV 球体,而不是 icosphere 或球形立方体。
编辑:这是 libnoise 用来将 lat/long 映射到 XYZ 的算法:
public double GetValue(double latitude, double longitude) {
double x=0, y=0, z=0;
double PI = 3.1415926535897932385;
double DEG_TO_RAD = PI / 180.0;
double r = System.Math.Cos(DEG_TO_RAD * lat);
x = r * System.Math.Cos(DEG_TO_RAD * lon);
y = System.Math.Sin(DEG_TO_RAD * lat);
z = r * System.Math.Sin(DEG_TO_RAD * lon);
return GetNoiseValueAt(x, y, z);
}
一个n维的噪声函数有n个独立的输入(i0, i1, ..., in-1, in) & returns 一个值v,因此3D噪声足以生成随时间变化的高度图。在您的情况下,输入是经度、纬度和时间,输出是高度偏移。
简单的通用算法是:
at each time step (t){
for each vertex (v) on a sphere centered on some point (c){
calculate the longitude & latitude
get the scalar noise value (n) for the longitude, latitude & time
calculate the new vertex position (p) as follows p = ((v-c)n)+c
}
}
注意:这假设您不是 replacing/modifiying 原始顶点值。您可以保存它们的副本(使用更少的计算,但更多的内存)或根据与 c 的距离重新计算它们(使用更少的内存,但更多的计算)。此外,您可能会通过计算 2 个(或更多)较大的时间步长并进行插值以获得中间帧来获得更流畅的动画。
据我所知,此解决方案适用于 UV 球体、棱角球体或球形立方体。
好的,我想我做到了。
我刚刚将时间参数添加到映射的 XYZ 坐标中。
使用相同的纬度和经度但将时间增加 0.01d 给了我一个不错的结果。
这是我的代码:
public double GetValue(double latitude, double longitude, double time) {
double x=0, y=0, z=0;
double PI = 3.1415926535897932385;
double DEG_TO_RAD = PI / 180.0;
double r = System.Math.Cos(DEG_TO_RAD * lat);
x = r * System.Math.Cos(DEG_TO_RAD * lon);
y = System.Math.Sin(DEG_TO_RAD * lat);
z = r * System.Math.Sin(DEG_TO_RAD * lon);
return GetNoiseValueAt(x + time, y + time, z + time);
}
如果有人有更好的解决方案请分享!
抱歉回答晚了,但我在网上其他地方找不到满意的答案,所以我写这篇文章是为了以后遇到这个问题的人。
对我有用的是使用多个 3d perlin 噪声源,并将它们组合成 1 个噪声源。将时间添加到 xyz 坐标只会产生非常明显的地形在 (-1,-1,-1) 方向上移动的效果。 平均超过 4 个不相关的噪声源确实会稍微改变噪声特性,因此您可能需要根据您的用例调整一些因素。 这个解决方案仍然不完美,但我没有看到任何视觉伪影。
代码是 C++ libnoise,但它应该同样可以很好地翻译成其他语言。
noise::module::Perlin perlin_noise[4];
float get_height(ofVec3f p, float time) {
p*=2;
time /= 10 ;
return (perlin_noise[0].GetValue(p.x, p.y, p.z) +
perlin_noise[1].GetValue(p.x, p.y, time) +
perlin_noise[2].GetValue(p.x, time, p.z) +
perlin_noise[3].GetValue(time, p.y, p.z))/2;
}
理想情况下,对于单个 3d 噪声源,您想将 x、y、z 坐标与 t 的单调函数相乘,以便它探索噪声源的不断扩展的球面,但我没有我还没有想出数学..
编辑:我使用的框架 (openframeworks) 内置了 4d perlin 噪声函数 ofSignedNoise(glm::vec4)