Tutoriales OpenGL 3.1

De Codepixel

Contenido

[editar] General

conceptos que hay que saber de OpenGL y de opengl 3.1.


Para una introducción sobre OpenGL 3.x, visita la presentación de NVIDIA en el gdc2009.

[editar] Guías

[editar] Tutorial 0 (boceto)

Para entender los tutoriales a continuación, hace falta conocer algunas cosas sobre cómo funciona OpenGL internamente.


Inicialmente tenemos que saber cómo se calcula el color de los píxeles en pantalla cuando dibujamos un triángulo.

Primero, todo triángulo deberá ser procesado para calcular en qué posición queda cada vértice en pantalla. Puede haber rotaciones, escalados, traslaciones e incluso proyecciones.

Antes este proceso lo hacía OpenGL internamente en base a ciertos parámetros, pero ahora deberemos hacerlo nosotros manualmente, utilizando un Vertex Shader. Estos shaders son pequeños programas en GLSL (un lenguaje similar a C), que se ejecutan en la gráfica. Aunque pueda parecer complicado, el propio lenguaje GLSL nos ayuda bastante, y siempre podemos usar librerías externas como GLM para las cosas que no resulten fáciles en un primer momento. La ventaja de todo esto es que tenemos libertad absoluta para aplicar las operaciones que queramos, y optimizar el rendimiento al hacer siempre las operaciones que queremos, y ninguna más.


Bien, una vez calculadas las posiciones de los vértices en pantalla, la gráfica calcula qué pixeles en pantalla quedan cubiertos por el triángulo. A cada uno de esos pixeles, tendrá que asignarle un color.

La asignación de color es otro punto que antes se hacía en base a parámetros, y que ahora es programable. Igual que antes teníamos que usar un Vertex Shader, para esto deberemos usar un Fragment Shader. Al igual que antes, están programados en GLSL, y no tienen por qué ser difíciles de usar.


Otro punto importante que suele sorprender es que las propiedades que queremos que tenga un polígono deben estar completamente definidas antes de llamar a la operación de render. Una vez hayamos dicho a OpenGL que queremos dibujar un polígono con un cierto material y propiedades, esta información 'fluye' por el cauce gráfico y no podremos modificar la forma en la que se dibujará en pantalla.


Para programar en OpenGL 3 también tenemos que saber que ahora todo funciona con objetos almacenados en la propia tarjeta gráfica. Es decir, los polígonos, los shaders, las texturas, etc, todo debe ser almacenado en la gráfica para luego, con una simple llamada, lanzar el render de un bloque de miles de polígonos, o seleccionar una textura para aplicar a los polígonos.


También, antes de ponernos a mostrar cosas en pantalla, necesitaremos algo de código que monte la ventana de OpenGL y nos permita empezar a mandar comandos. Para esto usaremos este código que utiliza GLUT para la creación de la ventana y la gestión de eventos.

#include "GLee.h" // Necesitamos GLee para hacer que funcione en Windows
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
 
#ifdef __APPLE__ // En MacOS los includes son distintos
    #include <GLUT/glut.h>
#else
    #include <GL/glut.h>
#endif
 
int window;
 
// Función de inicialización de OpenGL
void InitGL (int windowWidth, int windowHeight, int windowDepth, const char * windowTitle)
{
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
    glutInitWindowSize(windowWidth,windowHeight);
    window = glutCreateWindow(windowTitle);
 
    // LA INICIALIZACION VA AQUI
}
 
// Función que controla las teclas pulsadas
void keyPressed(unsigned char key, int x, int y)
{
    if (key == 27 /*ESCAPE*/)
    {
        glutDestroyWindow(window);
        exit(1);
    }
}
 
// Función que se encarga del render
void DrawGLScene()
{
    // TODO EL PROCESO DE RENDER VA AQUI
}
 
// Se encarga de redimensionar la parte de la ventana 
// en la que dibuja OpenGL cuando se redimensiona esta
void ReSizeGLScene(int width, int height)
{
    glViewport(0, 0, width, height);
}
 
