Tutorial: Vertex Shader & Pixel Shader Unterstützung in DX9

Hier kannst du häufig gestellte Fragen/Antworten und Tutorials lesen und schreiben.
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hi,

nachdem wir im letzten Tutorial gelernt haben Mesh zu bewegen zeig ich Euch heute ein praktische Umsetzung um eine Fahne wehen zu lassen. Die hier verwendete Formel ist trickreich und leicht erklärt.

Als erstes benötigen wir einen float angle Wert der über den time Faktor erzeugt wird

Code: Alles auswählen

float angle= time *4; 
Der Wert 4 bestimmt quasi die Geschwindigkeit mit der die Fahne schwingt

Die Bewegung der Fahne wird erst einmal sinusförmig über

Code: Alles auswählen

v.z = sin( v.x+angle) 
bestimmt indem der laufende x Positionswert + time *4 mal dem Sinuswert gerechnet wird, also eine Sinuswelle über die Länge des Mesh
danach wird die halbe Sinuswelle über die Höhe berechnet, da die Fahne sich nie gleichförmig bewegt

Code: Alles auswählen

v.z += sin( v.y /2+angle);
"Var1+=" heist "Var1 = Var1 +"

Mit dem nächsten Trick wird die Fahne am Anfang gar nicht bewegt, aber je weiter weg desto oller äh doller.
v.z *= (v.x+halvewidh ) * 0.09f;
das Mesh beginnt bei x position -10 und endet bei x position + 10. demnach ist halvewidh bei diesem Mesh 10. Mit diesem Trick wird links am Mesh keien Bewegung ausgeführt, da ja bekanntlich v.z = v.z * (-10+10)* 0.09 = 0 ist (rechnet es ruhig nach) bei v.x = 10 kommt was anderes raus

Der Shader braucht jetzt nur noch

http://www.flasharts.de/mpz/flagge.x
http://www.flasharts.de/mpz/Flagge.JPG

im Shadereditor wird das Mesh Flagge.x geladen und als texture0 die flagge.jpg

Vom Shadereditor übergeben Variablen:
worldViewProj -> Weltposition vom Editor übergeben
texture0 -> geladene Textur, z.B. "flagge.jpg"
time -> die laufende Zeit in ms

Code: Alles auswählen

//-----------------------------------------------------------------------------
//           Name: MoveFlagge.fx
//         Author: Michael Paulwitz
//  Last Modified: 10.04.12
//    Description: move Flag 
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Effect File Variables
//-----------------------------------------------------------------------------

float4x4 worldViewProj : WorldViewProjection; // This matrix will be loaded by the application
texture texture0;
float time;
float halvewidh = 10;

sampler Sampler1 = sampler_state 
{ 
texture   = <texture0>;
};

//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------

// Our sample application will send vertices 
// down the pipeline laid-out like this...

struct VS_INPUT
{
    float3 position	: POSITION;
    float2 texture0     : TEXCOORD0;
};

// Once the vertex shader is finished, it will 
// pass the vertices on to the pixel shader like this...

struct VS_OUTPUT
{
    float4 hposition : POSITION;
    float2 texture0  : TEXCOORD0;
};


//-----------------------------------------------------------------------------
// Simple Vertex Shader
//-----------------------------------------------------------------------------

VS_OUTPUT myvs( VS_INPUT IN )
{
    VS_OUTPUT OUT;

        float4 v = float4( IN.position.x, IN.position.y, IN.position.z, 1.0f );
        float angle= time*4;
        v.z += sin( v.x+angle) ;
        v.z += sin( v.y /2+angle);
        v.z *= (v.x+halvewidh ) * 0.09f;

        OUT.hposition = mul( v, worldViewProj   );
        OUT.texture0 = IN.texture0;
        return OUT;
}

//-----------------------------------------------------------------------------
// Simple Effect (1 technique with 1 pass)
//-----------------------------------------------------------------------------

technique flag
{
    pass Pass0
    {
		Sampler[0] = (Sampler1); // Needed by pixel shader
		VertexShader = compile vs_2_0 myvs();
    }
}

Sollte die Fahne nicht nur links, sondern auch oben ruhig sein kann man das leicht mit dem Zuatz

Code: Alles auswählen

v.z *= (v.y-6 ) * 0.09f; 
erreichen.

Gruß Michael
Working on - MP3D Engine -
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hi,

so die Fahne weht im Wind, aber... Noch bewegt sie sich unrealistisch weil die Lichtschatten bzw die Ambientlight Berechnung fehlt. Zur Berechnung benötigen wie die Normals, welche sich aber dummerweise bei einem bewegten Mesh auch ändert. Die Normals sind quasi Vectoren die im 90 Grad Winkel von der Fläche wegzeigen. Steckt in einer Styroporkugel Nadeln, dann sind die Nadeln die "Normals".
Schnell gegoogelt um die Berechnung zu finden und...nix da. Also gehen wir jetzt an die Grundlagen der Normals Berechnung. Meshs bestehen aus Dreiecksflächen die aus drei Vertex Punkten bestehen (V0,V1,V2). Um Ein Normal des VertexPunktes Vo zu berechnen Wird das CrossProdukt aus (V0 - V1) und (V0 - V2) berechnet

