#c #opengl #graphics #data-visualization
#c #opengl #графика #данные-визуализация
Вопрос:
Вот фрагмент кода, который я хотел бы, чтобы мне помогли понять
for (i = 0; i < samplesX; i )
for (j = 0; j < samplesY; j )
{
newI = DIM * i / samplesX;
newJ = DIM * j / samplesY;
idx = (round(newJ) * DIM) round(newI);
if (color_dir == 1 amp;amp; draw_vecs == 1) {
direction_to_color(vx[idx], vy[idx], color_dir);
}
if (color_dir == 1 amp;amp; draw_vecs == 2) {
direction_to_color(fx[idx], fy[idx], color_dir);
}
else if (color_dir == 2) {
scalar = rho[idx];
set_colormap(scalar, min, max, clampLow, clampHigh);
}
else if (color_dir == 3) {
scalar = sqrt(vx[idx] * vx[idx] vy[idx] * vy[idx]);
set_colormap(scalar, min, max, clampLow, clampHigh);
}
else if (color_dir == 4) {
scalar = sqrt(fx[idx] * fx[idx] fy[idx] * fy[idx]);
set_colormap(scalar, min, max, clampLow, clampHigh);
}
/*if (draw_vecs == 1) {
glVertex2f(wn (fftw_real)newI * wn, hn (fftw_real)newJ * hn);
glVertex2f((wn (fftw_real)newI * wn) vec_scale * vx[idx], (hn (fftw_real)newJ * hn) vec_scale * vy[idx]);
}
else if (draw_vecs == 2) {
glVertex2f(wn (fftw_real)newI * wn, hn (fftw_real)newJ * hn);
glVertex2f((wn (fftw_real)newI * wn) vec_scale * fx[idx], (hn (fftw_real)newJ * hn) vec_scale * fy[idx]);
}*/
if (draw_vecs == 1) {
glVertex2f(wn (fftw_real)i * wn, hn (fftw_real)j * hn);
glVertex2f((wn (fftw_real)i * wn) vec_scale * vx[idx], (hn (fftw_real)j * hn) vec_scale * vy[idx]);
}
else if (draw_vecs == 2) {
glVertex2f(wn (fftw_real)i * wn, hn (fftw_real)j * hn);
glVertex2f((wn (fftw_real)i * wn) vec_scale * fx[idx], (hn (fftw_real)j * hn) vec_scale * fy[idx]);
}
}
glEnd();
}
Насколько я понимаю, в настоящее время это позволяет отображать эти двумерные линии / стрелки (ежики), которые визуализируют силу / скорость в 2D, как видно на рисунке ниже.
К сожалению, мое понимание линейной алгебры, исчисления и компьютерной графики в целом зашло так далеко, и у меня возникли проблемы с анализом этого фрагмента.
В идеале я хотел бы понять это, а также понять, как я могу использовать этот уже существующий код, а также добавить функциональность, которая может отображать два других типа глифов, которые показывают векторное и / или скалярное поле, такое как
- трехмерные конусы
- трехмерные эллипсоиды
Если я чего-то здесь не понимаю, пожалуйста, дайте мне знать!
Некоторые из переменных, включенных в приведенный выше фрагмент:
const int DIM = 50; //size of simulation grid
int color_dir = 0; //use direction color-coding or not
float scalar;
int newI, newJ;
float temp;
float vec_scale = 1000; //scaling of hedgehogs
int draw_vecs = 1; //draw the vector field or not
Ответ №1:
Фрагмент кода, который у вас там есть, мог бы быть написан проще (также требуется некоторое понимание того, что означают некоторые переменные и функции).
Давайте разберем это.
Первые две строки просты для понимания, это стандартная строка для перебора 2D-массива
for (i = 0; i < samplesX; i )
for (j = 0; j < samplesY; j )
i
и j
запускают индексы, которые будут повторяться по каждому кортежу дискретных координат в (i,j) ∈ [i, samplesX) × [j, samplesY)
. Следующие две строки переназначают 2D-индексы в новый диапазон значений, в частности [i, samplesX)×[j, samplesY) → [0, DIM)×[0, DIM)
. Недостающая часть информации заключается в том, какой тип является DIM
of. Это означало бы, что это должен быть какой-то тип с плавающей запятой.
newI = DIM * i / samplesX;
newJ = DIM * j / samplesY;
Следующая строка подвержена ошибкам. Он преобразует newI
и newJ
в работающий одномерный индекс для одномерного массива, который адресуется i
и j
.
Почему это проблематично? Потому что при преобразовании в формат DIM информация о пробелах могла быть потеряна. Такого рода потеря информации может привести к ошибкам безопасности (!), На самом деле, Skia, библиотека рендеринга, используемая Google Chrome, Android и другими проектами, недавно имела именно такую ошибку; статью стоит прочитать:https://googleprojectzero.blogspot.com/2019/02/the-curious-case-of-convexity-confusion.html
Правильный способ реализовать это — сделать DIM целым числом и выполнить над ним арифметику с фиксированной запятой, в конечном итоге усекая дробные цифры. Но я отвлекся. Следующий блок, по сути, выполняет поиск по таблице поиска для бедных людей. vx``vy
и fx``fy
представляют собой несколько сглаженных 2D-массивов, доступ к которым осуществляется через одномерный индекс, и direction_to_color
сопоставляются либо со значением, предположительно, либо с вызовом glColor
; то же самое, вероятно, относится и к set_colormap
. Это неправильное использование OpenGL.
Все переназначение из i
и j
в DIM
, а затем поисковые запросы — это просто плохая реализация поиска текстуры. В OpenGL уже есть текстуры. Просто загрузите как массив координат текстуры и включите текстурирование.
Наконец, для каждого корешка выполняется два вызова glVertex
, один с точкой наблюдения, которая находится в центрах сетки (wn, hn)
, в смещенном местоположении (wn, hn) (i, j)
.
Мой вердикт по этому коду: Полный мусор!Все это можно было бы сделать гораздо элегантнее, даже в 1994 году с OpenGL-1.0, для которого, похоже, был написан код. Если вы хотите реализовать свой собственный график векторного поля, не используйте это в качестве отправной точки.
В наши дни у нас есть программируемые графические процессоры с шейдерами. Все, что там можно сделать, — это несколько строк кода шейдера.
Комментарии:
1. Спасибо за ввод и объяснение. Этот код был предоставлен с намерением расширить его, поэтому, особенно в моем случае, я изо всех сил стараюсь ссылаться на исходный код при попытке реализовать новые функции. Теперь я предполагаю, что для повторения 3D-варианта вышеупомянутого фрагмента кода нам придется перебирать 3D-массив? Или есть более простое / правильное решение для реализации 3D-глифов?
2. @K.Saudi: Это назначение класса? Если это так, пожалуйтесь в свою школу, что вас учат сильно устаревшим знаниям, которые сегодня неактуальны за пределами поддержки устаревших кодовых баз. В любом случае, если они запрашивают 3D-корешки, хотят ли они, чтобы это было в 3D-сетке, или корешки должны быть направлены в 3D, но все еще находиться на 2D-сетке. Технически это не имеет большого значения, потому что 2D равно 3D с экстентом 3-го измерения, равным 1. Что касается того, как это сделать: для каждого
…x
и…y
вы бы ввели другой…z
и добавили и третий индекс. Послеi
иj
идетk
, так что это было бы подходящее имя.