Opengl: Как текстурировать модель, созданную с помощью массива вершин?

Я пытаюсь уйти от немедленного режима, потому что мне постоянно говорят, что это действительно не лучший способ программирования на Opengl. Я нашел учебник, который сделает куб и раскрасит его, но он не охватывает текстурирование.

Это код, который у меня есть:

GLfloat vertices[] = { 1, 1, 1,  -1, 1, 1,  -1,-1, 1,   1,-1, 1,   // v0,v1,v2,v3 (front)
                        1, 1, 1,   1,-1, 1,   1,-1,-1,   1, 1,-1,   // v0,v3,v4,v5 (right)
                        1, 1, 1,   1, 1,-1,  -1, 1,-1,  -1, 1, 1,   // v0,v5,v6,v1 (top)
                       -1, 1, 1,  -1, 1,-1,  -1,-1,-1,  -1,-1, 1,   // v1,v6,v7,v2 (left)
                       -1,-1,-1,   1,-1,-1,   1,-1, 1,  -1,-1, 1,   // v7,v4,v3,v2 (bottom)
                        1,-1,-1,  -1,-1,-1,  -1, 1,-1,   1, 1,-1 }; // v4,v7,v6,v5 (back)

// normal array
GLfloat normals[]  = { 0, 0, 1,   0, 0, 1,   0, 0, 1,   0, 0, 1,   // v0,v1,v2,v3 (front)
                        1, 0, 0,   1, 0, 0,   1, 0, 0,   1, 0, 0,   // v0,v3,v4,v5 (right)
                        0, 1, 0,   0, 1, 0,   0, 1, 0,   0, 1, 0,   // v0,v5,v6,v1 (top)
                       -1, 0, 0,  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,   // v1,v6,v7,v2 (left)
                        0,-1, 0,   0,-1, 0,   0,-1, 0,   0,-1, 0,   // v7,v4,v3,v2 (bottom)
                        0, 0,-1,   0, 0,-1,   0, 0,-1,   0, 0,-1 }; // v4,v7,v6,v5 (back)

// color array
GLfloat colors[]   = { 1, 1, 1,   1, 1, 0,   1, 0, 0,   1, 0, 1,   // v0,v1,v2,v3 (front)
                        1, 1, 1,   1, 0, 1,   0, 0, 1,   0, 1, 1,   // v0,v3,v4,v5 (right)
                        1, 1, 1,   0, 1, 1,   0, 1, 0,   1, 1, 0,   // v0,v5,v6,v1 (top)
                        1, 1, 0,   0, 1, 0,   0, 0, 0,   1, 0, 0,   // v1,v6,v7,v2 (left)
                        0, 0, 0,   0, 0, 1,   1, 0, 1,   1, 0, 0,   // v7,v4,v3,v2 (bottom)
                        0, 0, 1,   0, 0, 0,   0, 1, 0,   0, 1, 1 }; // v4,v7,v6,v5 (back)

// index array of vertex array for glDrawElements() & glDrawRangeElement()
GLubyte indices[]  = { 0, 1, 2,   2, 3, 0,      // front
                       4, 5, 6,   6, 7, 4,      // right
                       8, 9,10,  10,11, 8,      // top
                      12,13,14,  14,15,12,      // left
                      16,17,18,  18,19,16,      // bottom
                      20,21,22,  22,23,20 };    // back

// Initialization routine.
void setup(void)
{
   glClearColor(0.0, 0.0, 0.0, 0.0);
   glEnable(GL_DEPTH_TEST); // Enable depth testing.


}

// Drawing routine.
void drawScene()
{
   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glLoadIdentity();

    // enable and specify pointers to vertex arrays
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);
    glNormalPointer(GL_FLOAT, 0, normals);
    glColorPointer(3, GL_FLOAT, 0, colors);
    glVertexPointer(3, GL_FLOAT, 0, vertices);

    glPushMatrix();
    glTranslatef(0, 0, -5);

    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);

    glPopMatrix();

    glDisableClientState(GL_VERTEX_ARRAY);  // disable vertex arrays
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);

   glutSwapBuffers();
}

// OpenGL window reshape routine.
void resize (int w, int h)
{
   glViewport (0, 0, (GLsizei)w, (GLsizei)h);
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(60.0, (float)w/(float)h, 1.0, 20.0);
   glMatrixMode(GL_MODELVIEW);
}

// Keyboard input processing routine.
void keyInput(unsigned char key, int x, int y)
{
   switch (key) 
   {
      case 27:
         exit(0);
         break;
      default:
         break;
   }
}

// Callback routine for non-ASCII key entry.
void specialKeyInput(int key, int x, int y)
{
   //if(key == GLUT_KEY_UP) if (step < 180) step++;;
   //if(key == GLUT_KEY_DOWN) if (step > 0) step--;;
   glutPostRedisplay();
}

