Получите код OpenGL старого стиля, работающий в GLSL

Я пытаюсь нарисовать этот шаблон в OpenGL:

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

Чтобы получить это, я создал шаблон как:

vector< vector<DataPoint> > datas;
float Intensitytemp=0;
float xPos=0, yPos=0, angleInRadians=0;
for (float theta = 0.0f; theta < 4096; theta += 1.f)
{
vector<DataPoint> temp;
angleInRadians = 2 * M_PI*theta / 4096;
for (float r = 0; r < 4096; r += 1.f)
{
xPos = cos(angleInRadians)*r / 4096;
yPos = sin(angleInRadians)*r / 4096;
Intensitytemp = ((float)((int)r % 256)) / 255;
DataPoint dt;
dt.x = xPos;
dt.y = yPos;
dt.Int = Intensitytemp;
temp.push_back(dt);
}
datas.push_back(temp);
}

и я рисую шаблон как:

glBegin(GL_POINTS);
for (int x = 0; x < 4096; x++)
for (int y = 0; y < 4096; y++)
{
xPos = datas[x][y].x;
yPos = datas[x][y].y;
Intensitytemp = datas[x][y].Int;
glColor4f(0.0f, Intensitytemp, 0.0f, 1.0f);
glVertex3f(xPos, yPos, 0.0f);
}
glEnd();

Если я создаю данные в glBegin()-glEnd() блок, он работает быстрее. Но в обоих случаях я считаю, что в GLSL все лучше. Я не очень хорошо понимаю логику современного OpenGL.

Я пытался создать массив буферов вершин и цветовые массивы, но не смог заставить его работать. Проблема была не в переносе массивов на видеокарту. Я получаю переполнение стека в массивах. Это вопрос другой темы но вот что мне интересно, можно ли выполнить эту задачу в полностью коде GLSL (те, в файле .vert) не перенося эти огромные массивы на видеокарту.

0

Решение

  1. рендеринг четырехугольника, охватывающего экран

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    GLint id;
    glUseProgram(prog_id);
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);
    
    glBegin(GL_QUADS);
    glColor3f(1,1,1);
    glVertex2f(-1.0,-1.0);
    glVertex2f(-1.0,+1.0);
    glVertex2f(+1.0,+1.0);
    glVertex2f(+1.0,-1.0);
    glEnd();
    
    glUseProgram(0);
    glFlush();
    SwapBuffers(hdc);
    

    Также см Смотрите полный пример GL + GLSL + VAO / VBO C ++ о том, как получить GLSL работает (даже новый материал)

    Не забудьте установить вид GL на квадратную область!

  2. в вершинном шейдере передайте координаты вершины фрагменту

    нет необходимости в матрицах … pos находится в диапазоне <-1.0,1.0> что хорошо для фрагмента.

    // Vertex
    varying vec2 pos;
    void main()
    {
    pos=gl_Vertex.xy;
    gl_Position=gl_Vertex;
    }
    
  3. во фрагменте вычислить расстояние от середины (0,0) и вычислить окончательный цвет из него

    // Fragment
    varying vec2 pos;
    void main()
    {
    vec4 c=vec4(0.0,0.0,0.0,1.0);
    float r=length(pos);    // radius = distance to (0,0)
    if (r<=1.0)             // inside disc?
    {
    r=16.0*r;           // your range 16=4096/256
    c.g=r-floor(r);     // use only the fractional part ... %256
    }
    gl_FragColor=c;
    }
    

    Вот результат:

    пример вывода

  4. Как работает GLSL

    Вы можете справиться с фрагментный шейдер в качестве механизма вычисления цвета для заливки полигонов. Это работает так:

    GL примитив проходит GL звонки в вершинный шейдер который отвечает за преобразования и предварительные вычисления констант. Вершинный шейдер называется для каждого glVertex звонок из старого стиля GL.

    Если поддерживается примитив (устанавливается glBegin в старом стиле GL) полностью (как TRIANGLE, QUAD, …) начала растеризации карты gfx. Это сделано HW вызов интерполяторов фрагментный шейдер для каждого «пикселя» для заполнения. Так как «пиксель» содержит гораздо больше данных, чем просто цвет, а также может быть отброшен … это называется фрагмент вместо. Его единственная цель — вычислить целевой цвет пикселя на экране, который он представляет. Вы не можете изменить свою позицию только цветом. Это самая большая разница между старым GL а также GLSL подход. Вы не можете изменить форму или положение объектов, только как они окрашены / затенены, следовательно, название шейдеры. Поэтому, если вам нужно сгенерировать определенный шаблон или эффект, вы обычно визуализируете некоторый примитив, покрывающий область, GL и перекрасить его вычислением внутри в основном фрагментный шейдер.

    Очевидно, что Вершинный шейдер не вызывается так часто, как Фрагмент шейдера в большинстве случаев перенесите как можно больше вычислений на Вершинный шейдер улучшить производительность.

    Новее GLSL версии поддерживают также геометрию и тесселяционные шейдеры но эта глава сама по себе и не важна для вас сейчас. (сначала нужно привыкнуть к вершине / фрагменту).

