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(); }
#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:
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.
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.