Вы не сказали точно, как вы на самом деле генерировали позиции.Поэтому я предполагаю, что вы используете шум Перлина для генерации значений высоты на карте высот.Итак, для любой позиции X, Y в hieghtmap вы используете функцию 2D-шума для генерации значения Z.
Итак, давайте предположим, что ваша позиция вычисляется следующим образом:
vec3 CalcPosition(in vec2 loc) {
float height = MyNoiseFunc2D(loc);
return vec3(loc, height);
}
Это создает трехмерную позицию.Но в каком пространстве находится эта позиция?Вот в чем вопрос.
Большинство шумовых функций ожидают, что loc
будут двумя значениями в некотором конкретном диапазоне с плавающей точкой.Насколько хороша ваша шумовая функция, будет определять, в каком диапазоне вы можете передавать значения. Теперь, если не гарантируется, что 2D-позиции вашего модельного пространства находятся в пределах диапазона шумовой функции, вам необходимо преобразовать их в этот диапазон, выполнить вычисления изатем преобразуйте его обратно в пространство модели.
Таким образом, теперь у вас есть 3D-позиция.Преобразование для значений X и Y простое (обратное преобразование к пространству шумовой функции), но что из Z?Здесь вы должны применить какую-то шкалу к высоте.Функция шума будет возвращать число в диапазоне [0, 1), поэтому вам нужно масштабировать этот диапазон до того же пространства модели, к которому будут подходить ваши значения X и Y.Обычно это делается путем выбора максимальной высоты и масштабирования положения соответствующим образом.Поэтому наша пересмотренная позиция вычисления выглядит примерно так:
vec3 CalcPosition(in vec2 modelLoc, const in mat3 modelToNoise, const in mat4 noiseToModel)
{
vec2 loc = modelToNoise * vec3(modelLoc, 1.0);
float height = MyNoiseFunc2D(loc);
vec4 modelPos = noiseToModel * vec4(loc, height, 1.0);
return modelPos.xyz;
}
Две матрицы преобразуются в пространство функции шума, а затем преобразуются обратно.Ваш реальный код может использовать менее сложные структуры, в зависимости от вашего варианта использования, но полное аффинное преобразование просто описать.
Хорошо, теперь, когда мы установили, что вам нужно помнить следующее:ничто не имеет смысла, если вы не знаете, в каком пространстве оно находится. Ваше нормальное положение, ваши позиции, ничего не имеет значения, пока вы не установите, в каком пространстве оно находится.
Эта функция возвращает позиции в пространстве модели.Нам нужно вычислить нормали в пространстве модели .Для этого нам понадобятся 3 позиции: текущая позиция вершины и две позиции, которые немного смещены относительно текущей позиции.Позиции, которые мы получаем , должны находиться в пространстве модели, иначе наша нормаль не будет.
Следовательно, нам нужна следующая функция:
void CalcDeltas(in vec2 modelLoc, const in mat3 modelToNoise, const in mat4 noiseToModel, out vec3 modelXOffset, out vec3 modelYOffset)
{
vec2 loc = modelToNoise * vec3(modelLoc, 1.0);
vec2 xOffsetLoc = loc + vec2(delta, 0.0);
vec2 yOffsetLoc = loc + vec2(0.0, delta);
float xOffsetHeight = MyNoiseFunc2D(xOffsetLoc);
float yOffsetHeight = MyNoiseFunc2D(yOffsetLoc);
modelXOffset = (noiseToModel * vec4(xOffsetLoc, xOffsetHeight, 1.0)).xyz;
modelYOffset = (noiseToModel * vec4(yOffsetLoc, yOffsetHeight, 1.0)).xyz;
}
Очевидно,Вы можете объединить эти две функции в одну.
Значение delta
является небольшим смещением в пространстве ввода текстуры шума.Размер этого смещения зависит от вашей шумовой функции;он должен быть достаточно большим, чтобы возвращать высоту, которая значительно отличается от высоты, возвращаемой фактической текущей позицией.Но оно должно быть маленьким достаточно, чтобы вы не вытягивали из случайных частей распределения шума.
Вы должны узнать свою функцию шума.
Теперь, когдау вас есть три позиции (текущая позиция, смещение по x и смещение по оси y) в пространстве модели, вы можете вычислить нормаль вершины в пространстве модели:
vec3 modelXGrad = modelXOffset - modelPosition;
vec3 modelYGrad = modelYOffset - modelPosition;
vec3 modelNormal = normalize(cross(modelXGrad, modelYGrad));
Отсюда выполните обычныевещи.Но никогда не забывайте следить за пробелами ваших различных векторов.
О, и еще одна вещь: это должно быть сделано в шейдере vertex .Нет смысла делать это в геометрическом шейдере, поскольку ни одно из вычислений не влияет на другие вершины.Пусть параллелизм GPU сработает для вас.