» it.Tutorial Effects - Le Normali
This site relies heavily on Javascript. You should enable it if you want the full experience. Learn more.

it.Tutorial Effects - Le Normali

English | Mandarin | Japanese

INDICE: it.Of Effects and Shaders
Precedente: I Dati del Vertice
Prossimo: Morphing della Geometria


Le normali della superficie, oltre alla posizione ed alle coordinate della texture, sono il terzo e più comunemente usato campo dati di un vertice. La normale è un vettore 3d che è perpendicolare ad una superficie (leggi qualcosa sulla normale di superficie su wikipedia).
Le normali sono molto importanti per il calcolo della luce, quando il vettore della luce viene riflesso sulla superficie per la sfumatura dei colori della superficie.

Mostrare le Normali

VVVV ha un modulo d'aiuto per visualizzare le normali di una mesh: Normals (EX9)

Possiamo modificare la sua helppatch per avere una vista della mesh con le normali:

Calcolare le Normali

Se la mesh non contiene le sue normali, allora è possibile usare il nodo Normals (EX9.Geometry Mesh) per calcolarle nella patch prima di passare la mesh allo shader. Usa il pin Smoothing Angle per calcolare la media delle normali sulla superficie.

Dato che la maggior parte di modelli di shading (come il phong) hanno bisogno della normale nello spazio relativo alla vista, dobbiamo trasformare la normale assieme alla posizione del vertice, facendo attenzione al fatto che la normale è un float3, o se è un float4, la componente w della normale è 0 (invece che 1 come nella posizione), e che può essere solo ruotata, ma non traslata. Un tipico vertexshader compie queste trasformazioni:

...
    //normal in view space
    Out.NormV = normalize(mul(NormO, tWV));
 
    //position (projected)
    Out.PosWVP  = mul(PosO, tWVP);
    ...

Ricalcolare le Normali

Naturalmente le cose si complicano se si cambiano le posizioni del vertice nel vertexshader, proprio come è successo in it.Mr.Wiggle o in Disegnare con le Funzioni. Dato che la traslazione delle posizioni dei vertici cambia la curvatura della superficie, le normali memorizzate precedentemente nella mesh non sono più valide. Quindi i calcoli per lo shading sono sbagliati.

Così, se hai bisogno di calcolare l'illuminazione nel pixelshader devi trovare il modo di ricalcolare le normali, prima. Questo però è strettamente legato al metodo che usi per traslare le posizioni.

Il metodo più usato, ma poi non così preciso, per calcolare le nuove normali consiste nel calcolare 2 posizioni vicine in più ed ottenerne due vettori che sono sul piano tangente a questo vertice e non sono paralleli. Dai due vettori tangenti si può calcolare la normale con il prodotto vettoriale (cross product):

  • calcola la posizione attuale p
  • calcola la posizione vicina n1
  • calcola la posizione vicina n2
  • ottiene il vettore tangente t1 = p - n1
  • ottiene il vettore tangente t2 = p - n2
  • ottiene la normale n = t1 x t2

Usando l'esempio del cono da Disegnare con le Funzioni avremmo:

float NeighbourOffset = 0.001;
 
vs2ps VS(
    float4 PosO  : POSITION,
    float4 TexCd : TEXCOORD0)
{
    //dichiara la struttura dell'output
    vs2ps Out;
 
    //calcola la nuova posizione
    float3 p = Cone(PosO.xy);
 
    //calcola la posizione vicina nella direzione u
    float3 n1 = Cone(PosO.xy + float2(NeighbourOffset, 0));
 
    //calcola la posizione vicina nella direzione v
    float3 n2 = Cone(PosO.xy + float2(0, NeighbourOffset));
 
    //ottiene il vettore tangente 1
    float3 t1 = p - n1;
 
    //ottiene il vettore tangente 2
    float3 t2 = p - n2;
 
    //ottiene la normale
    float3 NormO = cross(t1, t2);
 
    //imposta la nuova posizione
    PosO.xyz = p;
    ...

Per poter usare le normali potremmo per sesempio usare la funzione Phong dichiarata nel file PhongDirectional.fxh nella cartella effects di vvvv. Copia quindi il contenuto del file .fxh nel tuo shader, e poi confronta il codice contenuto in PhongDirectional.fx pr capire quali righe siano necessarie per aver un phong shading che funzioni.
Dobbiamo inserire la normale, la luce e la direzione della vista nello spazio della vista, e poi passare tutto quello che c'è nella struttura vs2ps al pixelshader. copamo anche il codice per la texture per aver un buon setup per lo shading, dove si possa semplicemente rimpiazzare la funione Cone con tutte le superfici parametriche-uv che si possono troare sul web:

// ----------------------------------------------------------------------------
// PARAMETRI:
// ----------------------------------------------------------------------------
 
//trasforma
float4x4 tW: WORLD;        //il modello matrice mondo tramite lo shader
float4x4 tV: VIEW;         //matrice vista come impostata tramite Renderer (EX9)
float4x4 tP: PROJECTION;   //matrice proiezione come impostata tramite Renderer (EX9)
float4x4 tWV : WORLDVIEW;
float4x4 tWVP: WORLDVIEWPROJECTION; //tutti e 3 premoltiplicati  
 
/la trasformazione della texture segnata con la semantica TEXTUREMATRIX
//per ottenere trasformazioni simmetriche
float4x4 tTex: TEXTUREMATRIX <string uiname="Texture Transform";>;
 
//texture
texture Tex <string uiname="Texture";>;
sampler Samp = sampler_state    //campionatore per il lookup della texture
    Texture   = (Tex);          //applica una texture al campionatore
    MipFilter = LINEAR;         //stati del campionatore
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};
 
