Tessellation evaluation shader

Il tessellation evaluation shader è eseguito una volta per ogni vertice prodotto dal Tessellator, nonché per i vertici originali prodotti dal tessellation control shader. La presenza di un tessellation evaluation shader rende obbligatorio l'uso del tipo di primitiva patch e la presenza di un tessellation control shader.

Ciascuna istanza può leggere tutti gli array che sono stati inviati dal tessellation control shader, esattamente come esso li ha prodotti (non c'è nessuna interpolazione), ma può produrre dati per un solo vertice.

L'utilità principale di questo shader è il calcolo degli attributi dei nuovi vertici creati dal Tessellator, in modo che possano proseguire la pipeline come quelli della patch originale.

Anche il tessellation evaluation shader prevede una direttiva di tipo layout:

layout(triangles, equal_spacing, ccw) in;

Questa direttiva indica come le patch debbano essere interpretate e quale tipo di primitiva debba essere emessa. Il primo parametro può essere:

triangles  le patch sono (insiemi di) triangoli e devono rimanere triangoli
quads      le patch sono (insiemi di) quadrilateri e devono essere convertiti in triangoli
isolines   le patch sono (insiemi di) quadrilateri e devono essere convertiti in segmenti

Il secondo parametro riguarda l'effetto di gl_TessLevelOuter. Può essere:

equal_spacing           i lati sono suddivisi in segmenti di uguale lunghezza
fractional_even_spacing i lati sono suddivisi in un numero pari di 
                        segmenti di uguale lunghezza, più due più corti.
fractional_odd_spacing  i lati sono suddivisi in un numero dispari di 
                        segmenti di uguale lunghezza, più due più corti.

Il terzo parametro può essere:

cw    i vertici delle primitive sono prodotti in senso orario
ccw   i vertici delle primitive sono prodotti in senso antiorario

Il tessellation evaluation shader non riceve in ingresso direttamente la posizione del nuovo vertice che gli è assegnato. Invece, ha accesso in lettura alla variabile

vec3 gl_TessCoord;

Questa variabile contiene i pesi per calcolare la posizione del vertice assegnato a quel tessellation evaluation shader come media delle posizioni degli altri vertici. Nell'ipotesi in cui le primitive di input siano triangoli e che il tessellation control shader abbia passato avanti un array che contiene le posizioni dei vertici della patch:

in vec3 tcPosition[3];

la posizione può essere calcolata in questo modo:

vec3 p0 = gl_TessCoord.x * tcPosition[0];
vec3 p1 = gl_TessCoord.y * tcPosition[1];
vec3 p2 = gl_TessCoord.z * tcPosition[2];
vec3 position = p0 + p1 + p2;

Segue un esempio di tessellation evaluation shader, capace di applicare l'illuminazione a ciascun vertice:

#version 400

layout(triangles, equal_spacing, ccw) in;
in vec3 tcPosition[];

in vec3 tcNormal[];
in vec4 tcColor[];
in float tcmatshininess[];
in vec3 tcmatspecular[];

uniform mat4 Projection;
uniform mat4 Modelview;
uniform mat3 NormalMatrix;

uniform vec4 LightPosition;
uniform vec3 LightDiffuse;
uniform vec3 LightAmbient;
uniform vec3 LightSpecular;

out vec4 tecolor; 

vec4 ApplyLight(in vec4 oColor, in vec3 relativepos, in vec3 normal, in vec3 lightpos, in vec3 lightambient, 
  in vec3 lightdiffuse, in vec3 lightspecular, in float matshininess,in vec3 matspecular);

void main()
  {
  // posizione del vertice
  vec3 p0 = gl_TessCoord.x * tcPosition[0];
  vec3 p1 = gl_TessCoord.y * tcPosition[1];
  vec3 p2 = gl_TessCoord.z * tcPosition[2];
  vec3 position = (p0 + p1 + p2);
    
  // normale del vertice
  p0 = gl_TessCoord.x * tcNormal[0];
  p1 = gl_TessCoord.y * tcNormal[1];
  p2 = gl_TessCoord.z * tcNormal[2];
  vec3 normal = p0 + p1 + p2;
  normal = normalize(NormalMatrix * normal);
    
  // calcola questi valori come media dei valori in ingresso
  vec4 avgcolor = (tcColor[0] + tcColor[1] + tcColor[2]) / 3.0;
  float avgshini = (tcmatshininess[0] + tcmatshininess[1] + tcmatshininess[2]) / 3.0;
  vec3 avgspec = (tcmatspecular[0] + tcmatspecular[1] + tcmatspecular[2]) / 3.0;
   
  // illuminazione
  vec4 rp4 = Modelview * vec4(position, 1.0);
  vec3 relativepos = rp4.xyz / rp4.w;
  tecolor = ApplyLight(avgcolor,relativepos,normal,LightPosition.rgb / LightPosition.w,LightAmbient,
    LightDiffuse,LightSpecular,avgshini,avgspec);
    
  gl_Position = Projection * Modelview * vec4(position, 1.0);
  }

Il contenuto del listato sovrastante è rilasciato nel pubblico dominio.


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.