Рисование моно chrome 2D массива в OpenGL - PullRequest
0 голосов
/ 07 февраля 2020

Мне нужно использовать OpenGL для очень конкретной c цели. У меня есть 1D массив с плавающей точкой размера [SIZE] [SIZE] (он всегда квадратный), который представляет 2D-изображение. Рисование здесь просто лишнее, поскольку я делал это с помощью третьих программ, выводя массив в текстовый файл, но я хотел бы дать возможность сделать это в самой программе.

Этот массив постоянно обновляется в al oop, поскольку он должен представлять значения моделируемого поля, детали которого не имеют никакого значения, но важно отметить, что значение каждого из них будет плавающим между -1 и 1 Теперь я хотел бы просто нарисовать этот массив как 2D-изображение (в режиме реального времени), каждые N шагов основного l oop. Я пытался использовать инструмент рисования пикселей X11 (я делаю это на Linux) и рисовать массив, просто зацикливая его и перемещаясь по пикселям в окне SIZE X SIZE, но это было очень медленно и занимало гораздо больше, чем сама симуляция. Я изучал OpenGL, и из того, что я прочитал, идеальным решением было бы повторно интерпретировать мой массив как 2D-текстуру, а затем распечатать его на четырехугольнике. Очевидно, что для использования голого OpenGL мне пришлось бы перечитать мой код для работы с основным l oop чертежа OpenGL, и это немного непрактично, поэтому, если то же самое можно сделать в GLFW, я доволен этим.

Изображение для рисования всегда квадратное, и его ориентация совершенно не имеет значения, не имеет значения, отрисовано ли оно зеркально, перевернуто, транспонировано и т. Д. c, так как оно должно быть полностью изотропным c .

Основной костяк программы следует следующей схеме

#include <iostream>
#include <GLFW/glfw3.h>
using namespace std;


int main(int argc, char** argv)
{
    if (GFX) //GFX is a bool, only draw stuff if it's 1 (its value doesnt change)
    {
        //Initialize GLFW
    }


    float field[2*SIZE][SIZE] = {0}; //This is the array to print (only the first SIZE * SIZE components)

    for (int i = 0; i < totalTime; i++)
    {
        for (int x=0; x < SIZE; x++)
        {
            for (int y=0; y < SIZE; y++)
            {
                //Each position of the array is then updates here
            }
        }
        if (GFX)
        {
            //The drawing should be done here
        }
    }
    return 0;
}

Я пробовал некоторые фрагменты кода и модифицировал некоторые другие примеры, которые я нашел, но не смог чтобы заставить его работать, либо они должны вызвать glL oop, который нарушает мою собственную симуляцию l oop, либо он просто печатает пиксель в центре.

Так что мой главный вопрос - как сделать текстуру из первых SIZE X SIZE компонентов field, а затем нарисуйте ее на КВАД.

Спасибо!

1 Ответ

1 голос
/ 09 февраля 2020

Самое простое для ладьи ie - использовать старый API без шейдеров. Для того, чтобы это работало, вы просто кодируете свои данные в 1D линейный массив с плавающей точкой в ​​диапазоне <0.0,1.0>, что можно сделать из <-1,+1> довольно быстро на стороне процессора с единичным значением для l oop, например:

for (i=0;i<size*size;i++) data[i]=0.5*(data[i]+1.0);

Я не использую ни GLUT, ни код для вашей платформы, поэтому я придерживаюсь только рендеринга:

//---------------------------------------------------------------------------
const int size=512;         // data  resolution
const int size2=size*size;
float data[size2];          // your float size*size data
GLuint txrid=-1;            // GL texture ID
//---------------------------------------------------------------------------
void init() // this must be called once (after GL is initialized)
    {
    int i;
    // generate float data
    Randomize();
    for (i=0;i<size2;i++) data[i]=Random();
    // create texture
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,txrid);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
    glDisable(GL_TEXTURE_2D);
    }
//---------------------------------------------------------------------------
void exit() // this must be called once (before GL is unitialized)
    {
    // release texture
    glDeleteTextures(1,&txrid);
    }
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClear(GL_COLOR_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // bind texture
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,txrid);
    // copy your actual data into it
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE32F_ARB, size, size, 0, GL_LUMINANCE, GL_FLOAT, data);

    // render single textured QUAD
    glColor3f(1.0,1.0,1.0);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0,0.0); glVertex2f(-1.0,-1.0);
    glTexCoord2f(1.0,0.0); glVertex2f(+1.0,-1.0);
    glTexCoord2f(1.0,1.0); glVertex2f(+1.0,+1.0);
    glTexCoord2f(0.0,1.0); glVertex2f(-1.0,+1.0);
    glEnd();

    // unbind texture (so it does not mess with othre rendering)
    glBindTexture(GL_TEXTURE_2D,0);
    glDisable(GL_TEXTURE_2D);

    glFlush();
    SwapBuffers(hdc);   // ignore this GLUT should make it on its own
    }