//la struttura dati: "vertexshader to pixelshader"
//usata come output della Funzione VS
//e come input della funzione PS
struct vs2ps
{
    float4 Pos  : POSITION;
    float2 TexCd : TEXCOORD0;
    float3 LightDirV: TEXCOORD1;
    float3 NormV: TEXCOORD2;
    float3 ViewDirV: TEXCOORD3;
};
 
#include "PhongDirectional.fxh"
 
// ----------------------------------------------------------------------------
// VERTEXSHADERS
// ----------------------------------------------------------------------------
 
 
#define twopi 6.28318531
 
float2 Scale = 1;
float2 Offset = 0;
 
float3 Cone(float2 uv)
{
 
     uv *= Scale;
     uv += Offset;
 
    float u = uv.x * twopi;
    float v = uv.y;
 
    float3 newPos;
    newPos.x = v * cos(u);
    newPos.y = v * sin(u);
    newPos.z = v;
 
    return newPos;
}
 
float NeighbourOffset = 0.001;
 
vs2ps VS(
    float4 PosO  : POSITION,
    float4 TexCd : TEXCOORD0)
{
    //dichiara la struttura dell'output
    vs2ps Out;
 
    //calcola la nuova posizione
    float3 p = Cone(PosO.xy);
 
    //calcola la posizione vicina nella direzione u
    float3 n1 = Cone(PosO.xy + float2(NeighbourOffset, 0));
 
    //calcola la posizione vicina nella direzione v
    float3 n2 = Cone(PosO.xy + float2(0, NeighbourOffset));
 
    //ottiene il vettore tangente 1
    float3 t1 = p - n1;
 
    //ottiene il vettore tangente 2
    float3 t2 = p - n2;
 
    //ottiene la normale
    float3 NormO = cross(t1, t2);
 
    //imposta la nuova posizione
    PosO.xyz = p;
 
    //immette la normale nello spazio vista e la normalizza
    Out.NormV = normalize(mul(NormO, tWV));
 
    //direzione inversa della luce nello spazio vista
    Out.LightDirV = normalize(-mul(lDir, tV));
 
    //direzione inversa della vista nello spazio vista
    Out.ViewDirV = -normalize(mul(PosO, tWV));
 
    //trasforma la posizione (proiettata)
    Out.Pos = mul(PosO, tWVP);
 
    //trasforma le coordinate della texture
    Out.TexCd = mul(TexCd, tTex);
 
    return Out;
}
 
// ----------------------------------------------------------------------------
// PIXELSHADERS
// ----------------------------------------------------------------------------
 
float Alpha <float uimin=0.0; float uimax=1.0;> = 1;
 
float4 PS(vs2ps In) : COLOR
{
    float4 col = tex2D(Samp, In.TexCd);
 
    col.rgb *= PhongDirectional(In.NormV, In.ViewDirV, In.LightDirV);
    col.a *= Alpha;
 
    return col;
}
 
// ----------------------------------------------------------------------------
// TECHNIQUES:
// ----------------------------------------------------------------------------
 
technique TFunctionWithPhong
{
    pass P0
    {
        VertexShader = compile vs_1_1 VS();
        PixelShader  = compile ps_2_0 PS();
    }
}

INDICE: it.Of Effects and Shaders
Precedente: I Dati del Vertice
Prossimo: Morphing della Geometria

anonymous user login

Shoutbox

~15d ago

~18d ago

joreg: The Winter Season of vvvv workshops is now over but all recordings are still available for purchase: https://thenodeinstitute.org/ws23-vvvv-intermediates/

~24d ago

schlonzo: Love the new drag and drop functionality for links in latest previews!

~1mth ago

joreg: Workshop on 29 02: Create Sequencers and Precise Clock Based Tools. Signup here: https://thenodeinstitute.org/courses/ws23-vvvv-08-create-sequencers-and-precise-clock-based-tools-in-vvvv-gamma/

~1mth ago

joreg: Workshop on 22 02: Unlocking Shader Artistry: A Journey through ‘The Book of Shaders’ with FUSE. Signup here: https://thenodeinstitute.org/courses/ws23-vvvv-12-book-of-shaders/

~2mth ago

joreg: Talk and Workshop on February 15 & 16 in Frankfurt: https://visualprogramming.net/blog/vvvv-at-node-code-frankfurt/

~2mth ago

woei: @Joanie_AntiVJ: think so, looks doable