http://www.gamedev.net/page/resources/_ ... tors-r1089

Jetzt haben wir nur das Problem das bei einem Vertex Shader jeder VertexPunkt nacheinander durchgegangen wird, wir aber keinen Zugriff auf "alte" Vertex Punkte haben. Also definieren wir einfach temporäre Punkte um die Normals zu berechnen. In dem Fall der Flage durch die 2d Fläche einfach anzunehmen.

Code: Alles auswählen

V0 ist der gerade berechnete v.xyz VertexPunkt
V1 ist der V.xyz Vertex Punkt + 0.5 auf X Achse und v.z für diese neue Koordinate berechnet
V2 ist der V.xyz Vertex Punkt + 0.5 auf y Achse und v.z gleich wie bei V 
Die zweite Variante bei der auch bei V2 der v.z Wert neu berechnet wird zeige ich Euch auch noch, aber die erste variante gefällt mir selber schon gut genug.

Der Shader braucht jetzt nur noch

http://www.flasharts.de/mpz/flagge.x
http://www.flasharts.de/mpz/Flagge.JPG

im Shadereditor wird das Mesh Flagge.x geladen und als texture0 die flagge.jpg

Vom Shadereditor übergeben Variablen:

worldViewProj -> Weltposition vom Editor
matWorld -> Meshposition vom Editor
texture0 -> geladene Textur, z.B. "flagge.jpg"
time -> die laufende Zeit in ms
halvewidh = 10 -> Hälte der Meshlänge
lightDir -> Lichtrichtung vom Editor

Code: Alles auswählen

//-----------------------------------------------------------------------------
//           Name: MoveFlaggeNormals.fx
//         Author: Michael Paulwitz
//  Last Modified: 28.10.09
//    Description: move Flag 
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Effect File Variables
//-----------------------------------------------------------------------------

float4x4 worldViewProj : WorldViewProjection; // This matrix will be loaded by the application
float4x4   matWorld      ; // For calculating normals

texture texture0;
float time;
float halvewidh = 10;
float3          lightDir            ; // Our lights direction

sampler Sampler1 = sampler_state 
{ 
texture   = <texture0>;
};

//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------

// Our sample application will send vertices 
// down the pipeline laid-out like this...

struct VS_INPUT
{
    float3 position	: POSITION;
    float2 texture0     : TEXCOORD0;
    float4 normal   : NORMAL0 ;
};


// Once the vertex shader is finished, it will 
// pass the vertices on to the pixel shader like this...

struct VS_OUTPUT
{
    float4 hposition : POSITION;
    float2 texture0  : TEXCOORD0;
    float4 lightnormal : COLOR0;
};


//-----------------------------------------------------------------------------
// Simple Vertex Shader
//-----------------------------------------------------------------------------

VS_OUTPUT myvs( VS_INPUT IN )
{
    VS_OUTPUT OUT;

        float4 v = float4( IN.position.x, IN.position.y, IN.position.z, 1.0f );
        float angle= time *4;

        v.z = sin( v.x+angle) ;
        v.z += sin( v.y /2+angle);
        v.z *= (v.x+halvewidh ) * 0.09f;
        //v.z *= (v.y-6 ) * 0.09f;

        float v2 = sin( v.x+angle-0.5) ;
        v2 += sin( v.y /2+angle);
        v2 *= (v.x-0.5+halvewidh ) * 0.09f;
        //v2 *= (v.y-6 ) * 0.09f;

         float3 poss[3];
                
         poss[0] = v.xyz;
         poss[1] = float3(v.x-0.5,v.y,v2);
         poss[2] = float3(v.x,v.y-0.5,v.z);

         float3 side1 = poss[0] - poss[2];
         float3 side2 = poss[0] - poss[1];
         IN.normal.xyz = cross(side1,side2);

        OUT.hposition = mul( v, worldViewProj   );
        
        float3 L = normalize(-lightDir);
        // transform our normal with matInverseWorld, and normalize it
        float3 N = normalize(mul(IN.normal.xyz,matWorld ));

        OUT.lightnormal =  saturate(dot(L, N)); 

       OUT.texture0 = IN.texture0;
        return OUT;
}

float4 myps(VS_OUTPUT IN) : COLOR
{
    return tex2D(Sampler1, IN.texture0)*(IN.lightnormal*0.8+0.2);
}

//-----------------------------------------------------------------------------
// Simple Effect (1 technique with 1 pass)
//-----------------------------------------------------------------------------

technique flag
{
    pass Pass0
    {
		PixelShader = compile ps_2_0 myps();
		VertexShader = compile vs_2_0 myvs();
    }
}

Man kann die Ambientlight Berechnung als Variante 2 auch so durchführen:

