OpenGL - Как рассчитать нормали в сетке высот местности?

Мой подход заключается в вычислении двух касательных векторов, параллельных осям X и Y соответственно. Затем вычислите векторное произведение, чтобы найти вектор нормали.

Касательный вектор задается линией, которая пересекает среднюю точку на двух ближайших сегментах, как показано на следующем рисунке.

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

Мне было интересно, есть ли более прямой расчет или менее затратный с точки зрения циклов ЦП.


person rraallvv    schedule 21.12.2012    source источник
comment
Могу я спросить, что вы использовали, чтобы нарисовать это изображение? Это действительно приятно.   -  person Aesthete    schedule 21.12.2012


Ответы (1)


На самом деле вы можете рассчитать его без перекрестного произведения, используя «метод конечных разностей» (или, по крайней мере, я думаю, что он называется таким образом).

На самом деле это достаточно быстро, чтобы я использовал его для вычисления нормалей на лету в вершинном шейдере.

  // # P.xy store the position for which we want to calculate the normals
  // # height() here is a function that return the height at a point in the terrain

  // read neightbor heights using an arbitrary small offset
  vec3 off = vec3(1.0, 1.0, 0.0);
  float hL = height(P.xy - off.xz);
  float hR = height(P.xy + off.xz);
  float hD = height(P.xy - off.zy);
  float hU = height(P.xy + off.zy);

  // deduce terrain normal
  N.x = hL - hR;
  N.y = hD - hU;
  N.z = 2.0;
  N = normalize(N);
person Gigi    schedule 21.12.2012
comment
Жаль, что я не могу дать вам больше, чем +1: я удвоил свой FPS, используя ваш простой алгоритм! - person Zac; 05.07.2013
comment
Очень хорошо, отлично работает для моих предварительных расчетов на процессоре - person Paul Spain; 08.12.2016
comment
Очень хорошо! Можете ли вы распространить свое решение на 3D-текстуры? - person qantik; 11.04.2017
comment
Есть ли где-нибудь математическое объяснение этому? - person j00hi; 02.02.2018
comment
Это работает безупречно! Просто примечание: числа в выключенном векторе необходимо настроить для вашего конкретного случая (мне пришлось использовать немного большее смещение, чтобы оно работало в моем случае) - person Michele; 16.05.2018
comment
не совсем уверен, почему, но мне пришлось использовать N.z =~ .06. Кроме того, для пользователей Unity z и y перевернуты. В остальном он дает довольно приличные результаты :) - person Bas Smit; 09.07.2019
comment
Более дорогая, но немного более точная версия здесь stackoverflow.com/a/21660173/175592 - person Bas Smit; 09.07.2019
comment
хорошо, это имеет смысл, N.z должно быть в 2 раза больше вашего смещения, поэтому в моем случае я использую 0,03 в качестве смещения, что дает N.z = 0,06 - person Bas Smit; 10.07.2019
comment
Рассмотрим вашу поверхность: z = h(x, y), где h — карта высот. Итак, z - h(x,y) = 0 Это уравнение представляет собой контур при g=0 для следующей функции: g(x,y,z) = z - f(x,y) Градиент g точек в сторону максимального увеличения. Он также ортогонален контурной плоскости. Так что это нормально. Чтобы найти дискретный градиент, сосредоточьтесь на (x, y) и возьмите разницу его соседей. grad_x = f(x+1,y) - f(x-1,y)/2 grad_y = f(x,y+1) - f(x,y-1)/2 grad_z = (z+1) - (z-1) / 2 = 2/2 = 1 Все это можно масштабировать без изменения направления, поэтому умножьте на 2. Затем нормализуйте. Тада! - person Kookei; 20.01.2021
comment
Шикарное решение, только что проверил. Работает как шарм. - person Sinisa; 06.06.2021