Matemáticas OpenGL (GLM)

De Wikipedia, la enciclopedia libre
GLM
Información general
Tipo de programa Header-only
Desarrollador G-Truc Creation
Lanzamiento inicial 25 de febrero de 2005
Licencia MIT License
Estado actual Activa
Información técnica
Programado en C++
Versiones
Última versión estable 0.9.5 ( abril de 2014)
Enlaces

Matemáticas OpenGL o Opengl Maths es una librería multiplatforma ligera de sólo cabeceras con plantillas C++ (header-only) desarrollada por G-Truc Creation para realizar cálculos complejos de manera sencilla, intuitiva y centralizada. Trabaja con elementos como vectores, matrices, ángulos, cuaternión... y se encarga de casi todos aquellos cálculos y transformaciones sobre dichos tipos de datos. Principalmente, se usa en conjunto con las nuevas versiones de OpenGL para realizar los cálculos matriciales necesarios para dicha librería.

Del fixed-function pipeline a los shaders[editar]

A finales del 2004, apareció la versión 2.0 de OpenGL, en el cual el núcleo 1.x se despreció (deprecated), una de las principales características de OpenGL: la tubería de funcionalidad fija, o fixed-function pipeline. A partir de este punto, se empezaron a despreciar características principales de la librería, como la manipulación interna de matrices y las estructuras de datos que usaban. No fue hasta la estandarización y la nueva despreciación en el año 2008 cuando el núcleo de OpenGL 2.x entre disputas internas y aprovechando la desventaja de Windows Vista y Direct3D 10.0, que aparece el nuevo núcleo y estándar de programación de OpenGL, la versión 3.0, es aquí donde finalmente se deja atrás todo rastro de la 'fixed-function pipeline', siendo que antiguamente hasta la publicación de los documentos estándar de OpenGL 2.0 y posteriormente en 2006 de OpenGL 2.1, se venía pidiendo por escrito que se dejara de utilizar y mezclar el estándar de llamadas de 'fixed-functions' como glMatrixMode como mayormente destacado, entre otras.

La característica que reemplazó a todos estos aspectos fueron los Shaders, que permitieron programar de manera cómoda de las acciones de renderizado. Para complementar los cálculos de las matrices principales que utilizaba OpenGL 1.x, GLM proporcionó funciones sencillas y rápidas, como el cálculo de una matriz inversa o una multiplicación de matrices entre la gran cantidad de contenido que ésta proporciona.

Entidades usadas[editar]

GLM utiliza, principalmente, las siguientes estructuras de datos:

Vectores[editar]

GLM define vectores desde una dimensión hasta 4 dimensiones, de la siguiente manera:

#include <glm/glm.h>

glm::tvec4 vector_1( 1.0, 1.1, 1.2, 1.3 );        // Vector de flotantes (implícito)
glm::vec4 vector_2(1.f, 0.f, 4.f, -5.f );         // Vector de flotantes (implícito)
glm::tvec4<double> vector_3(1.f, 2.0, 1.f, 3.0);  // Vector de doubles (explícito)

glm::vec3 v1( 1.0, 0.0, 1.1 );                    // Vector de flotantes (por defecto)
glm::vec3 v2( 1.2, 1.3, 0.5 );                    // Vector de flotantes (por defecto)

Y puede operar con vectores con acciones varias, por ejemplo:

glm::vec3 = glm::cross(v1, v2); // Producto vectorial
double s = glm::dot(v1, v2);    // Producto escalar

Trigonometría[editar]

La librería acepta algunas funcionalidades básicas de trigonometría, por ejemplo:

double rad = glm::radians(45);  // Grados a radianes
double deg = glm::degrees(0.5); // Radiantes a grados

glm::cos(rad); // Coseno (correcto). 
glm::cos(deg); // Coseno (incorrecto, se debe trabajar con radianes).

Matrices[editar]

GLM permite matrices de dimensiones desde 2x2 hasta 4x4, incluyendo matrices cuadradas y no-cuadradas. Por ejemplo, podemos definir matrices de la siguiente manera:

glm::mat2x2 m1(2.0, 1.0
               1.2, 2.1);