Code: Alles auswählen

        v.z = sin( v.x+angle) ;
        v.z += sin( v.y /2+angle);
        v.z *= (v.x+halvewidh ) * 0.09f;
       // v.z *= (v.y-6 ) * 0.09f;

        float v2 = sin( v.x+0.5+angle) ;
        v2 += sin( v.y /2+angle);
        v2 *= (v.x+0.5+halvewidh ) * 0.09f;
       // v2 *= (v.y-6 ) * 0.09f;

        float v3 = sin( v.x+angle) ;
        v3 += sin( (v.y+0.5) /2+angle);
        v3 *= (v.x+0.5+halvewidh ) * 0.09f;
       // v3 *= (v.y-6+0.5 ) * 0.09f;

         float3 poss[3];
                
         poss[0] = v.xyz;
         poss[1] = float3(v.x+0.5,v.y,v2);
         poss[2] = float3(v.x,v.y+0.5,v3);

         float3 side1 = poss[0] - poss[2];
         float3 side2 = poss[0] - poss[1];
         IN.normal.xyz = cross(side1,side2);

Aber manchmal ist weniger mehr

Gruß Michael
Working on - MP3D Engine -
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hi,

es gibt einen neuen Shadereditor Version 0.5 (download über den ersten Beitrag). Mit einigen neuen Funktionen:

* Anzeige der Zeile und Position
* Bei einem ShaderFehler sprung auf die Position des ersten erkannten Fehler
* diverse editor Funktionen (suchen ersetzen etc)
* FPS Anzeige
* Vsync on/off
* Tiefe des Meshs über Mauswheel steuerbar
* Mesh kann nur noch bewegt werden wenn das Editorfeld nicht aktiv ist (1 mal ESC drücken)

Gruß Michael
Working on - MP3D Engine -
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hallo,

heute werden wir ein 3D Mesh über eine eigene Procedure verdrehen. Dazu benötigen wir
ein Mesh (in diesem Fall eine Turm), die Länge des Meshs und den Drehwinkel.
Die Längeneinheit des Mesh beträgt 300 und der Drehwinkel soll 360 Grad betragen

Code: Alles auswählen

float height = float(300); 
float angle_deg_max = float(360); 


Über die folgende Formel kann ich dann den Winkel errechnen

Code: Alles auswählen

float angle_deg = angle_deg_max*sin(time);// Änderung des Winkels über die Zeit
float angle_rad = angle_deg * 3.14159 / 180.0; // Umrechnung in Rad


die Veränderung der Drehrichtung erfolgt über die IN.position.y - Achse

Code: Alles auswählen

 
float ang = (height*0.5 + IN.position.y)/height * angle_rad; 


In einem Shader kann man vergleichbar mit PB auch Proceduren verwirklichen,
die machen in diesem Fall die Berechnung einfacher.

Die Vertexe.xyz werden damit über "Winkel t" gedreht

Code: Alles auswählen

 
float3 DoTwist( float3 pos, float t )
{
	float st = sin(t);
	float ct = cos(t);
	float3 new_pos;
	
	new_pos.x = pos.x*ct - pos.z*st;
	new_pos.z = pos.x*st + pos.z*ct;
	new_pos.y = pos.y;

	return( new_pos );
}
Der Shader braucht jetzt nur noch das Mesh
http://www.flasharts.de/mpz/Tower.x
und eine geladene Textur texture0

Vom Shadereditor übergeben Variablen:

worldViewProj -> Weltposition vom Editor
texture0 -> geladene Textur, z.B. "Demo_Texture_1.bmp"
height -> länge 300 des Mesh
angle_deg_max - Drehrichtung 360 Grad
time -> die laufende Zeit in ms

Code: Alles auswählen

//-----------------------------------------------------------------------------
//     Name: Mesh_Twister_Shader.fx
//     Author: Michael Paulwitz
//    Last Modified:
//    Description: Mesh Twister Shader with texture
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Effect File Variables
//-----------------------------------------------------------------------------

float4x4 worldViewProj : WorldViewProjection; // This matrix will be loaded by the application

float time;
float height = float(300); 
float angle_deg_max = float(360); 
texture texture0;

sampler Sampler1 = sampler_state 
{ 
texture   = <texture0>;
};


float3 DoTwist( float3 pos, float t )
{
	float st = sin(t);
	float ct = cos(t);
	float3 new_pos;
	
	new_pos.x = pos.x*ct - pos.z*st;
	new_pos.z = pos.x*st + pos.z*ct;
	new_pos.y = pos.y;

	return( new_pos );
}

//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------

// Our sample application will send vertices
// down the pipeline laid-out like this...

struct VS_INPUT
{
    float3 position   : POSITION;
    float2 tex0       : TEXCOORD0;
};

struct VS_OUTPUT
{
    float4 hposition : POSITION;
    float2 tex0        : TEXCOORD0;
};

//-----------------------------------------------------------------------------
// Simple Vertex Shader
//-----------------------------------------------------------------------------

VS_OUTPUT myvs( VS_INPUT IN )
{
    VS_OUTPUT OUT;
    float angle_deg = angle_deg_max*sin(time);
    float angle_rad = angle_deg * 3.14159 / 180.0;
    float ang = (height*0.5 + IN.position.y)/height * angle_rad;
    
    IN.position = DoTwist(IN.position, ang);

    OUT.hposition = mul( float4(IN.position.x ,IN.position.y ,IN.position.z, 1), worldViewProj); //
    OUT.tex0 = IN.tex0 ;

    return OUT;
}

float4 myps(float2 Tex : TEXCOORD0) : COLOR
{
    return tex2D(Sampler1, Tex);
}

