improved_noise
не был предназначен для обработки отрицательных входных данных.
Комментарий в нем гласит:
The left bound is ( |_x_|,|_y_|,|_z_| )…
Обозначение |…|
предполагает, что абсолютное значение предназначено.Однако код вычисляет:
int xi = (int)x & 255;
В распространенных реализациях C (где используется дополнение до двух), это эффективно вычисляет остаток целочисленной части x
по модулю 256. Например, если x - -3.25, его целочисленная часть равна -3, и это установит xi
в 253 (что равно -3 + 256).
В этом есть две проблемы.Во-первых, 253 не является абсолютным значением -3, поэтому этот код не соответствует комментарию.Во-вторых, он берет «правую» границу единичного куба, содержащего точку (границу с большим значением), в то время как комментарии и поведение для положительных значений предполагают, что целью является установить xi
, yi
и zi
до «левой» границы (той, которая имеет меньшее значение).
Далее, код устанавливает double xf = x - (int) x;
.Для неотрицательных значений это дает дробную часть x
.Например, если бы x
было 3,25, xf
было бы 0,25.Однако с отрицательными значениями и предшествующей & 255
операцией это сбивается с пути.Для x
= -3,25 вычисляется -3,25 - 253 = -256,25.Но код, скорее всего, предназначен просто для интерполяции в единичном кубе, для дробных частей от 0 до 1. Какая бы функция ни использовалась для выполнения интерполяции, скорее всего, не поддерживается -256.25.
По сути, этот код никогда не разрабатывалсядля поддержки отрицательных значений, а исправление требует пересмотра его из первых принципов того, как он должен работать.
Исходный код , на который вы указываете , лучше:
int X = (int)Math.floor(x) & 255
…
x -= Math.floor(x);
Первый правильно использует floor
, чтобы найти «левую» границу, независимо от того, является ли x
отрицательным или нет.Тогда это относится & 255
к этому.Предполагая, что два дополняют друг друга, это даст правильную координату в периодической мозаике.(Предполагая, что два дополнения не являются чисто переносимыми, и их следует документировать или избегать.)
Затем он правильно находит дробь, вычитая floor
из x
, а не вычитая результат & 255
.Например, для x
= -3,25 это даст целочисленную координату -4 и дробь 0,75.
Изменение improved_noise
для аналогичной работы может помочь.Вы можете попробовать:
int xi = (int) floor(x) & 255;
int yi = (int) floor(y) & 255;
int zi = (int) floor(z) & 255;
double xf = x - floor(x);
double yf = y - floor(y);
double zf = z - floor(z);
Вы пометили этот вопрос как C ++, так и C. В C ++ предпочтительнее использовать std::floor
вместо floor
, и могут быть другие проблемы с различиями между C ++и С.