Нужна помощь в понимании работы с 2D / 3D глифами - PullRequest
1 голос
/ 07 марта 2019

Вот фрагмент кода, который я хотел бы помочь понять

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 && draw_vecs == 1) {
                direction_to_color(vx[idx], vy[idx], color_dir);
            }
            if (color_dir == 1 && 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 Ответ

0 голосов
/ 08 марта 2019

Фрагмент кода, который у вас там есть, мог бы быть написан проще (также нужно уметь догадываться, что означают некоторые переменные и функции).

Давайте разберемся с этим.

Первые две строки легко понять, это стандартная строфа для перебора 2D-массива

for (i = 0; i < samplesX; i++)
        for (j = 0; j < samplesY; j++)

i и j - это запущенные индексы, которые будут повторяться по каждому кортежу дискретных координат в (i,j) ∈ [i, samplesX) × [j, samplesY). Следующие две строки преобразуют двумерные индексы в новый диапазон значений, в частности [i, samplesX)×[j, samplesY) → [0, DIM)×[0, DIM). Отсутствует информация о том, какого типа DIM из. Это будет для некоторого типа с плавающей точкой.

     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 - некоторые плоские двумерные массивы, доступ к которым осуществляется через одномерный индекс, а direction_to_color отображает либо значение , предположительно , на вызов glColor; то же самое, вероятно, относится и к set_colormap. Это плохое использование OpenGL.

Целое переназначение от i и j до DIM, а затем поиск - просто плохая реализация поиска текстуры. OpenGL уже имеет текстуры. Просто загрузите как массив координат текстуры и включите текстурирование.

Наконец, для каждого позвоночника выполняются два вызова glVertex, один с начальной точкой, которая лежит на центрах сетки (wn, hn), в местоположение смещения (wn, hn) + (i, j).

Мой вердикт этого кода: Полный мусор! Все это можно было бы сделать гораздо более элегантно, даже в 1994 году с OpenGL-1.0, для которого, похоже, написан код. Если вы хотите реализовать свой собственный векторный график, не используйте его в качестве отправной точки.

В наши дни у нас есть программируемые графические процессоры с шейдерами. Все, что можно сделать, - это несколько строк шейдерного кода.

...