technique inverse
{
    pass p1  
    {
        VertexShader = compile vs_2_0 myvs();
        PixelShader = compile ps_2_0 myps();
    }
}

Gruß Michael
Working on - MP3D Engine -
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hallo,

nachdem wir wirklich schön ein Rechteck verdreht haben, fehlt nur noch die
Spielerei mit den Variablen und der Schatten der das Objekt realistisch werden läßt.

z.B. Wird das Objekt mit den Werten

Code: Alles auswählen

float height = float(1); 
float angle_deg_max = float(1); 


mittig verdreht. Die Frage ist warum und hier die Fleißaufgabe an Euch, fällt Euch dazu was ein? :) :) :)

Jetzt wieder zu der Schattenbildung. Die Procedure DoTwist verdreht die Vertex Punkte.
Der Trick hier ist es einfach die Normals Vectoren auch damit verdrehen zu lassen.
Wir setzen dazu wieder unseren Standard Textur Normals Shader ein und benutzen auch
für die Normals die Procedure

Code: Alles auswählen

    IN.position = DoTwist(IN.position, ang);
    IN.normal.xyz= DoTwist(IN.normal.xyz, ang);


Wie man sieht recht einfach gehalten, aber effektiv

Der Shader braucht jetzt nur noch das Mesh
http://www.flasharts.de/mpz/Tower.x
und eine geladene Textur texture0

Vom Shadereditor übergeben Variablen:

worldViewProj -> Weltposition vom Editor
matWorld -> Meshposition vom Editor
lightDir -> Lichtrichtung vom Editor
texture0 -> geladene Textur, z.B. "Demo_Texture_1.bmp"
height -> länge 300 des Mesh
angle_deg_max - Drehrichtung 360 Grad
time -> die laufende Zeit in ms

Code: Alles auswählen

//-----------------------------------------------------------------------------
//     Name: Mesh_Twister_Shader_with_light.fx
//     Author: Michael Paulwitz
//    Last Modified:
//    Description: Mesh Twister Shader with texture
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Effect File Variables
//-----------------------------------------------------------------------------

float4x4 worldViewProj : WorldViewProjection; // This matrix will be loaded by the application
float4x4	matWorld      ; // For calculating normals
float3       	lightDir            ; // Our lights direction
uniform float time;

uniform float height = float(1); 
uniform float angle_deg_max = float(1); 
texture texture0;

sampler Sampler1 = sampler_state 
{ 
texture   = <texture0>;
};

float3 DoTwist( float3 pos, float t )
{
             float st = sin(t);
	float ct = cos(t);
	float3 new_pos;
	
	new_pos.x = pos.x*ct - pos.z*st;
	new_pos.z = pos.x*st + pos.z*ct;
	new_pos.y = pos.y;

	return( new_pos );
}

//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------

// Our sample application will send vertices
// down the pipeline laid-out like this...

struct VS_INPUT
{
    float3 position   : POSITION;
    float4 normal	: NORMAL0 ;
    float2 tex0       : TEXCOORD0;
};

struct VS_OUTPUT
{
    float4 hposition : POSITION;
    float2 tex0        : TEXCOORD0;
    float4 lightnormal : COLOR0;
};

//-----------------------------------------------------------------------------
// Simple Vertex Shader
//-----------------------------------------------------------------------------

VS_OUTPUT myvs( VS_INPUT IN )
{
    VS_OUTPUT OUT;
    float angle_deg = angle_deg_max*sin(time);
    float angle_rad = angle_deg * 3.14159 / 180.0;
    float ang = (height*0.5 + IN.position.y)/height * angle_rad;
    
    IN.position = DoTwist(IN.position, ang);

    OUT.hposition = mul( float4(IN.position.x ,IN.position.y ,IN.position.z, 1), worldViewProj); //
    OUT.tex0 = IN.tex0 ;
     // normalize(a) returns a normalized version of a.
     // in this case, a = vLightDirection
     float3 L = normalize(-lightDir);
     // transform our normal with matInverseWorld, and normalize it

     IN.normal.xyz= DoTwist(IN.normal.xyz, ang);

     float3 N = normalize(mul(IN.normal.xyz,matWorld      ));
     OUT.lightnormal =  saturate(dot(L, N)); 
     OUT.tex0 = IN.tex0;
    return OUT;
}

float4 myps(VS_OUTPUT IN) : COLOR
{
    return tex2D(Sampler1, IN.tex0 )*(IN.lightnormal*0.9+0.1) ;
}

technique inverse
{
    pass p1  
    {
        VertexShader = compile vs_2_0 myvs();
        PixelShader = compile ps_2_0 myps();
    }
}



Gruß Michael
Working on - MP3D Engine -
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hallo,

bei meinem heutigen Shader hat mir Stargate geholfen. http://forums.purebasic.com/german/view ... =4&t=25462
Wie wollen heute ein Mesh verformen. Wer kennt Ihn nicht den Frosch den man aufbläst zur Kugel. Dazu gehen wir wie folgt vor.
Als erstes benötigen wir eine Variable die den Wert 0-1 über eine Zeit variierend annimmt. Da wir wissen der sin(time) wert ist ein wert zwischen -1 und +1
können wir die folgende Formel nutzen:

Code: Alles auswählen

