Как применить шум Перлина к сфере?

Я пытаюсь создать анимированное солнце в HLSL для проекта XNA.

Я генерирую его текстуру в пиксельном шейдере, используя алгоритм Perlin Noise, который я узнал из этот сайт.

Это 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 256px):

введите описание изображения здесь

Результат в AMD RenderMonkey будет следующим:

введите описание изображения здесь

Но на полюсах сферы наблюдается неприглядный нежелательный эффект, делающий сгенерированную текстуру неоднородной:

введите описание изображения здесь

Как я могу решить эту проблему и сделать сгенерированную текстуру однородной?


person Omar    schedule 27.12.2012    source источник
comment
не могли бы вы также загрузить свою градиентную текстуру?   -  person Vertexwahn    schedule 01.01.2013
comment
Хорошо, здесь - текстура градиента.   -  person Omar    schedule 01.01.2013


Ответы (1)


Это происходит из-за того, что вы обрабатываете шумовую функцию как 2D-текстуру, которая будет растягиваться / искажаться при проецировании на сферу. Вы в основном создаете 2D-текстуру в пиксельном шейдере в реальном времени, а затем применяете ее к сфере.

Если вы действительно понимаете принципы шума Перлина, то вы можете обобщить свой код более чем на два измерения. Сам Кен Перлин придерживался этой же идеи при изобретении алгоритма шума; по его собственным словам: «Окуните объект в суп процедурной текстуры (шума) материал ".

Просто используйте координаты пикселей в качестве входных данных для функции 3D-шума (ваша переменная позиции float4), сохраняя неизменным код отображения цвета. Это должно произвести желаемый эффект. Кстати, если вы хотите анимировать, обобщите его на 4D и меняйте 4-й параметр со временем. Если все сделано правильно, это должно привести к красивому эффекту «лава-планета» (дополнительную информацию см. На слайдах Перлина).

Да, и совет по ускорению: вместо использования косинусной интерполяции используйте знаменитую кривую интерполяции 3 * t ^ 2-2 * t ^ 3. Между 0 и 1 он выглядит почти идентично гармонической волне, но требует меньших вычислительных затрат.

person MVittiS    schedule 02.01.2013
comment
Действительно, я уже применил шум Перлина в сочетании с алгоритмом маршевых кубов и добился отличного эффекта с моим ландшафтом. Но из-за некоторых ограничений XNA это на самом деле сложно реализовать на графическом процессоре. Вот почему я просто хотел создать простую 2D-текстуру. Хотя вы заслуживаете одобрения за полезные предложения. - person Omar; 02.01.2013
comment
Я ценю положительный голос. Но что касается ландшафта, не просто тесселяция проще, используя 2D-шум, который вы только что описали в пиксельном шейдере, вместо того, чтобы работать с вершинным шейдером? Для меня походные кубы кажутся излишеством, если вы просто хотите создать какие-то пейзажи. Возможно, XNA / Direct3D включает некоторые накладные расходы, препятствующие этому подходу; из моего опыта работы с OpenGL я знаю, что это почти наверняка будет быстрее. - person MVittiS; 02.01.2013
comment
(использование вершинного шейдера будет быстрее, а не сам OpenGL) - person MVittiS; 02.01.2013