Classificazione dei triangoli

Esempio

Il geometry shader può avere un diverso comportamento a seconda di alcune caratteristiche delle primitive in ingresso. Questo è usato di solito per ottenere effetti particolari, come visualizzare solo i triangoli ai bordi del poliedro.
In questo esempio, si classificano i triangoli in modo classico in base agli angoli (acutangolo, rettangolo, ottusangolo) e in base ai lati (equilatero, isoscele, scaleno).

Il geometry shader assegna un colore diverso a ciascun tipo di triangolo:

Segue il codice del geometry shader:

#version 120
#extension GL_EXT_geometry_shader4: enable

varying out float gmatshininess;
varying out vec3 gmatspecular;
varying out vec3 geyeposition;
varying out vec3 gnormal;

varying in float vmatshininess[3];
varying in vec3 vmatspecular[3];
varying in vec3 veyeposition[3];
varying in vec3 vnormal[3];

const float epsilon = 0.01;

void main()
  {
  gl_BackColor = vec4(0.0,0.0,0.0,1.0);

  // Si calcolano i vettori che rappresentano i lati
  // in eye coordinates, così non sono distorti dalla proiezione prospettica
  vec3 diff1 = veyeposition[0] - veyeposition[1];
  vec3 diff2 = veyeposition[1] - veyeposition[2];
  vec3 diff3 = veyeposition[2] - veyeposition[0];

  // Si calcola la lunghezza al quadrato di ciascuno
  float lenq1 = dot(diff1,diff1);
  float lenq2 = dot(diff2,diff2);
  float lenq3 = dot(diff3,diff3);

  // Questa variabile conterrà il numero di coppie di lati che sono uguali
  int equals = 0;

  // Due valori sono approssimativamente uguali se la loro differenza in valore assoluto è minore di un numero molto piccolo
  // Usare l'uguaglianza (==) non ha molto senso con valori float
  if (abs(lenq1 - lenq2) < epsilon)
    equals++;
  if (abs(lenq2 - lenq3) < epsilon)
    equals++;
  if (abs(lenq3 - lenq1) < epsilon)
    equals++;
  // Ora, "equals" contiene 0, 1 o 3 (o 2, ma è improbabile), a seconda del numero di coppie di lati che sono uguali

  // Il triangolo è ottusangolo se la somma dei quadrati costruiti su una coppia di lati è minore del
  // quadrato costruito sul terzo (Teorema di Pitagora esteso).
  // lenq1, lenq2 e lenq3 sono già lunghezze elevate al quadrato
  bool obtuse = lenq1 + lenq2 < lenq3 || lenq2 + lenq3 < lenq1 || lenq3 + lenq1 < lenq2;

  // Il triangolo è rettangolo se la somma dei quadrati costruiti sui cateti è uguale al quadrato costruito
  // sull'ipotenusa (Teorema di Pitagora inverso).
  bool right = abs(lenq1 + lenq2 - lenq3) < epsilon || abs(lenq1 + lenq3 - lenq2) < epsilon || abs(lenq3 + lenq2 - lenq1) < epsilon;

  // Triangolo isoscele (una sola coppia di lati uguali)
  if (equals == 1)
    gl_FrontColor = right ? vec4(0.9,0.0,0.0,1.0) : (obtuse ? vec4(0.0,0.0,0.9,1.0) : vec4(0.9,0.9,0.0,1.0));

  // Triangolo scaleno
  if (equals == 0)
    gl_FrontColor = right ? vec4(0.3,0.0,0.0,1.0) : (obtuse ? vec4(0.0,0.0,0.3,1.0) : vec4(0.0,0.9,0.0,1.0));

  // Triangolo equilatero (2 o 3 coppie)
  if (equals > 1)
    gl_FrontColor = vec4(0.9,0.5,0.0,1.0);
  
  for (int i = 0; i < 3; i++)
    {
    gl_Position = gl_PositionIn[i];
    
    gmatshininess = vmatshininess[i];
    gmatspecular = vmatspecular[i];
    geyeposition = veyeposition[i];
    gnormal = vnormal[i];
    
    EmitVertex();
    }
    
  EndPrimitive();
  }

Configurazione per l'esempio

#define SHADER_FOLDER "shaders/classify_triangles/"

#define USE_VERTEX_SHADER true
#define USE_FRAGMENT_SHADER true
#define USE_GEOMETRY_SHADER true
#define USE_NORMAL_SHADER false
#define USE_VERTEX_LIGHT_SHADER false
#define USE_FRAGMENT_LIGHT_SHADER true
#define USE_TESSEVAL_LIGHT_SHADER false
#define USE_TESSELLATION_SHADERS false

#define GEOMETRY_INPUT_TYPE GL_TRIANGLES         
#define GEOMETRY_OUTPUT_TYPE GL_TRIANGLE_STRIP   
#define GEOMETRY_MAX_VERTICES 3                

#define ENABLE_BACK_FACE_CULLING true
#define LOAD_NORMALS true
#define TIMER_MS 0

Risultato:

Risultato classificazione triangoli 1

Dal colore giallo predominante, è evidente che i triangoli dell'icosaedro non sono perfettamente equilateri.

Per ottenere una migliore varietà, è possibile deformare l'icosaedro. Basta una piccola modifica alla costante

const GLfloat OBJECT_SCALE[] = {4.0,4.0,4.0};

Ad esempio, con

const GLfloat OBJECT_SCALE[] = {4.0,2.1,2.0};

si ottiene anche qualche triangolo rettangolo.

Risultato classificazione triangoli 2

Copyright © 2011 Riccardo Monica
Eccetto ove espressamente indicato altrimenti, il contenuto di questa pagina è disponibile secondo la licenza Creative Commons Attribuzione - Condividi allo stesso modo 3.0.