float var = (1+ sin (time))/2; // Wert von 0-1 
der Rest ist einfach. Die Vertex Kordinaten V1.xyz bwegen sich zwischen den Ausgangkoordinaten und den
normalisierten "Kugelkoordinaten"

Code: Alles auswählen

normalize(IN.position.xyz)*high ); // high = Grösse der Kugel 
Der Shader braucht jetzt nur noch das Mesh
http://www.flasharts.de/mpz/Tower.x
und eine geladene Textur texture0

Vom Shadereditor übergeben Variablen:

worldViewProj -> Weltposition vom Editor
texture0 -> geladene Textur, z.B. "Demo_Texture_1.bmp"
float high = 200; // high = Grösse der Kugel
time -> die laufende Zeit in ms

Code: Alles auswählen

//-----------------------------------------------------------------------------
//     Name: Simple_DeformToBall_Shader.fx
//     Author: Michael Paulwitz
//    Last Modified:
//    Description: Easy Vertex Shader, to defom mesh to ball
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Effect File Variables
//-----------------------------------------------------------------------------

float4x4 worldViewProjI : WorldViewProjection; // This matrix will be loaded by the application
texture texture0;
float time;
float high = 200; // high = Grösse der Kugel 

sampler Sampler1 = sampler_state 
{ 
texture   = <texture0>;
};

//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------

// Our sample application will send vertices
// down the pipeline laid-out like this...

struct VS_INPUT
{
    float3 position   : POSITION;
    float2 tex0       : TEXCOORD0;
};

struct VS_OUTPUT
{
    float4 hposition : POSITION;
    float2 tex0        : TEXCOORD0;
};

//-----------------------------------------------------------------------------
// Simple Vertex Shader
//-----------------------------------------------------------------------------

VS_OUTPUT myvs( VS_INPUT IN )
{
    VS_OUTPUT OUT;
    
    float var = (1+ sin (time))/2; // Wert von 0-1 
    float3 pos = ((var* IN.position)+((1-var)*normalize(IN.position)*high ) ); // mix zwischen Ausgangskoodinaten und Ballkoordinaten

    OUT.hposition = mul( worldViewProjI, float4(pos, 1) ); //
    OUT.tex0 = IN.tex0 ;
    return OUT;
}

float4 myps(float2 Tex : TEXCOORD0) : COLOR
{
    return tex2D(Sampler1, Tex);
}

technique Ball
{
    pass p1  
    {
        VertexShader = compile vs_2_0 myvs();
        PixelShader = compile ps_2_0 myps();
    }
}
Und auch hier kann man über die IN.position.y ein Bewegungskomponente hinzufügen...

Code: Alles auswählen

float var = (1+ sin (time+ (IN.position.y/100)))/2; // Wert von 0-1 
Gruß Michael
Working on - MP3D Engine -
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hi,

wie man abeer sieht fehlt wieder die "realistische" Beleuchtung. Also müssen wir wieder an die Normals ran. Bei einer Kugel mit einem Mittelpunkt xyz = 0,0,0 ist das aber einfach. Hier nehmen wir einfach

Code: Alles auswählen

float3 nor =  normalize(IN.position);
um die Normals der Kugel zu errechnen. Jetzt benutzen wir
die gleiche Formel die wir zur Verschiebung der Vertex Koodinaten benutzen um zwischen den Rechteck Normals und den Kugelnormals zu verschieben.

Veränderung der Normals

Code: Alles auswählen

float3 nor =  normalize(IN.position); // new normalize position  of ball
nor = (var*IN.normal.xyz) + ((1-var)*nor); 
Der Shader braucht jetzt nur noch das Mesh
http://www.flasharts.de/mpz/Tower.x
und eine geladene Textur texture0

Vom Shadereditor übergeben Variablen:

worldViewProj -> Weltposition vom Editor
matWorld -> Meshposition vom Editor
lightDir -> Lichtrichtung vom Editor
texture0 -> geladene Textur, z.B. "Demo_Texture_1.bmp"
float high = 200; // high = Grösse der Kugel
time -> die laufende Zeit in ms

Code: Alles auswählen

//-----------------------------------------------------------------------------
//     Name: Simple_DeformToBall_Shader_light.fx
//     Author: Michael Paulwitz
//    Last Modified:
//    Description: Easy Vertex Shader, to defom mesh to ball with light
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Effect File Variables
//-----------------------------------------------------------------------------

float4x4  worldViewProj : WorldViewProjection; // This matrix will be loaded by the application
float4x4  matWorld      ; // For calculating normals
float3      lightDir            ; // Our lights direction
float time;
float high = 200; // high = Grösse der Kugel 
texture texture0;

sampler Sampler1 = sampler_state 
{ 
texture   = <texture0>;
};

//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------

// Our sample application will send vertices 
// down the pipeline laid-out like this...

struct VS_INPUT
{
    float3 position	: POSITION;
    float4 normal	: NORMAL0 ;
    float2 tex0            : TEXCOORD0;
};

// Once the vertex shader is finished, it will 
// pass the vertices on to the pixel shader like this...

struct VS_OUTPUT
{
    float4 hposition    : POSITION;
    float2 tex0           : TEXCOORD0;
    float4 lightnormal : COLOR0;
};