// Routine to output interaction instructions to the C++ window.
void printInteraction(void)
{
   cout << "Interaction:" << endl;
}

// Main routine.
int main(int argc, char **argv) 
{
   printInteraction();
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); 
   glutInitWindowSize (500, 500);
   glutInitWindowPosition (100, 100);
   glutCreateWindow ("sphereInBox2.cpp");
   setup();
   glutDisplayFunc(drawScene);
   glutReshapeFunc(resize);
   glutKeyboardFunc(keyInput);
   glutSpecialFunc(specialKeyInput);
   glutMainLoop();

   return 0;
}

Этот код создаст куб, поэтому я хотел бы знать, как текстурировать каждую сторону по отдельности и как текстурировать всю модель с помощью 1 текстуры. Что ты посоветуешь?


person WhyYouNoWork    schedule 03.01.2015    source источник
comment
Вам нужен массив координат текстуры, который будет отображаться в одну развернутую текстуру, содержащую все 6 граней вашего куба. Найдите UV mapping и unwrapping, это ключевые слова методики.   -  person j-p    schedule 03.01.2015
comment
Если я скажу вашим glEnableClientState(GL_TEXTURE_COORD_ARRAY) и glTexCoordPointer, это даст вам подсказку? ;-)   -  person datenwolf    schedule 03.01.2015
comment
@datenwolf Я добавил их оба в свой проект. Я сделал переменную texcoord для указателя координат, но не вижу разницы. Что мне не хватает?   -  person WhyYouNoWork    schedule 04.01.2015
comment
@WhyYouNoWork: Ну, в первую очередь вам нужен объект текстуры. ответ Игги довольно полный. Вы можете игнорировать `glActiveTexture' на данный момент; это функциональность OpenGL-1.2, которую, как и все, что выше OpenGL-1.1, вы должны загружать во время выполнения с помощью механизма расширения (просто используйте для этого GLEW). Загрузите текстуру после создания контекста OpenGL. Затем, когда вы хотите использовать glBindTexture и для конвейера фиксированной функции glEnable(GL_TEXTURE_2D). Но, честно говоря, вы не должны учиться устаревшему способу ведения дел.   -  person datenwolf    schedule 04.01.2015
comment
@datenwolf Ты потерял меня. Не могли бы вы предоставить более подробную информацию?   -  person WhyYouNoWork    schedule 04.01.2015
comment
@WhyYouNoWork: Ну, есть два вида OpenGL. Старый, устаревший, который следует дизайну API, заложенному в 1994 году. А затем есть современный OpenGL, который покончил (скатертью дорога) со всем устаревшим хламом. До сих пор вы программировали для устаревших вещей. Я предлагаю вам посмотреть учебник по современному OpenGL; очень хороший вариант вы можете найти на arcsynchronous.org/gltut — однако есть два недостатка: Контекст OpenGL требует немного больше усилий. А использование современного OpenGL требует, чтобы вы выполнили всю работу, которая использовалась для его создания; преимущество заключается в том, что он гораздо более универсален.   -  person datenwolf    schedule 04.01.2015
comment
@datenwolf Мне трудно следовать этому руководству. Это сбивает меня с толку, потому что нет полного кода, а то, что они показывают, не компилируется. Есть ли на сайте место для просмотра примеров кода?   -  person WhyYouNoWork    schedule 05.01.2015
comment
@WhyYouNoWork: Если вы внимательно прочитаете arc Synthesis.org/gltut/Building%20the%20Tutorials.html вы найдете ссылку для скачивания архива со всеми исходными кодами: bitbucket.org/alfonse /gltut/downloads — это также объясняется в главе «Создание учебных пособий», какие инструменты вам нужны и как их создавать.   -  person datenwolf    schedule 05.01.2015
comment
@datenwolf Я читал учебник, но все еще теряюсь в нем. Я нахожу современный Opengl очень сложным. Для начала, в чем разница между glDrawArrays и glDrawElements?   -  person WhyYouNoWork    schedule 15.01.2015
comment
@WhyYouNoWork: glDrawArrays последовательно обрабатывает элементы в массивах вершин. glDrawElements принимает другой массив, содержащий список индексов, в массив вершин для последовательной обработки.   -  person datenwolf    schedule 15.01.2015
comment
@datenwolf Интересно. Есть ли причина отдавать предпочтение тому или другому? Похоже, они делают одно и то же.   -  person WhyYouNoWork    schedule 22.01.2015
comment
@WhyYouNoWork: они делают разные вещи. Допустим, вы хотите провести несколько линий из центральной точки (в форме звезды). Пусть центральная точка находится в индексе 0, а окружающие точки 1, 2, 3, …; затем, чтобы нарисовать звезду, вы должны нарисовать линии (0,1), (0,2), (0,3), … . Используя glDrawElements, вы можете дать OpenGL список 0,1,0,2,0,3,… и он нарисует его вот так. Используя glDrawArrays, вы указываете OpenGL рисовать с индексами, увеличивающимися в диапазоне, то есть 0,1,2,3,… — рисование, которое рисует линию из центральной точки, а затем соединяет каждую другую пару точек по окружности линиями.   -  person datenwolf    schedule 23.01.2015
comment
@datenwolf Боюсь, я до сих пор не совсем понимаю. Значит, glDrawArray просто считывает x координат за раз, а затем делает рожу?   -  person WhyYouNoWork    schedule 24.01.2015
comment
@WhyYouNoWork: я написал небольшую программу, которая имитирует режимы доступа OpenGL glDrawArrays и glDrawElements. Надеюсь, это поможет вам понять. Вы можете найти и поэкспериментировать с ним здесь: codepad.org/zePO6Pe6 или здесь ideone.com/9JSqFk   -  person datenwolf    schedule 24.01.2015


Ответы (1)


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

GLfloat texcoords[] = {
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    0.0f, 1.0f,
};

Для каждой вершины грани куба необходимо указать UV-координаты, соответствующие некоторому расположению на текстуре. Вы должны указать координаты для всех 6 сторон, и большую часть времени они будут в другом порядке.

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

Затем вам нужно будет загрузить текстуру, используя другую библиотеку, например SOIL. Он вернет вам указатель на пиксели, которые вы позже сможете передать в OpenGL.

Вот как это выглядит с OpenGL. Сначала мы создаем новую текстуру, задаем некоторые параметры и заполняем ее пикселями, которые мы загрузили с помощью внешней библиотеки.

glGenTextures(1, &testTexture);
glBindTexture(GL_TEXTURE_2D, testTexture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, &texData[0]
);

Чтобы окончательно отрендерить эту текстуру, вы должны привязать ее как активную текстуру:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, testTexture);

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

person Iggy    schedule 03.01.2015
comment
Боюсь, вы меня потеряли. Я понимаю текстуркоорд. Требуется прописать текстуру на лицо и я так понимаю и она накладывает на нее определенный процент изображения. У меня есть несколько функций для загрузки png: codepad.org/ygG2U0cF. Хотя я не знаю, что делать дальше. glActiveTexture не определено, и ваш последний абзац после этого пролетел мимо меня. Не могли бы вы уточнить? - person WhyYouNoWork; 04.01.2015
comment
@WhyYouNoWork Возможно, я мог бы порекомендовать вам этот превосходный учебник? - person Iggy; 04.01.2015
comment
Я читаю учебник, но я застрял. Я не понимаю, как заставить ПОЧВУ работать. Я не могу запустить ни один из файлов, включенных в него. Он продолжает говорить мне, что файл повреждается, когда я пытаюсь его преобразовать. Что происходит? - person WhyYouNoWork; 04.01.2015
comment
@WhyYouNoWork Создание библиотек и обеспечение их работы в вашем проекте — это отдельный навык. Вы можете опубликовать еще один вопрос о SOIL на StackOverflow. - person Iggy; 05.01.2015
comment
У меня есть .lib для компиляции, и я могу правильно скомпилировать свой проект, но у меня проблемы с руководством, которое вы мне прислали. Я нахожусь в разделе Применение текстур, где вы сказали, что это самая сложная часть. Это совершенно не укладывается у меня в голове. Что ты собираешься делать? - person WhyYouNoWork; 05.01.2015
comment
@WhyYouNoWork Возможно, вы могли бы вернуться на главу назад, чтобы лучше понять шейдеры? - person Iggy; 05.01.2015
comment
Я посмотрел учебник по шейдерам, но мне все еще трудно его понять. Меня действительно смущает то, как этот человек создал свой учебник. Они сломали свой код, и каждый раз, когда они показывают код, он не завершен. Как настроить шейдер на C++? Какой в ​​них смысл? Я чувствую, что этот человек что-то упускает. - person WhyYouNoWork; 05.01.2015
comment
Шейдеры @WhyYouNoWork не написаны на C++, обычно это небольшие внешние файлы, которые загружаются C++ и передаются в OpenGL для компиляции, которая будет выполняться на графическом процессоре для каждой вершины и фрагмента. На ваш вопрос сложно ответить одним комментарием, я могу только порекомендовать вам прочитать все возможные учебники, которые вы можете найти по этому вопросу, и если у вас есть конкретный вопрос, опубликуйте его на StackOverflow. - person Iggy; 05.01.2015