2All :
простите, господа, а что вы все так всполошились?
статья имхо не стоит того... это вольный перевод Хьюго Элиаса, и btw шум тут маленько кучерявый...
лучше использовать препросчитанные градиенты вместо псевдо-рэндома...
про скорость я молчу...
и напоследок пара ссылок, думаю тогда вы оцените возможности шума по достоинству :
Perlin noise math FAQ
http://www.robo-murito.net/code/perlin-noise-math-faq.html#algorithm
Sky Rendering Techniques
http://www.gamedev.net/community/forums/topic.asp?whichpage=2&pag… opic_id=86024
to:Alexded
ИМХО для этого надо использовать либо алгоритм удаления шва,
либо зразу генерировать текстуру без шва
e.g http://www.gamedev.ru/download/?id=441 tnx to Mikle
Boo
Если хочеш написать лучше - сделай это , а критиковать каждый может ...
Таких ссылок есть полным полно - но стаття розсчитана на геймдев комюнити среди которых тех людей которые хотят углублятся в математику еденицы , а я пробовал сделать материал доступным для всех...Не знаю удалось ли мне это...
люди а у меня вот алгоритм не работает почему то...потоянно переполнение идет....скажите так вот правильно
n=pow(shl(n,13),n);
to: Misterion
Pascal? Delphi?
Дело в том, что в C "a^b" означает не а в степени b, а побитовое исключающее ИЛИ. В общем я сделал так:
function Noise(x,y:integer):byte;
var p:integer;
begin
p:=x+y*57;
p:=not((p shl 13) or p);
Noise:=round(((1-((p*(p*p*15731+789221)+1376312589) and $7fffffff)/1073741824)+1)*127.5);
end;
В любом случае получился повторяющийся шум, что меня конкретно не устроило.
Легче, по-моему, инициализировать в начале генерации шума 2-мерный массивчик - n-размерности (больше 1000 желательно), заполненный рандомом, а потом делать так:
NoiseArr:array[0..n,0..n] of byte;
...
function Noise(x,y:integer):byte;
begin
if x>n then x:=x-n*(x div n);
if y>n then y:=y-n*(y div n);
Noise:=NoiseArr[x][y];
end;
Все отлично работает.
Скопипастил сурсы и офигел от того какой затилиный оказался шум. Покопался на гугле, но нашел только статью, с которой перевели эту (т.е. ничего полезного)
Разобрался поподробнее и пришел к выводу, что использование составных чисел в псевдорандоме не есть гуд.
Заменил 57 на 97171 и стало счастье)
Было:
_inline float CMyNoise::Noise2D(int x, int y) { int n = x + y * 57; n = ( n<<13) ^ n; return ( 1.0f - ( ( n * ( n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f); }
Стало:
_inline float CMyNoise::Noise2D(int x, int y) { __int64 n = x + y * 97171; n = ( n<<13) ^ n; return ( 1.0f - ( ( n * ( n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f); }
PS автору спасибо за статью, пригодилась
Вопрос к автору:
google.ru Ken Perlin noise. Сразу же выдаётся статья Кена Перлина: http://www.noisemachine.com/talk1/14.html
В ней нет никаких частот - только игра с градиентами.
Чем отличается метод в статье от оригинального метода?
bruzo
> В ней нет никаких частот
это функция turbulance
спасибо.
еще бы ты генерацию 3д шума показал и было бы еще лучше!!!!
и для облаков совершенно необязательно юзать перлин шум
вот тут показан левый соверщенно шум
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series4/Perlin_noise.php
и облака на нем
...
или шумом перлина называется любой шум генерированный через рандом??
float int_X = int(x);//целая часть х
float fractional_X = x - int_X;//дробь от х
//аналогично у
float int_Y = int(y);
float fractional_Y = y - int_Y;
здесь ошибка при отрицательных числах надо так (эта ошибка видна при factor<0)
надо так есть способ рациональнее (вместо if поставить ? но я так неумею...)
float int_X;
if (x>=0)
{
int_X = int(x);
}else{
int_X = int(x)-1;
}
float fractional_X = x - int_X;
float int_Y;
if (y>=0)
{
int_Y = int(y);
}else{
int_Y = int(y)-1;
}
float fractional_Y = y - int_Y;
Можно подробную реализацию данного класса и OpenGL со всеми вызовами функции данного класса? или это слишком?)
_inline float CMyNoise::Noise2D(int x, int y) { int n = x + y * 57; n = ( n<<13) ^ n; return ( 1.0f - ( ( n * ( n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f); }
А у меня не работает эта функция. Она должна возвращать псевдо-случайные числа, а возвращает для большинства аргументов константное значение, вот пример:
http://jsfiddle.net/byoybjkw/
Кто знает, в чем подвох?
Xegby, магическая замена 57 на 97171 не помогла. :)
//здесь можно перевести значения цвета по какой-то формуле
...
total=fabsf(total);
int res=int(total*255.0f);//приводим цвет к значению 0-255…
return res;
Вообще лучше приводить total к диапазону [-1; 1] или [0; 1]. Для [-1; 1] надо разделить на максимальное значение шума. Максимальное значение вычисляется так:
1f - Mathf.Pow( 0.5f, octaves );
Можно как-то оптимизировать вычисление шума?
У меня шум для массива 512x512 считается 0.25 - 0.3 сек.
Если распараллелить в 4 потока, то 0.14 - 0.15 сек.
Если еще и на fixed point переделать, то 0.8 - 0.13 сек.
Но все равно медленно. Хотелось бы 1024x1024 считать меньше, чем 0.1 сек.
Мой PerlinNosie FastPerlinNoise2D
И с Fixel Point FastPerlinNoise2D
При низкой частоте шума получается, что много раз считаются одни и те же псевдо-рандомное значение, между которыми производится интерполяция.
Надо не вычислить каждый раз заново значение, а вычислять сначала в 4х ключевых точках, а потом интерполировать между ними и записывать в массив. Никто так не делал?
WISHMASTER35
У тебя ведь тоже не Перлин, так (отсутствие градиентов)?
Работает заметно быстрее, чем например stb_perlin (на C++), где градиенты есть (ну и он 3d).
А так, наверно, разбить на кусочки, хорошо влезающие в L1-кеш, для каждого кусочка сказать:
for( int i = 0; i < octaves; i++ ) {
for( int y = tile_start_y; y < tile_end_y; y++ ) {
for( int x = tile_start_x; x < tile_end_x; x++ ) {
// ...то будет, надо думать, побыстрее. Т. к. внутри можно меньше считать (fy, y0, y1 не меняются, и т. д.).
Ну и для ситуации, когда Mathf.FloorToInt( tile_start_y*freq )==Mathf.FloorToInt( (tile_start_y-1)*freq )&&Mathf.FloorToInt( tile_start_x*freq )==Mathf.FloorToInt( (tile_start_x-1)*freq ) - отдельную ветку, тоже пригодится, пожалуй.
Но это я не проверял, так говорю.
И преобразований int<->float, вроде, можно меньше делать.
Написал такое:
public void Compute() {
System.Array.Clear(texture, 0, texture.Length);
int freq = 1;
float amp = 1;
for( int i = 0; i < noise.octaves; i++ ) {
Compute( noise.scale * freq, noise.offset * freq, amp );
freq *= 2;
amp *= 0.5f;
}
for( int i = 0; i < texture.Length; i++ ) {
texture[i] *= noise.invMaxValue;
}
}
private void Compute(float scale, Vector2 offset, float amp) {
int step = Mathf.CeilToInt( 1f/scale );
int NX = (int) (offset.x * step); // noise offset
int NY = (int) (offset.y * step);
int TX = NX - (Mathf.FloorToInt( offset.x ) * step); // texture offset
int TY = NY - (Mathf.FloorToInt( offset.y ) * step);
for( int y = -TY; y < height; y+=step ) {
for( int x = -TX; x < width; x+=step ) {
int nx = x + NX;
int ny = y + NY;
Compute( x, y, nx, ny, step, amp );
}
}
}
private void Compute(int x, int y, int nx, int ny, int step, float amp) {
float v0 = FastPerlinNoise2D.Random( nx, ny );
float v1 = FastPerlinNoise2D.Random( nx+step, ny );
float v2 = FastPerlinNoise2D.Random( nx, ny+step );
float v3 = FastPerlinNoise2D.Random( nx+step, ny+step );
int x0 = Mathf.Max( x, 0 );
int x1 = Mathf.Min( x+step, width );
int y0 = Mathf.Max( y, 0 );
int y1 = Mathf.Min( y+step, height );
for( int iy = y0; iy < y1; iy++ ) {
int index = ToIndex( x0, iy );
for( int ix = x0; ix < x1; ix++, index++ ) {
float tx = FastPerlinNoise2D.SmoothStep( (float) (ix-x)/step );
float ty = FastPerlinNoise2D.SmoothStep( (float) (iy-y)/step );
float a = FastPerlinNoise2D.Lerp( v0, v1, tx );
float b = FastPerlinNoise2D.Lerp( v2, v3, tx );
float c = FastPerlinNoise2D.Lerp( a, b, ty );
texture[index] += c * amp;
}
}
}Текстура 512x512. Время: 0.13 - 0.15 сек. И это без многопоточности.
Только если бы избавится от SmoothStep и Lerp.
Если бы просто Lerp использовал, то прибавлял бы dx и dy. А из-за SmoothStep интерполяция не линейная.
Можно как-то оптимизировать это место?
Тема в архиве.