//-----------------------------------------------------------------------------
// Simple Vertex Shader
//-----------------------------------------------------------------------------

VS_OUTPUT myvs( VS_INPUT IN)
{
    VS_OUTPUT OUT;
                
                float var = (1+ sin (time))/2;

                float3 nor =  normalize(IN.position); // new normalize position  of ball

                float3 pos = ((var* IN.position)+((1-var)*nor*high ) ); // move position
                nor = (var*IN.normal.xyz) + ((1-var)*nor); 

	OUT.hposition = mul( float4(pos,1) ,worldViewProj); //

	// normalize(a) returns a normalized version of a.
	// in this case, a = vLightDirection
	float3 L = normalize(-lightDir);
	// transform our normal with matInverseWorld, and normalize it
	float3 N = normalize(mul(nor,matWorld ));
                OUT.lightnormal =  saturate(dot(L, N)); 
                OUT.tex0 = IN.tex0;
	return OUT;
}

float4 myps(VS_OUTPUT IN) : COLOR
{
    return tex2D(Sampler1, IN.tex0 )*IN.lightnormal ;
}

//-----------------------------------------------------------------------------
// Simple Effect (1 technique with 1 pass)
//-----------------------------------------------------------------------------

technique Technique0
{
    pass Pass0
    {

                VertexShader = compile vs_2_0 myvs();
	PixelShader = compile ps_2_0 myps();
    }
}

Working on - MP3D Engine -
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hi,

es gibt einen neuen Shadereditor Version 0.6 (download über den ersten Beitrag). Mit einigen neuen Funktionen:

* Änderung der Hintergrundfarbe
* Setze Farbe von Vertex eines Meshs
* Lösche Farbe von Vertex eines Meshs


Das heutige Thema lautet Darstellung von Texturen. Dazu laden wir den "Simple_VertexTexture_Shader.fx"
und modifizieren hier die Textur UV Werte indem wir diese verdreifachen. Dadurch werden die Veränderungen besser sichtbar

VS_OUTPUT myvs( VS_INPUT IN )
...
OUT.tex0 = IN.tex0 *3 ; // * 3 ist hier die verdreifachung



Vom Shadereditor übergeben Variablen:

worldViewProj -> Weltposition vom Editor
texture0 -> geladene Textur, z.B. "Demo_Texture_1.bmp"

Code: Alles auswählen

//-----------------------------------------------------------------------------
//     Name: Simple_VertexTexture_Shader.fx
//     Author: Michael Paulwitz
//    Last Modified:
//    Description: Easy Vertex Shader, Show only the texture of the mesh
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Effect File Variables
//-----------------------------------------------------------------------------

float4x4 worldViewProj : WorldViewProjection; // This matrix will be loaded by the application

texture texture0;

sampler Sampler1 = sampler_state 
{ 
texture   = <texture0>;

};

//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------

// Our sample application will send vertices
// down the pipeline laid-out like this...

struct VS_INPUT
{
    float3 position   : POSITION;
    float2 tex0       : TEXCOORD0;
};

struct VS_OUTPUT
{
    float4 hposition : POSITION;
    float2 tex0        : TEXCOORD0;
};

//-----------------------------------------------------------------------------
// Simple Vertex Shader
//-----------------------------------------------------------------------------

VS_OUTPUT myvs( VS_INPUT IN )
{
    VS_OUTPUT OUT;
    OUT.hposition = mul( float4(IN.position.x ,IN.position.y ,IN.position.z, 1),worldViewProj ); //

    OUT.tex0 = IN.tex0 *3 ;  // * 3 ist hier die verdreifachung

    return OUT;
}

float4 myps(float2 Tex : TEXCOORD0) : COLOR
{
    return tex2D(Sampler1, Tex);
}

technique inverse
{
    pass p1  
    {
        VertexShader = compile vs_2_0 myvs();
        PixelShader = compile ps_2_0 myps();
    }
}


wie wir sehen wird die Textur auf dem Würfel verdoppelt.

Jetzt modifizieren wir aber einfach die Funktion der Texuren

Normale verdreifachung der Textur

Code: Alles auswählen

sampler Sampler1 = sampler_state 
{ 
    texture   = <texture0>;
    AddressU = Wrap;
    AddressV = Wrap;
};


Textur wird einmal dargestellt aber letzte Farbreihe weitergeführt

Code: Alles auswählen

sampler Sampler1 = sampler_state 
{ 
    texture   = <texture0>;
    AddressU = Clamp;
    AddressV = Clamp;
};


Textur wird einmal dargestellt und die zweite Textur gespiegelt

Code: Alles auswählen

sampler Sampler1 = sampler_state 
{ 
    texture   = <texture0>;
    AddressU = MIRROR;
    AddressV = MIRROR;

};


Textur wird einmal dargestellt und der Rest schwarz

Code: Alles auswählen

sampler Sampler1 = sampler_state 
{ 
    texture   = <texture0>;
    AddressU = BORDER;
    AddressV = BORDER;

};


Das nächste Thema ist schon fertig und kommt bald, das animieren von Grass.

Gruß Michael
Working on - MP3D Engine -
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hallo,

