【问题标题】:How to apply the perlin noise on a sphere?如何在球体上应用柏林噪声?
【发布时间】:2012-12-27 22:26:25
【问题描述】:

我正在尝试在 HLSL 中为 XNA 项目创建动画太阳。

我使用 Perlin Noise 算法在像素着色器中生成它的纹理,该算法是从 this site 学到的。

这是我为像素着色器编写的 hlsl 代码:

sampler myTexture;

struct VS_Output{
   float4 Position : POSITION0;
   float4 Color : COLOR0;
   float2 TextCoord : TEXCOORD0;
};

float CosineInterpolation( float x, float y, float fractional ) {
   float ft = 3.141592f * fractional;
   float f = ( 1.0f - cos( ft ) ) * 0.5f;

   return x * ( 1.0f - f ) + y * f;
}

float Noise(float2 xy)
{
    float2 noise = (frac(sin(dot(xy ,float2(12.9898,78.233)*2.0)) * 43758.5453));
    return abs(noise.x + noise.y) * 0.5;
}

float SmoothNoise( float integer_x, float integer_y ) {
   float corners = ( Noise( float2(integer_x - 1, integer_y - 1) ) + Noise( float2(integer_x + 1, integer_y + 1 )) + Noise( float2(integer_x + 1, integer_y - 1 )) + Noise( float2(integer_x - 1, integer_y + 1 )) ) / 16.0f;
   float sides = ( Noise( float2(integer_x, integer_y - 1 )) + Noise( float2(integer_x, integer_y + 1 )) + Noise( float2(integer_x + 1, integer_y )) + Noise( float2(integer_x - 1, integer_y )) ) / 8.0f;
   float center = Noise( float2(integer_x, integer_y )) / 4.0f;

   return corners + sides + center;
}

float InterpolatedNoise( float x, float y ) {
   float integer_x = x - frac(x), fractional_x = frac(x);
   float integer_y = y - frac(y), fractional_y = frac(y);

   float p1 = SmoothNoise( integer_x, integer_y );
   float p2 = SmoothNoise( integer_x + 1, integer_y );
   float p3 = SmoothNoise( integer_x, integer_y + 1 );
   float p4 = SmoothNoise( integer_x + 1, integer_y + 1 );

   p1 = CosineInterpolation( p1, p2, fractional_x );
   p2 = CosineInterpolation( p3, p4, fractional_x );

   return CosineInterpolation( p1, p2, fractional_y );
}

float CreatePerlinNoise( float x, float y ) {
    float result = 0.0f, amplitude = 0.0f, frequency = 0.0f, persistance = 0.1f;

    for ( int i = 1; i <= 4; i++ ) {
       frequency += 2;
       amplitude += persistance;

       result += InterpolatedNoise( x * frequency, y * frequency ) * amplitude;
    }

    return result;
}

float4 ps_main(VS_Output Input) : COLOR0
{  
   float index = CreatePerlinNoise(Input.TextCoord.x*256.0f, Input.TextCoord.y*256.0f);
   return tex2D(myTexture, index);
}

基本上,在这段代码中,通过将纹理坐标分量 (TextCoord) 传递给 CreatePelinNoise 函数,它返回一个用作渐变纹理颜色索引的值 (myTexture 1px x 256 像素):

AMD RenderMonkey 中的结果如下:

但是在球体的两极有一个难看的不需要的效果,这使得生成的纹理不均匀:

如何解决这个问题,让生成的纹理统一?

【问题讨论】:

  • 你能上传你的渐变纹理吗?
  • 好的,here 是渐变纹理。

标签: hlsl pixel-shader perlin-noise


【解决方案1】:

发生这种情况是因为您将噪波函数视为 2D 纹理,如果将其投影到球体上,被拉伸/扭曲。您基本上是在像素着色器中实时生成 2D 纹理,然后将其应用于球体。

如果您真的了解 Perlin Noise 原则,那么您就可以将您的代码推广到两个以上的维度。 Ken Perlin 本人在发明噪声算法时也有同样的想法; in his own words,“将对象浸入程序纹理(噪声)材料的汤中”。

只需使用像素坐标作为 3D 噪声函数(您的 float4 Position 变量)的输入,保持颜色映射代码不变。这应该会产生预期的效果。 顺便说一句,如果您想让它动画化,请将其推广到 4D 并随时间改变第 4 个参数。如果处理得当,它应该会产生一个不错的“熔岩星球”效果(查看 Perlin 的幻灯片了解更多信息)。

哦,还有一个加速提示:不要使用余弦插值,而是使用著名的 3*t^2-2*t^3 插值曲线。在 0 和 1 之间,它看起来几乎与谐波相同,但计算量更少。

【讨论】:

  • 确实,我已经应用了柏林噪声结合行进立方体算法,并在我的地形上取得了很好的效果。但由于 XNA 的一些限制,实际上很难在 GPU 上实现这一点。这就是为什么我只想创建一个简单的 2D 纹理。尽管您应该为有用的建议投票。
  • 感谢您的支持。但是对于地形,使用您刚刚在像素着色器中描述的 2D 噪声进行曲面细分不仅更简单,而是在顶点着色器上运行?对我来说,如果你只是想生成一些风景,行进立方体似乎是一种矫枉过正。也许 XNA/Direct3D 包含一些不鼓励这种方法的开销;从我在 OpenGL 的背景来看,我知道它几乎肯定会更快。
  • (顶点着色器的使用会更快,而不是 OpenGL 本身)
猜你喜欢
  • 2021-04-29
  • 2012-01-29
  • 2012-07-22
  • 2017-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多