//---------------------------------------------------------------------------

Вот предварительный просмотр:

preview

Чтобы сделать это, вам нужно вызвать init() при запуске приложения после того, как GLUT создает контекст GL, и exit() в конце приложения, прежде чем GLUT закроет контекст GL. gl_draw() отобразит ваши данные, поэтому их нужно вызывать в событии рисования GLUT.

Если вы не хотите выполнять преобразование диапазона в <0,1> на стороне процессора, вы можете переместить его в шейдеры (очень простой вершинный и фрагментный шейдеры), но у меня возникло ощущение, что вы ладья ie, и шейдеров было бы просто слишком много для начала. Если вы действительно хотите go, то посмотрите:

Это также охватывает Инициализация GL без GLUT, но на Windows ...

Теперь некоторые примечания к программе выше:

  1. Я использовал GL_LUMINANCE32F_ARB расширение формата текстуры

    это 32-битный формат текстур с плавающей точкой, который не ограничен, поэтому ваши данные остаются как есть. Он должен присутствовать на всех современных gfx HW. Я сделал это, чтобы облегчить переход к последним шейдерам, где вы можете напрямую работать с вашими необработанными данными ...

  2. size

    в оригинальной спецификации GL размер текстуры должен быть степенью 2, так что 16,32,64,128,256,512, ... Если нет, вам нужно использовать расширение текстур прямоугольников, но это является родным для gfx HW уже многие годы, поэтому не нужно ничего менять. Но на linux и MA C могут быть проблемы с реализацией GL, поэтому, если что-то не работает, попробуйте использовать мощность 2 размера (на всякий случай) ...

    Также не слишком увлекайтесь с размером, поскольку у карт gfx есть ограничения, обычно 2048 - безопасный предел для вещей низкого уровня. Если вам нужно больше, тогда сделайте mosai c из большего числа квадов / текстур

  3. GL_CLAMP_TO_EDGE

    , это также расширение (теперь родное для HW), так что ваша текстура координаты go от 0 до 1 вместо от 0+pixel/2 до 1-pixel/2 ...

Однако все это не относится к GL 1.0, поэтому вам нужно добавить расширения в ваше приложение (если GLUT или что вы используете, еще не сделали). Все это просто токены / константы, а не вызовы функций, поэтому на случай, если компилятор жалуется, этого должно быть достаточно:

#include <gl\glext.h>

После включения gl.h или непосредственного добавления определений:

#define GL_CLAMP_TO_EDGE                  0x812F
#define GL_LUMINANCE32F_ARB               0x8818

кстати. ваш код не похож на приложение GLUT (но я могу ошибаться, поскольку я его не использую), например, посмотрите:

Ваш заголовок предлагает GLFW3 , что является чем-то совершенно иным (если оно не является производным от GLUT), чем GLUT , поэтому, возможно, вам следует отредактировать теги и OP, чтобы они соответствовали тому, что вы действительно используете / используете .

Теперь шейдеры:

, если вы генерируете свои данные в <-1,+1> диапазоне:

for (i=0;i<size2;i++) data[i]=(2.0*Random())-1.0;

И используете эти шейдеры:

Вершина:

// Vertex
#version 400 core
layout(location = 0) in vec2 pos;   // position
layout(location = 8) in vec2 tex;   // texture

out vec2 vpos;
out vec2 vtex;

void main()
    {
    vpos=pos;
    vtex=tex;
    gl_Position=vec4(pos,0.0,1.0);
    }

Фрагмент:

// Fragment
#version 400 core

uniform sampler2D txr;

in vec2 vpos;   // position
in vec2 vtex;   // texture

out vec4 col;

void main()
    {
    vec4 c;
    c=texture(txr,vtex);
    c=(c+1.0)*0.5;
    col=c;
    }

Тогда результат тот же (пример более быстрого преобразования на Сторона графического процессора). Однако вам необходимо преобразовать GL_QUADS в VAO / VBO (, если не используется карта nVidia , но даже тогда вам обязательно следует использовать VBO / VAO).

...