Как рисовать точки в случайных местах, но в пределах границ экрана или окна - PullRequest
0 голосов
/ 11 октября 2018

Я использую библиотеку OpenGL в своем приложении Visual C ++, где я хочу нарисовать, скажем, 100 точек в случайных местах, и я хотел бы проверить, находятся ли эти точки случайных координат или случайных местоположений, которые генерируются, в пределах границ экрана или окна,Я устал, используя (x, y, z) вариант вершины, и я получаю точки по вертикали, идущие вдоль линии.Если я попытаюсь сгенерировать только (x, y) и нарисовать их, то получу гораздо больше разбросанных точек, но определенно не все 100 в пределах размеров окна.

мой код выглядит примерно так:

GLfloat dots_vert[99];
for (int i = 0; i < 99; i++){

if (i % 2 == 0)
    dots_vert[i] = 0.0f;

else
    dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*100.0f - (100.0f / 2);
}


glEnable(GL_POINT_SMOOTH);
glPointSize(3.0f);
glEnableClientState(GL_VERTEX_ARRAY);

GLuint vbo_ID;
glGenBuffers(1, &vbo_ID);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glBufferData(GL_ARRAY_BUFFER, sizeof(dots_vert), dots_vert, GL_DYNAMIC_DRAW);
while (!GetAsyncKeyState(VK_DOWN)){
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glVertexAttribPointer(
    0,                  
    3,                  
    GL_FLOAT,           
    GL_FALSE,           
    0,                  
    (void*)0            
    );
glDrawArrays(GL_POINTS, 0, 100);
SwapBuffers(g_pOpenGLWindow->hDC);

1 Ответ

0 голосов
/ 12 октября 2018

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

Прежде всего очевидная первая ошибка: вы утверждаете, что рисуете 100 точек, но ваш массив dots_vert только99 элементов длиной.Это повторяется в следующем цикле, где вы переходите от 0 к 98 всего 99 раз.

Итак, прежде всего:

GLfloat dots_vert[100];
for (int i = 0; i < 100; ++i)
{
    [...]
}

ЕстьЭто еще одна огромная ошибка, но мы ее оставим на потом, а теперь давайте двигаться дальше.

Вторая ошибка связана со знанием API OpenGL и компьютерной графики.Прежде всего, ваша цель состоит в том, чтобы передавать очки в GPU, поэтому вам нужна функция glVertexAttribPointer, которую вы так сильно разобрались.Абсолютно первое, что вы хотите сделать, это посмотреть справочную документацию glVertexAttribPointer , чтобы вы имели представление о том, что вам нужно.Вам нужны index, size, type, normalized флаг, stride и offset.

Давайте посмотрим, что в справочной документации говорится о size параметр:

размер

Указывает количество компонентов на общий атрибут вершины.Должно быть 1, 2, 3, 4. Кроме того, символическая константа GL_BGRA принимается glVertexAttribPointer.Начальное значение равно 4.

Это сразу же очевидно, чтобы иметь решающее значение при определении того, какие данные вы пытаетесь передать в графический процессор.Вы устанавливаете параметр на 3, что означает, что у вас есть x, y и z.Но предыдущий код противоречит этому.Для начала, ваш массив dots_vert имеет длину 100 элементов, и вы хотите нарисовать 100 точек, так что вам достаточно для 100/100 = 1 компонента на точку, а не 3.Но что еще хуже, внутренняя часть цикла for противоречит этому еще больше, поэтому давайте вернемся и проверим ошибку, о которой я упоминал ранее.

Ошибка номер три: ваш цикл for состоит из if {} else {}оператор, в котором для текущего элемента массива dots_vert установлено значение 0.0f, если индекс цикла четный (if (i % 2 == 0)), и случайное значение между -50.0f и 50.0f в противном случае.Предполагая 1 компонента на точку, это означает, что вы генерируете только x координаты, поэтому вы работаете в одном измерении.

Очевидно, что это не то, что вы намеревались сделать, также потому, чтополовина ваших очков будет 0.0f, и поэтому все они будут перекрываться.Поэтому я предполагаю, что вы пытались сгенерировать случайное значение для x и y и установить z на 0.0f, что имело бы гораздо больше смысла.Прежде всего, у вас есть 3 компонентов на точку, и поэтому вам понадобится массив с 100*3 = 300 элементами.Итак, прежде всего, давайте исправим предыдущий код:

GLfloat dots_vert[300];
for (int i = 0; i < 300; ++i)
{
    [...]
}

Намного лучше.Теперь нам нужно сгенерировать случайное значение x и y для каждой точки и установить z в 0.0f, поскольку нам это не нужно.Вы хотите выполнить все компоненты одновременно в одном цикле, поэтому вы хотите, чтобы ваш цикл шагал по 3, а не 1, поэтому еще раз исправим предыдущий код:

GLfloat dots_vert[300];
for (int i = 0; i < 300; i += 3)
{
    [...]
}

Теперьмы можем создать x, y и z вместе в одном цикле.Это критически важная часть понимания работы компьютерной графики, особенно в контексте API OpenGL.OpenGL использует систему координат, где начало координат находится в середине экрана, ось x движется горизонтально (положительные x точки направо), ось y движется вертикально (положительные y точки вверх),и ось z идет прямо через экран (положительные z указывают за пределы экрана к вам).Теперь это очень важная часть: x, y и z обрезаются до определенного диапазона значений;все, что находится за пределами этого диапазона, игнорируется.Для всех координат диапазон изменяется от -1.0f до 1.0f.Все, что ниже, выше, вообще не нарисовано.

Итак, если вы хотите, чтобы 100 точек находились внутри экрана, игнорируя проекцию, выходящую за рамки этого упражнения, вы хотите сгенерировать x и y в -1.0f до 1.0f диапазон, а не -50.0f до 50.0f, как вы делаете там.Вы можете оставить от z до 0.0f, в данном случае это не имеет значения.Вот почему большинство ваших точек находятся за пределами экрана: с этой точки зрения, по статистике, около 98% ваших точек будут выходить за пределы пространства клипа и будут игнорироваться.

Так что в конечном итоге это то, что выwant:

GLfloat dots_vert[300];
for (int i = 0; i < 300; i += 3)
{
    dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x
    dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y
    dots_vert[i+2] = 0.0f; // this is z
}

Напоследок напоминание: когда вы делаете glDrawArrays(GL_POINTS, 0, 100);, вы говорите графическому процессору рисовать 100 очков.Каждая точка состоит из множества компонентов, указанных вами в параметре size функции glVertexAttribPointer.В этом случае вы хотите нарисовать 100 точек, каждая точка состоит из 3 компонентов, поэтому графический процессор ожидает массив 100*3 = 300 с плавающей точкой.номера.Все, что меньше, может привести либо к ошибке сегментации, либо, что еще хуже, к неопределенному поведению (что означает, что все может произойти), поэтому внимательно следите за тем, что вы делаете, и убедитесь, что вы точно знаете, какие данные вы передаете в графический процессор.потому что у вас может получиться бессмысленный результат, и вы застрянете, пытаясь понять, что пошло не так.В этом случае у вас практически нет кода для проверки, поэтому его легко исправить, но когда вы получите приличный объем кода (и вы в конечном итоге), такая ошибка может привести к потере часов или даже днейпытаясь найти ошибку.

В качестве бонуса, не стесняйтесь игнорировать это: технически точка состоит из 4 компонентов.Этот компонент называется w, и его использование выходит за рамки данного упражнения, поэтому не беспокойтесь об этом, просто помните, что для него всегда должно быть установлено значение 1.0f, если только вы не выполняете проецирование.

Так что технически вы могли бы сделать это тоже:

GLfloat dots_vert[400];
for (int i = 0; i < 400; i += 4)
{
    dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x
    dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y
    dots_vert[i+2] = 0.0f; // this is z
    dots_vert[i+3] = 1.0f; // this is w
}

Затем вы устанавливаете параметр size для glVertexAttribPointer равным 4 вместо 3, результат должен быть точно таким же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...