воскресенье, 22 ноября 2015 г.

Настройка рабочей среды для начала работы с OpenGL

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

Операционная система - Windows 7 x64 (она стоит на моем ноутбуке), а в качестве IDE выбран Visual Studio 2013 Express (очень удобный инструмент и доступен бесплатно).
Проблема в том, что нельзя просто взять и нарисовать треугольник.


Чтобы это сделать, нужно создать контекст, в котором мы будем рисовать и обрабатывать ввод-вывод. Для этого существуют специальные библиотеки. GLFW кажется мне достаточно подходящей для этой цели. Загружаем с сайта заголовочные файлы и бинарники. Но и этого недостаточно, потому что Visual Studio поставляется с заголовочными файлами для спецификации OpenGL 1.1, которая вышла ну очень давно, более 20 лет назад. Так что нам нужны еще свежие заголовочные файлы и я выбрал библиотеку GLEW, которая содержит не только свежие заголовочные файлы, но и еще много чего полезного.

Теперь приступаем к установке библиотек:
- распаковываем и скачанные архивы;
- копируем заголовочные файлы, чтобы Visual Studio мог ими пользоваться. В моем случае это было содержимое папок include в архивах, скопированное в папку "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include". Теперь там появились две новые папки с заголовочными файлами: GL и GLFW;
- копируем glfw3.lib, glew32.lib и glew32s.lib в "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\lib" (обратите внимание, что нужно использовать 32-битные версии этих файлов, т.к. Visual Studio генерирует 32-битные версии бинарных файлов);
- копируем glew32.dll и glfw3.dll в папку C:Windows\System (тоже используем 32-битные версии файлов).

Идем дальше. Открываем Visual Studio, создаем простое консольное приложение и настраиваем его: в "Configuration Properties => Linker => Input => Additional Dependencies" добавляем библиотеки glew32s.lib, glew32.lib, glfw3.lib, OpenGL32.lib:


Теперь можно попробовать запустить простой пример:
 
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
 
// Shader sources
const GLchar* vertexSource =
"#version 150 core\n"
"in vec2 position;"
"in vec3 color;"
"out vec3 Color;"
"void main() {"
"   Color = color;"
"   gl_Position = vec4(position, 0.0, 1.0);"
"}";
 
const GLchar* fragmentSource =
"#version 150 core\n"
"in vec3 Color;"
"out vec4 outColor;"
"void main() {"
"   outColor = vec4(Color, 1.0);"
"}";
 
int main(int argc, char* argv[])
{
 glfwInit();
 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
 
 glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
 
 GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr); // Windowed
 //GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", glfwGetPrimaryMonitor(), nullptr); // Fullscreen
 
 glfwMakeContextCurrent(window);
 
 // Initialize GLEW
 glewExperimental = GL_TRUE;
 glewInit();
 
 // Create Vertex Array Object
 GLuint vao;
 glGenVertexArrays(1, &vao);
 glBindVertexArray(vao);
 
 // Create a Vertex Buffer Object and copy the vertex data to it
 GLuint vbo;
 glGenBuffers(1, &vbo);
 
 GLfloat vertices[] = {
  0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
  0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
  -0.5f, -0.5f, 0.0f, 0.0f, 1.0f
 };
 
 glBindBuffer(GL_ARRAY_BUFFER, vbo);
 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
 
 // Create and compile the vertex shader
 GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
 glShaderSource(vertexShader, 1, &vertexSource, NULL);
 glCompileShader(vertexShader);
 
 // Create and compile the fragment shader
 GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
 glCompileShader(fragmentShader);
 
 // Link the vertex and fragment shader into a shader program
 GLuint shaderProgram = glCreateProgram();
 glAttachShader(shaderProgram, vertexShader);
 glAttachShader(shaderProgram, fragmentShader);
 glBindFragDataLocation(shaderProgram, 0, "outColor");
 glLinkProgram(shaderProgram);
 glUseProgram(shaderProgram);
 
 // Specify the layout of the vertex data
 GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
 glEnableVertexAttribArray(posAttrib);
 glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);
 
 GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
 glEnableVertexAttribArray(colAttrib);
 glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
 
 //main loop
 while (!glfwWindowShouldClose(window))
 {
  if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
   glfwSetWindowShouldClose(window, GL_TRUE);
 
  // Clear the screen to black
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);
 
  // Draw a triangle from the 3 vertices
  glDrawArrays(GL_TRIANGLES, 0, 3);
 
  glfwSwapBuffers(window);
  glfwPollEvents();
  //glfwShowWindow(window);
 }
 
 glDeleteProgram(shaderProgram);
 glDeleteShader(fragmentShader);
 glDeleteShader(vertexShader);
 
 glDeleteBuffers(1, &vbo);
 
 glDeleteVertexArrays(1, &vao);
 
 glfwTerminate();
 
 return 0;
}




Если все сделано правильно, мы должны увидеть такой результат:
Ссылки на использованные материалы:
Setting up Windows Environment Window and OpenGL context GLEW installation