da wir das letzte mal mit Texturen beschäftigt waren denke ich das es am sinnvollsten ist
hier noch ein paar Möglichkeiten zu erleutern. Zudem werde ich beginnen ein paar Proceduren
zu erstellen die im Shaderbereich einfacher zu benutzen sind. Eine Erweiterung mit einer
kleinen Datenbank um die Proceduren zu verwalten wird es zukünftig im Shadereditor geben.

Also gibt es heute die Procedure um eine Texture zu drehen. Dazu folgende Vorüberlegungen:
Die UV Texturkoordinaten kann man als 2D Vectoren ansehen mit den Vetorenpaaren:
UV1 = (0,0) , UV2 = (1,0), UV3 = (0,1), UV4 = (1,1)
UM eine Textur zu drehen mus man quasi die UV(1-4) drehen.

Dazu gibt es den
x1=sin(Arctan2 (x,y)+rad)
y1=cos(Arctan2 (x,y)+rad)

gilt aber nur für den Radius mit den Einheitsvector "1" um das auf die Koordinaten zu
projezieren benutzen wir den alten Phytagoras x1* sqr(1*1+1*1)/2

x1=sin(Arctan2 (x,y)+rad)*0.71
y1=cos(Arctan2 (x,y)+rad)*0.71

Dazu müssen wir noch den Mittelpunkt bestimmen den wir als middle = 0.5 bezeichnen

Das Ergebniss ist folgende Funktion:

Code: Alles auswählen

float2 DoTurnTex( float2 postex, float t ) // t = Rad oder t * 0.017453 = Grad
{
  float2 new_postex;
  float middle = float (0.5);
  postex -= 0.5 ;
  // t*= 0.017453; // makes from radiant to grad
  new_postex.x = sin(atan2(postex.x,postex.y)+t)*0.71+ middle;
  new_postex.y = cos(atan2(postex.x,postex.y)+t)*0.71+ middle;
  return( new_postex );
}
Das testen wir mit einem Standardshader

Vom Shadereditor übergeben Variablen:

worldViewProj -> Weltposition vom Editor
texture0 -> geladene Textur, z.B. "Demo_Texture_1.bmp"

Code: Alles auswählen

//-----------------------------------------------------------------------------
//     Name: Simple_Texture_Shader.fx

//     Author: Michael Paulwitz
//    Last Modified:
//    Description: Easy Vertex Shader, Show only the texture of the mesh
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Effect File Variables
//-----------------------------------------------------------------------------

float4x4 worldViewProjI : WorldViewProjection; // This matrix will be loaded by the application

texture texture0;
float time;
sampler Sampler1 = sampler_state 
{ 
texture   = <texture0>;
};

//-----------------------------------------------------------------------------
// Vertex Definitions
//-----------------------------------------------------------------------------

// Our sample application will send vertices
// down the pipeline laid-out like this...

struct VS_INPUT
{
    float3 position   : POSITION;
    float2 tex0       : TEXCOORD0;
};

struct VS_OUTPUT
{
    float4 hposition : POSITION;
    float2 tex0        : TEXCOORD0;
};


float2 DoTurnTex( float2 postex, float t ) // t = Rad oder t * 0.017453 = Grad
{
  float2 new_postex;
  float middle = float (0.5);
  postex -= 0.5 ;
  // t*= 0.017453; // makes from radiant a grad function
  new_postex.x = sin(atan2(postex.x,postex.y)+t)*0.71+ middle;
  new_postex.y = cos(atan2(postex.x,postex.y)+t)*0.71+ middle;
  return( new_postex );
}




//-----------------------------------------------------------------------------
// Simple Vertex Shader
//-----------------------------------------------------------------------------

VS_OUTPUT myvs( VS_INPUT IN )
{
    VS_OUTPUT OUT;
    OUT.hposition = mul( worldViewProjI, float4(IN.position.x ,IN.position.y ,IN.position.z, 1) ); //
    
    OUT.tex0 = DoTurnTex( IN.tex0,time); // Hier dreht die Texture
    
    return OUT;
}

float4 myps(float2 Tex : TEXCOORD0) : COLOR
{
    return tex2D(Sampler1, Tex);
}

technique inverse
{
    pass p1  
    {
        VertexShader = compile vs_2_0 myvs();
        PixelShader = compile ps_2_0 myps();
    }
}

Gruß Michael
Working on - MP3D Engine -
Benutzeravatar
mpz
Beiträge: 489
Registriert: 14.06.2005 15:53
Computerausstattung: Win XP SP3, 2 GB Ram, AMD CPU und NVIDEA GT250 Grafikkarte, PB 4.41 / 4.50 beta2
Wohnort: Berlin, Kreuzberg

Re: Tutorial: Vertex Shader & Pixel Shader Unterstützung in

Beitrag von mpz »

Hallo,

da mein dieswöchiger Urlaub aufgrund eines Motorschadens nicht stattfand habe ich mal
wieder Zeit ein Tutorial vorzubereiten.

Hier geht es jetzt um Grassanimation und die "mehr Pass" Funktion.