glm::mat2x1 m1(2.0,
               1.2);

Y se pueden realizar operaciones incluyendo operaciones como las siguientes:

glm::mat2x1 m3 = m1 * m2;           // Producto de matrices
glm::mat2x2 m4 = glm::inverse(m1);  // Matriz inversa
glm::mat2x2 m5 = glm::traspose(m1); // Matriz traspuesta
double r = glm::determinant(m1);    // Determinante

Además, se pueden realizar transformaciones de matrices propias de OpenGL, como:

const int WINDOW_WIDTH = 800, WINDOW_HEIGHT = 600;

#include <glm/gtc/matrix_transform.hpp>

glm::mat4x4 modelviewMatrix;  // Matriz identidad por defecto.
glm::mat4x4 projectionMatrix; // Matriz identidad por defecto.

glm::vec3 translation(0, 2, 0);
modelviewMatrix = glm::translate(modelviewMatrix, translation); // Trasladar la matriz modelview 2 unidades hacia arriba.

// Generar una matriz de proyección con visión de "perspectiva".
projectionMatrix = glm::perspective( glm::radians(45.0)                  // Field Of View
                                     WINDOW_WIDTH/(double)WINDOW_HEIGHT, // Aspecto
                                     0.1,                                // near-z clip
                                     200.0,                              // far-z clip
                                    )

Cuaterniones[editar]

Un cuaternión sirve para representar una orientación en el mundo sin problemas como Gimbal Lock, producido por representaciones como los Ángulos de Euler. Por ejemplo, se puede definir un objeto de este tipo de la siguiente tipo:

#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>

glm::vec3 EulerAngles(0.0, glm::radians(45.0), 0.0);  // ¡¡Trabajar con radianes!!
glm::quat q(EulerAngles);
glm::vec3 EulerAnges2 = glm::EulerAngles(q); // Extraer ángulos de Euler.

// Rotar (multiplicar) una matriz por un cuaternión.
modelviewMatrix = modelviewMatrix * (glm::toMat4(g));

Ejemplo de uso[editar]

Se puede usar GLM para muchos aspectos. Por ejemplo, fuera de OpenGL, puede usarse parar calcular la normal de un triángulo:

// http://glm.g-truc.net/0.9.5/code.html

#include <glm/vec3.hpp>// glm::vec3
#include <glm/geometric.hpp>// glm::cross, glm::normalize

void computeNormal(triangle & Triangle)
{
  glm::vec3 const & a = Triangle.Position[0];
  glm::vec3 const & b = Triangle.Position[1];
  glm::vec3 const & c = Triangle.Position[2];
  Triangle.Normal = glm::normalize(glm::cross(c - a, b - a));
}

U orientado a OpenGL, se puede usar para definir las propiedades de un emisor de luz:

// http://glm.g-truc.net/0.9.5/code.html

#include <glm/vec3.hpp>// glm::vec3
#include <glm/geometric.hpp>// glm::normalize, glm::dot, glm::reflect
#include <glm/exponential.hpp>// glm::pow
#include <glm/gtc/random.hpp>// glm::vecRand3
glm::vec3 lighting(intersection const & Intersection, material const & Material, light const & Light, glm::vec3 const & View)
{
  glm::vec3 Color(0.0f);
  glm::vec3 LightVertor(glm::normalize( Light.position() - Intersection.globalPosition() + glm::vecRand3(0.0f, Light.inaccuracy()));

  if(!shadow(Intersection.globalPosition(), Light.position(), LightVertor))
  {
    float Diffuse = glm::dot(Intersection.normal(), LightVector);
    if(Diffuse <= 0.0f)
      return Color;
    if(Material.isDiffuse())
      Color += Light.color() * Material.diffuse() * Diffuse;
    if(Material.isSpecular())
    {
      glm::vec3 Reflect(glm::reflect(
      glm::normalize(-LightVector),
      glm::normalize(Intersection.normal())));
      float Dot = glm::dot(Reflect, View);
      float Base = Dot > 0.0f ? Dot : 0.0f;
      float Specular = glm::pow(Base, Material.exponent());
      Color += Material.specular() * Specular;
    }
  }
  return Color;
}

Enlaces[editar]