Restringere i triangoli

Un utile effetto che può essere ottenuto tramite un geometry shader è la diminuzione della dimensione dei singoli triangoli di cui è composta la primitiva, in modo che rimangano degli spazi tra loro.
Ovviamente, questo effetto è ottenibile anche definendo i triangoli già ristretti da OpenGL, ma se il mesh di poligoni originale non può essere modificato, questa è l'unica soluzione.

Si modificano le coordinate del vertice in modo che si avvicini al centro. Per "centro" si considera per semplicità il baricentro del triangolo, che si calcola facilmente come la media dei vertici:

vec3 vertex[3];                        // vertices using cartesian coordinates
vec3 center = vec3(0.0,0.0,0.0);
for (int i = 0; i < 3; i++)
  {
  vertex[i] = gl_PositionIn[i].xyz / gl_PositionIn[i].w;
  center += vertex[i];
  }
center /= 3.0;

Si definisce una variabile uniform float scale;, che varia tra 0.0 e 1.0. Dopodichè, si calcola la nuova posizione del vertice come media pesata tra la posizione originale e il baricentro. La posizione pesa per scale, mentre il baricentro per 1.0 - scale.

vec3 newposition = vertex[i] * scale + center * (1 - scale);

Per maggiore efficienza, si precalcola center * (1 - scale):

center *= (1 - scale);

...

vertex[i] * scale + center;

Questo è complessivamente il 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];

uniform float scale;

vec3 ComputeNormal(in vec3 v1,in vec3 v2,in vec3 v3);

void main()
  {
  gnormal = ComputeNormal(veyeposition[0],veyeposition[1],veyeposition[2]);
  
  vec3 vertex[3];                        // vertices using cartesian coordinates
  vec3 center = vec3(0.0,0.0,0.0);
  for (int i = 0; i < 3; i++)
    {
    vertex[i] = gl_PositionIn[i].xyz / gl_PositionIn[i].w;
    center += vertex[i];
    }
  center /= 3.0;
  center *= (1 - scale);
  
  for (int i = 0; i < 3; i++)
    {
    gl_FrontColor = gl_FrontColorIn[i];
    gl_BackColor = gl_BackColorIn[i];
    gl_Position = vec4(vertex[i] * scale + center,1.0);
    
    gmatshininess = vmatshininess[i];
    gmatspecular = vmatspecular[i];
    geyeposition = veyeposition[i];
    
    EmitVertex();
    }
    
  EndPrimitive();
  }

Il contenuto del listato sovrastante è rilasciato nel pubblico dominio.

Configurazione per l'esempio

#define SHADER_FOLDER "shaders/shrink_triangles/"

#define USE_VERTEX_SHADER true
#define USE_FRAGMENT_SHADER true
#define USE_GEOMETRY_SHADER true
#define USE_NORMAL_SHADER true
#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 false
#define LOAD_NORMALS false
#define TIMER_MS 0

Risultato, con un valore di scale pari a 0.9:

Risultato restringimento triangoli

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.