Was wir daher als erstes benötigen ist eine Mesh der im Prinzip aus 3 flachen Rechtecken
besteht der in der Mitte um 120 Grad verschoben ist und ein Grass Bild mit Alphakanal damit
das Bild an der richtigen Stelle durchscheint. Wer es mag kann auch verschiedene Meshes
benutzen und mehr oder weniger Rechtecke ungleichmäßig zusammenstellen.

Bild

Wie man den letzten Tutorial entnehmen konnte ist es am einfachste ein Mesh in der x und z Achse
über den y Positionswert zu animieren. D.h. das der höchste y Positionswert sich auch am meisten
bewegt. Hier wird zudem die z Achse doppelt so schnell über die Zeit bewegt wie der Pos.x Wert

Code: Alles auswählen

    Pos.x   += cos(time) * Pos.y * 0.02;
    Pos.z   += cos(time*2) * Pos.y * 0.02;
Jetzt kommen wir zur der "mehr Pass" Funktion. D.h wir sagen dem Shader führe erst die Funktion 1,
dann die Funktion 2 und dan die Funktion 3 aus

Code: Alles auswählen

pass p0 
	{
                   Funktion 1 ausführen
	}
pass p1 
	{
                   danach Funktion 2 ausführen
	}
pass p2 
	{
                   als letztes die Funktion 3 ausführen
	}
in meinem Beispiel verdreifachen wir einfach das Mesh und
stellen es unterschiedlich mit unterschiedlichen Bewegungen dar.

Code: Alles auswählen

"Hauptmesh"
    Pos.x   += cos(time) * Pos.y * 0.02;
    Pos.z   += cos(time*2) * Pos.y * 0.02;

"Rechtsmesh"
    Pos.x   += cos(time*2) * Pos.y * 0.02 + 4;
    Pos.z   += cos(time) * Pos.y * 0.02;

die +4 bestimmt die rechte Position  

"Linksmesh"
    Pos.x   += cos(time*2) * Pos.y * 0.02 - 4;
    Pos.z   += cos(time*2) * Pos.y * 0.02;

die -4 bestimmt die linke Position  
Hier jetzt das Beispiel:
Vom Shadereditor übergeben Variablen:

worldViewProj -> Weltposition vom Editor
texture0 -> geladene Textur, z.B. "grass1.tga"
time -> die laufende Zeit in ms

Der Shader braucht jetzt nur noch das Mesh
http://www.flasharts.de/mpz/Grass_Variante_1.x

und eine geladene Textur texture
http://www.flasharts.de/mpz/grass1.tga

Code: Alles auswählen

// Modified Version of the Grass Demo From ATI
// grass.fx
// Modifyt for MP3D by Michael
 
texture   texture0;
float4x4  worldViewProj;
float time;

// Faktoren (Tweakables)
float   g_fAlpha          = 10; 

// float4    windDirection;

sampler GrassSampler= sampler_state 
{
	Texture = <texture0>;
	
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
                AddressU = Clamp;
                AddressV = Clamp;
};

struct VS_OUTPUT
{
    float4 Pos   : POSITION;
    float2 Tex   : TEXCOORD0;
};

//
// V E R T E X - S H A D E R
//

VS_OUTPUT VSGrass(float4 Pos : POSITION,
                  float2 Tex : TEXCOORD0)
{
    VS_OUTPUT Out;

    Pos.x   += cos(time) * Pos.y * 0.02;
    Pos.z   += cos(time*2) * Pos.y * 0.02;

    Out.Pos   = mul(Pos, worldViewProj);
    Out.Tex   = Tex;

    return Out;
}

VS_OUTPUT VSGrass2(float4 Pos : POSITION,
                  float2 Tex : TEXCOORD0)
{
    VS_OUTPUT Out;

    Pos.x   += cos(time*2) * Pos.y * 0.02 + 4;
    Pos.z   += cos(time) * Pos.y * 0.02;

    Out.Pos   = mul(Pos, worldViewProj);
    Out.Tex   = Tex;

    return Out;
}

VS_OUTPUT VSGrass3(float4 Pos : POSITION,
                  float2 Tex : TEXCOORD0)
{
    VS_OUTPUT Out;

    Pos.x   += cos(time*2) * Pos.y * 0.02 - 4;
    Pos.z   += cos(time*2) * Pos.y * 0.02;

    Out.Pos   = mul(Pos, worldViewProj);
    Out.Tex   = Tex;

    return Out;
}

//
// P I X E L - S H A D E R
//

float4 PSGrass(VS_OUTPUT In) : COLOR0
{
    float4 TexColor = tex2D(GrassSampler, In.Tex);
    return float4(TexColor.rgb, g_fAlpha * TexColor.a);
}

// Techniques
technique grass 
{
	pass p0 
	{
                                Lighting         = FALSE;
                                AlphaTestEnable  = TRUE;
                                AlphaFunc        = Greater;

		VertexShader = compile vs_2_0 VSGrass();
		PixelShader = compile ps_2_0 PSGrass ();
	}
	pass p1 
	{
       		VertexShader = compile vs_2_0 VSGrass2();
		PixelShader = compile ps_2_0 PSGrass ();
	}
	pass p2 
	{
       		VertexShader = compile vs_2_0 VSGrass3();
		PixelShader = compile ps_2_0 PSGrass ();
	}
}

Gruß Michael
Working on - MP3D Engine -
Antworten