[Заметки]

не замужем if в таких простых шейдерах это не большая проблема. Основное увеличение скорости заключается в том, что вы проходите одиночный квад вместо 4096x4096 точки. Код шейдера полностью распараллелен gfx HW непосредственно. Вот почему архитектура … как ограничивает некоторые возможности того, что можно эффективно делать внутри шейдера, по сравнению со стандартным Процессор / МЕМ архитектуры.

[Edit1]

Вы можете часто избегать if по умным математическим трюкам вроде этого:

// Fragment
varying vec2 pos;
void main()
{
vec4 c=vec4(0.0,0.0,0.0,1.0);
float r=length(pos);            // radius = distance to (0,0)
r*=max(1.0+floor(1.0-r),0.0);   // if (r>1.0) r=0.0;
r*=16.0;                        // your range 16=4096/256
c.g=r-floor(r);                 // use only the fractional part ... %256
gl_FragColor=c;
}
2

Другие решения

Чтобы прямо ответить на ваш вопрос

Нет, теперь так работают шейдеры. Шейдеры переопределяют части конвейера рендеринга. В древнем OpenGL, где конвейер фиксирован, графический процессор использует встроенные процедуры шейдера для рендеринга примитивов, которые вы загружаете в него через glBegin/glEnd связанные звонки. Однако в более поздних версиях OpenGL вы можете написать собственные подпрограммы для использования вашим графическим процессором. В обоих случаях, вам нужно отправить данные для шейдеров для работы.

Чтобы дать вам лучший подход о том, как это сделать

Во-первых, вершинный шейдер питается данными вершин. Он принимает вершины и оперирует ими по одному, применяя различные преобразования (путем умножения вершины на матрицы модель-вид-проекция). Как только это будет сделано для каждой вершины, область, созданная путем соединения вершин, будет разбита на значения координат (среди прочего, вы можете перейти от вершинного шейдера к фрагментному шейдеру) в процессе, который называется растеризации. Эти координаты, каждая из которых представляет местоположение пикселя на экране, затем передаются фрагментному шейдеру, который воздействует на них, чтобы установить цвет и применить любой расчет освещения.

Теперь, поскольку вы пытаетесь нарисовать шаблон с формулой, вы можете закрасить квадрат 4096×4096, отправив буквально 4 вершины, так как вы хотите получить тот же результат.

Вершинный шейдер:

#version 150

in vec2 vertexPos;
out vec2 interpolatedVertexPos;

void main()
{
interpolatedVertexPos = vertexPos;
}

Фрагмент шейдера:

#version 1.5

in vec2 interpolatedVertexPos;
out vec4 glFragColor;

void main()
{
const vec2 center = vec2(2048, 2048);
float distanceFromCenter = sqrt(pow((interpolatedVertexPos.x-center.x), 2) + pow((interpolatedVertexPos.y-center.y), 2));
if (distanceFromCenter > 2048){
discard;
}
float Intensitytemp = ((float)((int)distanceFromCenter % 256)) / 255;
glFragColor = vec4(0, Intensitytemp , 0, 1);
}

Изменить: Я подумал, что вы также можете найти этот ответ полезным:
OpenGL большие проекты, VAO-ы и многое другое

0

По вопросам рекламы [email protected]