int main(int argc, char ** argv)
{
    glutInit(&argc, argv);
    InitGL(800,600,24,"OpenGL Tutorial1"); // Inicializamos
 
    // Indicamos qué función se va a encargar de cada tarea
    glutDisplayFunc(&DrawGLScene);
    glutIdleFunc(&DrawGLScene);
    glutReshapeFunc(&ReSizeGLScene);
    glutKeyboardFunc(&keyPressed);
 
    // Iniciamos el bucle principal del programa
    glutMainLoop();
    return 1;
}

[editar] Hello World

#include <stdio.h>
 
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#else
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#endif
 
#include <stdlib.h>
#include <math.h>
#define ESCAPE 27
 
int window;
 
void InitGL (int windowWidth, int windowHeight, int windowDepth, const char * windowTitle)
{
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize(windowWidth,windowHeight);
  window = glutCreateWindow(windowTitle);
 
 
  // Codigo de los shaders
  GLchar vertexShaderText[]=
    "varying vec2 scpos;"
    "void main()        "
    "{                  "
    "  gl_Position = vec4(gl_Vertex.xy,-1.0,1.0);"
    "  scpos = gl_Vertex.xy;                     "
    "}                  ";
 
  GLchar fragmentShaderText [] =
    "varying vec2 scpos;"
    "void main()        "
    "{                  "
    "  gl_FragColor = vec4(scpos.x*10.0,1.0,scpos.y*10.0,1.0);"
    "}                  ";
 
  const GLchar * vt = vertexShaderText;
  const GLchar * ft = fragmentShaderText;
 
  // Creamos 2 shaders en OpenGL
  GLuint vshader = glCreateShader(GL_VERTEX_SHADER);
  GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER);
 
  // Cargamos el codigo de los shaders
  glShaderSource(vshader,1,&vt,NULL);
  glShaderSource(fshader,1,&ft,NULL);
 
  // Los compilamos
  glCompileShader(vshader);
  glCompileShader(fshader);
 
  // Creamos el shader program y unimos los shaders
  GLuint program = glCreateProgram();
  glAttachShader(program, vshader);
  glAttachShader(program, fshader);
 
  // Enlazamos el programa
  glLinkProgram(program);
 
  // Indicamos que queremos usar este shader
  glUseProgram(program);
}
 
/* Esta funcion se llama cuando apretamos una tecla. */
void keyPressed(unsigned char key, int x, int y)
{
  if (key == ESCAPE)
    {
      glutDestroyWindow(window);
      exit(1);
    }
}
 
void DrawGLScene()
{
  // Limpiamos la imagen con color azul
  glClearColor(0.0,0.0,1.0,1.0);
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
 
  // Coordenadas de los puntos en espacio de pantalla (-1,-1)...(1,1)
  float vertexPos[] = {
    -0.5,-0.3,
     0.5,-0.3,
     0  , 0.7
  };
  // Activamos el render de vertex arrays
  glEnableClientState(GL_VERTEX_ARRAY);
  // Indicamos de donde debe tomar los datos
  glVertexPointer(2,GL_FLOAT,0,vertexPos);
  // Dibujamos el triangulo
  glDrawArrays(GL_TRIANGLES,0, 3);
  // Mostramos el triangulo en pantalla
  glutSwapBuffers();
}
 
void ReSizeGLScene(int width, int height)
{
  glViewport(0, 0, width, height);
}
 
int main(int argc, char ** argv)
{
  glutInit(&argc, argv);
  InitGL(800,600,24,"OpenGL Tutorial1");
  glutDisplayFunc(&DrawGLScene);
 
  glutIdleFunc(&DrawGLScene);
  glutReshapeFunc(&ReSizeGLScene);
  glutKeyboardFunc(&keyPressed);
 
  glutMainLoop();
  return 1;
}

[editar] Transformaciones

rellenar

[editar] Cubo Rotando

rellenar

[editar] VBO's

rellenar

[editar] Texturas básicas

rellenar

[editar] Render Targets

rellenar

[editar] Pixel Shaders básico

rellenar

[editar] Vertex shader básico

rellenar

Herramientas personales