FordPerfect
> У тебя ведь тоже не Перлин, так (отсутствие градиентов)?
Я где-то нашел этот алгоритм, он назывался PerlinNoise. Думал это PerlinNoise с предрасчитанными рандомными значениями. Или это уже не PerlinNoise?
WISHMASTER35
Не похоже.
http://www.noisemachine.com/talk1/15.html :
Given an input point
For each of its neighboring grid points:
1. Pick a "pseudo-random" gradient vector
2. Compute linear function (dot product)
3. Take weighted sum, using ease curves
Т. е. dot product считается per pixel, а не per vertex.
Т. е. предрассчиать градиенты не понятно как.
Вообще фразу "предрасчитанными рандомными значениями" я не совсем понял.
В оригинале rnd тоже из массива берутся:
http://mrl.nyu.edu/~perlin/doc/oscar.html#noise
А по оптимизации... Если предрассчитать все tx в линейный массив, а ty вообще вынести из внутреннего цикла?
И lerp по ty можно объединить с умножением на amp.
Интересно, сильно ли поможет (вообще?)?
Правка:
орфография.
Т. е. dot product считается per pixel, а не per vertex.
У меня 3д шум так работает PerlinNoise3D
И для оптимизации использую такой класс PerlinNoiseChunk3D чтобы считать только каждые 4е значения шума и интерполировать между ними.
Интерполяция очень простая:
Даже можно было бы отказаться от умножения.
Вообще фразу "предрасчитанными рандомными значениями" я не совсем понял.
Там же рандомное значение считается только для ineger x, y. Можно для какого-то промежутка предрасчитать и сохранить в массив.
А по оптимизации... Если предрассчитать все tx в линейный массив, а ty вообще вынести из внутреннего цикла?
И lerp по ty можно объединить с умножением на amp.
Предрассчитал в массив результатов SmoothStep.
Но быстрее не стало.
Даже если вообще так сделать:
float tx = 0, ty = 0;
То выигрыш скорости будет всего лишь 0.01 сек. Не так много.
а ty вообще вынести из внутреннего цикла?
Вынес ty и "* amp".
Может на сотую долю секунды стало быстрее.
Вообще на C# адекватно не оценишь производительность. Особенно если запускать из Visual Studio или Unity Editor. Но все же хочется выжить максимум.
Теперь время 0.085 сек.
Вряд ли можно еще что-то тут оптимизировать.
Предрасчет SmoothStep в массив почему-то ничего не дал.
А вот invStep предал немного скорости.
Только fixel point и многопоточность еще можно сделать.
Если я не ошибаюсь, то все рандомные значения можно предрассчитать в массив размером SIZE*SIZE, и шум будет работать так же.
Сделал так, все так же. На скорость не повлияло.
Кстати, из-за этих моих оптимизаций появилось какое-то дрожание шума при изменении offset. Но мне это не очень страшно.
WISHMASTER35
> Если я не ошибаюсь, то все рандомные значения можно предрассчитать в массив
> размером SIZE*SIZE, и шум будет работать так же.
Я давно так делаю. Не знаю че все вокруг этого ПерлЮна пляшут.
Всем очень хорошо известна формула получения случайной последовательности rnd(i+1)=rnd(i)*A+C - если качественно подобрать A то C можно выкинуть но придется обработать rnd(i)==0.
Банально масштабировать двухмерною карту с RND пикселями, сложить разные масштабы и каждый кто увидит результат, не зная как он получен, будет биться в истерике доказывая тебе что это на самом деле шум Перлина.
Вот тут ни какой Перлин ни когда и рядом не стоял, если че:
foxes
Шум Перлина - чистая функция от координат. Т. е. концептуально - текстура бесконечного размера и бесконечной детализации.
Вполне можно, наверно, представить ситуации, когда это удобно.
Если нужно только заполнить текстуру шумом - то да, влобный random, вроде, вполне достаточен.
WISHMASTER35
>Предрасчет SmoothStep в массив почему-то ничего не дал.
Ты его индексируешь как-то странно, или я не понял?..
float tx = SMOOTH_STEP[ (ix-x)*1023/step ];
Я подразумевал что-то вроде:
private void Compute(int x, int y, int nx, int ny, int step, float amp) {
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 );
float v0 = FastPerlinNoise2D.Random( nx, ny ) * amp;
float v1 = FastPerlinNoise2D.Random( nx+step, ny ) * amp;
float v2 = FastPerlinNoise2D.Random( nx, ny+step ) * amp;
float v3 = FastPerlinNoise2D.Random( nx+step, ny+step ) * amp;
float inv_step=1.0f/float(step);
for( int ix = x0; ix < x1; ix++, index++ ) {
SMOOTH_STEP[ix-x0]=FastPerlinNoise2D.SmoothStep( (float) (ix-x)*inv_step );
}
for( int iy = y0; iy < y1; iy++ ) {
float ty = FastPerlinNoise2D.SmoothStep( (float) (iy-y)*inv_step );
int index = ToIndex( x0, iy );
for( int ix = x0; ix < x1; ix++, index++ ) {
float tx = SMOOTH_STEP[ix-x0];
float a = FastPerlinNoise2D.Lerp( v0, v1, tx );
float b = FastPerlinNoise2D.Lerp( v2, v3, tx );
float c = FastPerlinNoise2D.Lerp( a, b, ty );
texture[index] += c;
}
}
}WISHMASTER35
А по здравом размышлении:
Примечание: C# я не знаю.
FordPerfect
> FastPerlinNoise2D.SmoothStep
Можно просто сохранить все результаты SmoothStep в массив.
Ну все не сохранить, а где-то 1024 будет вполне достаточно.
for( int i = 0; i < SMOOTH_STEP.Length; i++ ) {
SMOOTH_STEP[i] = FastPerlinNoise2D.SmoothStep( i / 1023f ); // [0; 1]
}foxes
Я давно так делаю. Не знаю че все вокруг этого ПерлЮна пляшут.
Странно, почему обычно предпочитают вычислять каждый раз:
random[perm[perm[x] + y]]
а не предрассчитывать в текстуру. Возможно текстура хуже кэшируется т.е. больше памяти занимает.
Кстати, что-то не замечал упоминаний о том, что всенародно любимая функция:
float IntNoise(int x) { x = ( x<<13) ^ x; return ( 1.0 - ( ( x * ( x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0); }
вообще говоря, содержит undefined behavior.
Это вдобавок к http://www.gamedev.ru/code/forum/?id=11014&page=2#m19 .
Тема в архиве.