Interaktive NPR-Darstellung von Metalloberflächen in Airbrushtechnik

Quelltexte

Vertexshader des Hauptdurchgangs

#define LOCALVIEWER true
#define Texturdaten true

float4x4 matWeltKameraProjektion; //Objektkoordinaten -> Projektionskoordinaten
float4x4 matWelt;         //Objektkoordinaten -> Kamerakoordinaten
float4x4 matWeltInvTrans; //Objektkoordinaten -> Kamerakoordinaten für die Normalen
float4x4 matKameraInv;    //Kamerakoordinaten -> Weltkoordinaten
float TexGroesse = 64;    //gibt Größe der quadratischen Zufallstextur in Texeln an
float BildGroesseX;       //Abmessungen des zu rendernden Bildes in Pixeln
float BildGroesseY;

struct PixelVertex
{
   float4 Position     : POSITION;  //Vertexposition in Projektionskoordinaten
   float4 BildPosition : TEXCOORD0; //Kopie der Vertexposition für Pixelshader
   float3 Normale      : TEXCOORD1;
   float3 Tangente     : TEXCOORD2;
   float3 Binormale    : TEXCOORD3;
   float4 Textur2x     : TEXCOORD4; //enthält 2 2D-Koordinaten:
                                    //Textur in .xy, Modulationstextur in .zw
   float3 KameraVekt   : TEXCOORD5; //Sichtrichtung
   float3 WeltPosition : TEXCOORD6; //Vertexposition in Weltkoordinaten
};

PixelVertex main(
   float4 VertexPosition : POSITION,
   float3 VertexNormale  : NORMAL,
   float3 VertexTangente : TANGENT,   //enthält Tangente
   float2 VertexTex      : TEXCOORD0) //enthält Texturkoordinaten
{
   PixelVertex Res;

   //transformiere Position in den Projektionsraum
   Res.Position = mul( matWorldViewProjection, VertexPosition );
   Res.BildPosition = Res.Position * float4((BildGroesseX / 2) / TexGroesse,
                                            (BildGroesseY / 2) / TexGroesse,1,1);

   //übergebe Texturkoordinaten
   Res.Textur2x.xy = VertexTex;

   //ermittle Sprühmodulationstexturkoordinaten
   if(Texturdaten)
   {
      //verwende existierende Texturkoordinaten für Modulationstextur
      Res.Textur2x.zw = VertexTex; //verwende exisiterende Koordinaten
   }
   else
   {
      //verwende Spiegelung von (1,0,0) aus in Objektkoordinaten
      Res.Textur2x.zw = 2 * VertexNormale.x * VertexNormale - (1,0,0);
   }

   //transformiere Normale (nach außen gerichtet) in Weltkoordinaten
   Res.Normale = normalize(mul(matWorldInvTrans,float4(VertexNormale.xyz,0))).xyz;
   //transformiere Tangente/Binormale in Weltkoordinaten
   Res.Tangente = normalize(mul(matWorld,float4(VertexTangente.xyz,0))).xyz;
   Res.Binormale = cross(Res.Normale,Res.Tangente);

   //ermittle Position in Weltkoordinaten (benötigt für Punktlichtquellen)
   Res.WeltPosition = mul(matWorld,VertexPosition);

   //ermittle Sichtrichtung (Kamera->Vertex) in Weltkoordinaten
   if(LOCALVIEWER)
   {
      //Kameraposition = Ursprung der Kamerakoordinaten
      Res.KameraVekt = normalize(mul(matWorld,VertexPosition).xyz - mul(matViewInv,float4(0,0,0,1)).xyz);
   }
   else
   {
      //verwende unendlich weit entfernte Kamera mit Sichtrichtung in z-Richtung in Kamerakoordinaten
      Res.KameraVekt = normalize(mul(matViewInv,float4(0,0,1,0)).xyz);
   }

   return Res;
}

Pixelshader des Hauptdurchgangs

//allgemeine Konstanten
const float PI=3.14159265359;

//Lichtquellen
//Anzahl der Lichtquellen
#define LichtNum 2
//aktuell verwendete Lichtquellen
#define MinLichtNum 0
#define MaxLichtNum 2
const bool Punktlicht=true;
const bool Richtungslicht=false;
struct Lichtquelle
{
   float4 Ambient;
   float4 Diffus;
   float4 GegenlichtDiffus;
   float4 Spekular;
   float3 Vektor; //Position oder Richtung
   bool Typ;      //Punktlicht=true oder Richtungslicht=false;
};
Lichtquelle Licht[MaxLichtNum];
float4 LichtfarbeEnv;
sampler EnvMap;
float4 EnvFarbe(float3 Richtung); //liest Farbe des Umgebungslichts

//Material
float4 DiffuseFarbe;
float4 SpekulareFarbe;
float Spekularexponent;
float Isotropie;
#define Abtastpunkte 5
sampler AnisoMap;
sampler BumpMap;
sampler decaltexture;

//Sprüheffekt
float Spruehparameter; //globale Variable, verwendet in spray(...)
float Streuung;
float Verlauf;
float z_Daempfung;
float TexGroesse;
float ModTexBreite;
sampler Zufallswerte;
sampler Modulierer;
sampler Relinearisierer;
float4x4 matKameraProjektion; //Kamerakoordinaten->Projektionskoordinaten
float Spray(float Intensitaet,float Spruehparameter); //berechnet lokale Intensität

float4 main(float4 BildPosition : TEXCOORD0,
            float3 IntNormale   : TEXCOORD1,
            float3 IntTangente  : TEXCOORD2,
            float3 IntBinormale : TEXCOORD3,
            float4 Textur2x     : TEXCOORD4, //enthält 2 2D-Koordinaten
            float3 IntKameraVekt: TEXCOORD5,
            float3 WeltPosition : TEXCOORD6) : COLOR
{
   //berechne lokale Geometrie (in Weltkoordinaten)

   //Objektparameter
   float2 Textur = Textur2x.xy;
   float2 TexturMod = Textur2x.zw;
   float3 TexNormale = normalize(IntNormale);
   float3 Tangente  = normalize(IntTangente);
   float3 Binormale = normalize(IntBinormale);

   //BumpMap
   float3 Normale = TexNormale;
   float3 Offset = tex2D(BumpMap,Textur);
   Normale = normalize(TexNormale + Offset.x * Tangente + Offset.y * Binormale);

   //Anisotropiehauptachse (Tangente der Schraffur)
   float2 Rotation = normalize(tex2D(AnisoMap,Textur).xy);
   float3 Anisotropieachse = Rotation.x * Tangente + Rotation.y * Binormale;
   //Anisotropietangente projiziert und skaliert
   float3 Anisotropietangente = mul(matViewProjection,float4(Anisotropieachse.xyz,0));
   float2 AnisotropietangenteBild = 1 / (TexGroesse/sqrt(2.))
                                    * normalize(Anisotropietangente.xy
                                                - Anisotropieachse.z * normalize(BildPosition.xy));

   //ermittle Sprühparameter
   //moduliere Streuung mit Entfernung
   float LokaleStreuung = Streuung;
   if(Tiefendaempfung_An)
   {
     LokaleStreuung*= (1. - (BildPosition.z / BildPosition.w) * z_Daempfung);
   }

   //skaliere Modulationstextur anhand des sichtbaren Bereichs
   float Modulation = tex2D(Modulierer,TexturMod);

   //Lese Zufallswert (mit linearem Filter in Richtung der Anisotropietangente)
   float4 Zufallswert = tex2Dproj(Zufallswerte,BildPosition);

   //projiziere Position in Bildraum
   float2 TexPosP = BildPosition.xy / BildPosition.w;
   float2 TexPosN = BildPosition.xy / BildPosition.w;
   //berechne gefilterten Wert
   float4 ZufallswertAniso = Zufallswert;
   for(int i=0; i<((Abtastpunkte - 1) / 2); i++)
   {
     TexPosP-= AnisotropietangenteBild;
     TexPosN+= AnisotropietangenteBild;
     ZufallswertAniso+= tex2D(Zufallswerte,TexPosP);
     ZufallswertAniso+= tex2D(Zufallswerte,TexPosN);
   }
   //erzeuge gleichverteilte Werte:
   ZufallswertAniso = tex2D(Relinearisierer,ZufallswertAniso / Abtastpunkte);
   Zufallswert = lerp(ZufallswertAniso,Zufallswert,Isotropie);

   //Moduliere Zufallswert und skaliere
   float4 Spruehparameter = LokaleStreuung * (0.5 - frac(Modulation + Zufallswert));

   //globale Beleuchtungsparameter
   float4 SpekularerAnteil = 0;
   float4 DiffuserAnteil = 0;
   float3 KameraVekt = normalize(IntKameraVekt);
   float3 ReflektVekt = reflect(KameraVekt,Normale);

   //Materialfarbe
   float4 SpekulareFarbeFresnel = SpekulareFarbe;
   float4 DiffuseFarbeFresnel = DiffuseFarbe;
   //Fresnel-Farbkorrektur
   float FresnelRef = pow(1 - saturate(dot(-KameraVekt,Normale)),5);
   SpekulareFarbeFresnel = lerp(SpekulareFarbe,1,FresnelRef);
   //diffuse Fresnel-Farbkorrektur vernachlässigbar:
   DiffuseFarbeFresnel = DiffuseFarbe;

   for(int i = MinLichtNum; i<MaxLichtNum; i++)
   {
      //lokale Beleuchtungsparameter
      float3 LichtVekt;
      if(Licht[i].Typ==Richtungslicht)
      {
         LichtVekt = -normalize(Licht[i].Vektor.xyz);
      }
      else
      {
         LichtVekt = normalize((Licht[i].Vektor - WeltPosition).xyz);
      }
      float3 Spekularorientierung;
      float cos_Spekularwinkel;
      float cos_LichtNormale = dot(LichtVekt,Normale);

      Spekularorientierung = normalize(-KameraVekt + LichtVekt);
      cos_Spekularwinkel = dot(Spekularorientierung,Normale);

      //berechne Beleuchtung
      float SpekularexponentAniso = Spekularexponent;

      //berechne anisotropen Spekularwert (für Blinn-Phong vom Ort der Lichtquelle abhängig)
      float cos_ReflektAnisotropieachse = dot(Spekularorientierung,Anisotropieachse);
      float cos_ReflektNormale = dot(Spekularorientierung,TexNormale);
      //Tangentiale Komponente des Richtungsvektors ^2
      float OrientierungAniso = pow(cos_ReflektAnisotropieachse,2);
      //Länge des in die Ebene projizierten Richtungsvektor ^2:
      float KorrekturAniso = 1 / (1 - pow(cos_ReflektNormale,2));
      SpekularexponentAniso = lerp(Spekularexponent / Isotropie,Spekularexponent * Isotropie,
                                   OrientierungAniso * KorrekturAniso);

      //Phong mit diffusem negativem Gegenlicht (Ambientes Licht ggf. anpassen)
      float IntensitaetAmbient = 1;
      float IntensitaetDiffus = abs(cos_LichtNormale);
      float IntensitaetSpekular = pow(saturate(cos_Spekularwinkel),SpekularexponentAniso);
      float4 RefFarbeAmbient = DiffuseFarbeFresnel * Licht[i].Ambient;
      float4 RefFarbeDiffus = ((cos_LichtNormale>0)
                               ?DiffuseFarbeFresnel * Licht[i].Diffus
                               :DiffuseFarbeFresnel * Licht[i].GegenlichtDiffus);
      float4 RefFarbeSpekular = SpekulareFarbeFresnel * Licht[i].Spekular;

      //wende Beleuchtung an
      //Diffuse Reflexion
      float4 DiffusesLicht = RefFarbeDiffus * Spray(IntensitaetDiffus,Spruehparameter.z);
      float4 AmbientesLicht = RefFarbeAmbient * IntensitaetAmbient;
      DiffuserAnteil+= DiffusesLicht + AmbientesLicht;
      //Spekulare Reflexion
      SpekularerAnteil+= RefFarbeSpekular * Spray(IntensitaetSpekular,Spruehparameter.w);
   }

   //resultierende Farbe
   float4 Pixel = SpekularerAnteil + DiffuserAnteil;

   //Environment Map
   float IntensitaetEnvmap = 1; //für Metalle praktisch winkelunabhängig
   float Streuweite = saturate(3 / sqrt(Spekularexponent));
   float4 RefFarbeEnv = SpekulareFarbeFresnel * LichtfarbeEnv;
   float3 EnvreflektVekt = ReflektVekt + Spruehparameter.xyz * Streuweite;
   float4 EnvAnteil = RefFarbeEnv * EnvFarbe(EnvreflektVekt) * IntensitaetEnvmap;
   Pixel+= EnvAnteil;

   return Pixel;
}

Vertexshader zur Erzeugung der spekularen Textur (erster Durchgang)

#define LOCALVIEWER true
#define Texturdaten true

float4x4 matWeltKameraProjektion; //Objektkoordinaten -> Projektionskoordinaten
float4x4 matWelt;         //Objektkoordinaten -> Kamerakoordinaten
float4x4 matWeltInvTrans; //Objektkoordinaten -> Kamerakoordinaten für die Normalen
float4x4 matKameraInv;    //Kamerakoordinaten -> Weltkoordinaten
float TexGroesse;         //gibt Größe der quadratischen Zufallstextur in Texeln an
float BildGroesseX;       //Abmessungen des zu rendernden Bildes in Pixeln
float BildGroesseY;

struct PixelVertex
{
   float4 Position     : POSITION;
   //TEXCOORD0 : nicht benötigt
   float3 Normale      : TEXCOORD1;
   float3 Tangente     : TEXCOORD2;
   float3 Binormale    : TEXCOORD3;
   float4 Textur2x     : TEXCOORD4; //enthält 2 2D-Koordinaten
   float3 KameraVekt   : TEXCOORD5;
   float3 WeltPosition : TEXCOORD6;
};

PixelVertex main(
   float4 VertexPosition : POSITION,
   float3 VertexNormale  : NORMAL,
   float3 VertexTangente : TANGENT,
   float2 VertexTex      : TEXCOORD0)
{
   PixelVertex Res;

   //transformiere Position in den Projektionsraum
   Res.Position = mul( matWorldViewProjection, VertexPosition );

   //übergebe Texturkoordinaten
   Res.Textur2x.xy = VertexTex;

   //ermittle Sprühmodulationstexturkoordinaten
   if(Texturdaten)
   {
      Res.Textur2x.zw = VertexTex; //verwende exisiterende Koordinaten
   }
   else
   {
      //verwende Spiegelung von (1,0,0) aus im Objektraum
      Res.Textur2x.zw = 2 * VertexNormale.x * VertexNormale - (1,0,0);
   }

   //transformiere Normale (nach außen gerichtet) in Weltkoordinaten
   Res.Normale = normalize(mul(matWorldInvTrans,float4(VertexNormale.xyz,0))).xyz;

   //transformiere Tangente/Binormale in Weltkoordinaten
   Res.Tangente = normalize(mul(matWorld,float4(VertexTangente.xyz,0))).xyz;
   Res.Binormale = cross(Res.Normale,Res.Tangente);

   //ermittle Position in Weltkoordinaten (für Punktlichtquellen)
   Res.WeltPosition = mul(matWorld,VertexPosition);

   //ermittle Sichtrichtung (Kamera->Vertex) in Weltkoordinaten
   if(LOCALVIEWER)
   {
      //Kameraposition = Ursprung der Kamerakoordinaten
      Res.KameraVekt = normalize(mul(matWorld,VertexPosition).xyz - mul(matViewInv,float4(0,0,0,1)).xyz);
   }
   else
   {
      //verwende unendlich weit entfernte Kamera mit Sichtrichtung in z-Richtung in Kamerakoordinaten
      Res.KameraVekt = normalize(mul(matViewInv,float4(0,0,1,0)).xyz);
   }

   return Res;
}

Pixelshader zur Erzeugung der spekularen Textur (erster Durchgang)

//allgemeine Konstanten
const float PI=3.14159265359;

//Lichtquellen
//Gesamtzahl Lichtquellen
#define LichtNum 2
//aktuell verwendete Lichtquellen
#define MinLichtNum 0
#define MaxLichtNum 2
const bool Punktlicht=true;
const bool Richtungslicht=false;
struct LichtquelleSpekular
{
   float3 Vektor; //float4 Position oder Richtung
   bool Typ;      //Punktlicht=true oder Richtungslicht=false;
};
Lichtquelle Licht[MaxLichtNum];

//Material
float4 SpekulareFarbe;
float Spekularexponent;
float Isotropie;
sampler AnisoMap;
sampler BumpMap;

//Effekt
float Spitzlichtstaerke; //Einstellung der Effektstärke durch Skalierung der Intensität
sampler Modulierer;

float4 main(float3 IntNormale   : TEXCOORD1,
            float3 IntTangente  : TEXCOORD2,
            float3 IntBinormale : TEXCOORD3,
            float4 Textur2x     : TEXCOORD4, //enthält 2 2D-Koordinaten
            float3 IntKameraVekt: TEXCOORD5,
            float3 WeltPosition : TEXCOORD6) : COLOR
{
   //berechne lokale Geometrie (in Weltkoordinaten)

   //Objektparameter
   float2 Textur = Textur2x.xy;
   float2 TexturMod = Textur2x.zw;
   float3 TexNormale = normalize(IntNormale);
   float3 Tangente =  normalize(IntTangente);
   float3 Binormale = normalize(IntBinormale);

   //BumpMap
   float3 Normale = TexNormale;
   float3 Offset = tex2D(BumpMap,Textur);
   Normale = normalize(TexNormale + Offset.x * Tangente + Offset.y * Binormale);

   //Anisotropiehauptachse (Tangente der Schraffur)
   float2 Rotation = normalize(tex2D(AnisoMap,Textur).xy);
   float3 Anisotropieachse = Rotation.x * Tangente + Rotation.y * Binormale;

   //skaliere Modulationstextur anhand des sichtbaren Bereichs
   float Modulation = tex2D(Modulierer,TexturMod);

   //globale Beleuchtungsparameter
   float IntensitaetSpekular = 0;
   float3 KameraVekt = normalize(IntKameraVekt);
   float3 ReflektVekt = reflect(KameraVekt,Normale);

   for(int i=MinLichtNum; i<MaxLichtNum; i++)
   {
      //lokale Beleuchtungsparameter
      float3 LichtVekt;
      if(Licht[i].Typ==Richtungslicht)
      {
         LichtVekt = -normalize(Licht[i].Vektor.xyz);
      }
      else
      {
         LichtVekt = normalize((Licht[i].Vektor - WeltPosition).xyz);
      }
      float3 Spekularorientierung;
      float cos_Spekularwinkel;
      Spekularorientierung = normalize(-KameraVekt + LichtVekt);
      cos_Spekularwinkel = dot(Spekularorientierung,Normale);

      //berechne Beleuchtung
      float SpekularexponentAniso = Spekularexponent;
      if(Anisotropie_An)
      {
         //berechne anisotropen Spekularwert (für Blinn-Phong vom Ort der Lichtquelle abhängig)
         float cos_ReflektAnisotropieachse = dot(Spekularorientierung,Anisotropieachse);
         float cos_ReflektNormale = dot(Spekularorientierung,TexNormale);
         //Tangentiale Komponente des Richtungsvektors ^2:
         float OrientierungAniso = pow(cos_ReflektAnisotropieachse,2);
         //Länge des in die Ebene projizierten Richtungsvektor ^2
         float KorrekturAniso = 1 / (1 - pow(cos_ReflektNormale,2));
         SpekularexponentAniso = lerp(Spekularexponent / Isotropie,Spekularexponent * Isotropie,
                                      OrientierungAniso * KorrekturAniso);
      }
      //(hier: Phong mit diffusem negativem Gegenlicht (Ambientes Licht ggf. anpassen))
      IntensitaetSpekular+= pow(saturate(cos_Spekularwinkel),SpekularexponentAniso);
   }

   //resultierende Intensität
   float4 Pixel;
   Pixel.rgb = Spitzlichtstaerke * IntensitaetSpekular;

   //übergebe Wert der Modulationstextur an zweiten Durchgang
   Pixel.a = Modulation;

   return Pixel;
}

Vertexshader für Glanzlichter (zweiter Durchgang)

float TexGroesse;   //Größe der quadratischen Zufallstextur in Texeln
float BildGroesseX; //Abmessungen des zu rendernden Bildes in Pixeln
float BildGroesseY;
float4 LichtVekt1;  //Lichtrichtung der hellsten Lichtquelle

float4x4 matKamera; //Weltkoordinaten -> Kamerakoordinaten

struct PixelVertex
{
   float4 Position:      POSITION;
   float4 BildPosition:  TEXCOORD0;
   float2 BildLichtVekt: TEXCOORD1;
};

PixelVertex main( float4 VertexPosition: POSITION )
{
   PixelVertex Res;

   //übergebe Koordinaten (Tiefe: vordere Z-Grenze)
   Res.Position.xy = VertexPosition;
   Res.Position.zw = float2(0,1);

   //transformiere Bildkoordinaten in entsprechende Texturkoordinaten
   Res.BildPosition.x = 0.5 * ( Res.Position.x + 1);
   Res.BildPosition.y = 0.5 * (-Res.Position.y + 1);
   Res.BildPosition.zw = Res.Position * float2((BildGroesseX / 2) / TexGroesse,
                                               (BildGroesseY / 2) / TexGroesse);

   //projiziere Lichtvektor in Bildebene
   float3 BildLichtVekt = float3(1,-1,1) * mul(matView,float4(LichtVekt1.xyz,0)).xyz;
   Res.BildLichtVekt = normalize(BildLichtVekt.xyz).xy;

   return Res;
}

Pixelxshader für Glanzlichter (zweiter Durchgang)

float Spitzlichtweite;  //Streuradius eines Texels in der spekularen Textur
float Spitzlichtoffset; //Stärke der Verschiebung des Streukreises in
                        //Richtung der hellsten Lichtquelle

sampler Zufallswerte;
sampler SpekularTex;    //enthält spekulare Intensität in R,G und B dupliziert
                        //sowie Modulationswert im Alphakanal

float4 main( float4 TexPos2x: TEXCOORD0, float2 LichtVektProj: TEXCOORD1) : COLOR0
{
   //ermittle Effektparameter
   float4 Spruehparameter = - 0.5 + frac(tex2D(Zufallswerte,TexPos2x.zw)
                                         + tex2D(SpekularTex,TexPos2x.xy).aaaa);
   float4 Spruehoffset = Spruehparameter * Spitzlichtweite;
   float2 Lichtoffset = Spitzlichtoffset * LichtVektProj;

   //berechne Effekt
   float2 Leseposition = TexPos2x.xy + Lichtoffset;
   float4 Spitzlichtfarbe = 0;
   Spitzlichtfarbe+= tex2D(SpekularTex,Leseposition+Spruehoffset.xy) * (1 -2 * length(Spruehparameter.xy));
   Spitzlichtfarbe+= tex2D(SpekularTex,Leseposition+Spruehoffset.zw) * (1 -2 * length(Spruehparameter.zw));
   Spitzlichtfarbe+= tex2D(SpekularTex,Leseposition+Spruehoffset.yw) * (1 -2 * length(Spruehparameter.yw));
   Spitzlichtfarbe+= tex2D(SpekularTex,Leseposition+Spruehoffset.xz) * (1 -2 * length(Spruehparameter.xz));
   return Spitzlichtfarbe;
}

Vertexshader für Sterneffekte (zweiter Durchgang)

// D3DRS_POINTSPRITEENABLE ist vor Verwendung des Shaders zu aktivieren

#define LOCALVIEWER true

float4x4 matWeltKameraProjektion;
float4x4 matWelt;
float4x4 matWeltInvTrans;
float4x4 matKameraInv;
float Spekularexponent;
float Spritegroesse; //maximale Größe des Sprites im Bildraum in Pixeln

//Lichtquellen
//Gesamtzahl Lichtquellen
#define LichtNum 2
//aktuell verwendete Lichtquellen
#define MinLichtNum 0
#define MaxLichtNum 2
const bool Punktlicht=true;
const bool Richtungslicht=false;
struct LichtquelleSpekular
{
   float3 Vektor; //float4 Position oder Richtung
   bool Typ;      //Punktlicht=true oder Richtungslicht=false;
};
Lichtquelle Licht[MaxLichtNum];

struct PixelVertex
{
   float4 Position     : POSITION;
   float2 BildPosition : COLOR0;
   float Punktgroesse  : PSIZE;
};

PixelVertex main(
   float4 VertexPosition : POSITION,
   float3 VertexNormale  : NORMAL,
   float2 VertexTex      : TEXCOORD0)
{
   PixelVertex Res;

   //transformiere Position in den Projektionsraum
   Res.Position = mul( matWeltKameraProjektion, VertexPosition );
   //berechne Zufalls- und Spekulartexturkoordinaten
   Res.BildPosition.x = ( Res.Position.x / Res.Position.w + 1) * 0.5;
   Res.BildPosition.y = (-Res.Position.y / Res.Position.w + 1) * 0.5;

   //transformiere Normale in Weltkoordinaten
   float3 Normale = normalize(mul(matWeltInvTrans,float4(VertexNormale.xyz,0.)).xyz);

   //Anisotropie/Bumpmap entfällt, da erst ab VS3.0 möglich

   //globale Beleuchtungsparameter
   float IntensitaetSpekular = 0;
   float3 WeltPosition = mul(matWelt,VertexPosition);
   //ermittle Sichtrichtung (Kamera->Vertex) in Weltkoordinaten
   float3 KameraVekt;
   if(LOCALVIEWER)
   {
      KameraVekt = normalize(WeltPosition - mul(matKameraInv,float4(0,0,0,1)).xyz);
   }
   else
   {
      KameraVekt = normalize(mul(matKameraInv,float4(0,0,1,0)).xyz);
   }
   float3 ReflektVekt = reflect(KameraVekt,Normale);

   for(int i=MinLichtNum; i<MaxLichtNum; i++)
   {
      //lokale Beleuchtungsparameter
      float3 LichtVekt;
      if(Licht[i].Typ==Richtungslicht)
      {
         LichtVekt = -normalize(Licht[i].Vektor.xyz);
      }
      else
      {
         LichtVekt = normalize((Licht[i].Vektor - WeltPosition).xyz);
      }
      float3 Spekularorientierung;
      float cos_Spekularwinkel;
      Spekularorientierung = normalize(-KameraVekt + LichtVekt);
      cos_Spekularwinkel = dot(Spekularorientierung,Normale);

      //berechne Beleuchtungsintensität nach Blinn-Phong
      IntensitaetSpekular+= pow(saturate(cos_Spekularwinkel),Spekularexponent);
   }

   Res.Punktgroesse = IntensitaetSpekular * Spritegroesse;

   return Res;
}

Pixelshader für Sterneffekte (zweiter Durchgang)

sampler SpekularTex;  //spekulare Textur mit Intensität in R, G und B dupliziert
sampler EffektSprite; //Textur mit Sterneffekt

float Spritehelligkeit; //Helligkeit des Effekts zur Kompensation von Mehrfachüberblendung
                        //und zu geringen spekularen Intensitäten

float4 main(float2 TexEffekt: TEXCOORD0, float4 TexPos: COLOR0) : COLOR0
{
  return Spritehelligkeit * tex2D(EffektSprite,TexEffekt) * tex2D(SpekularTex,TexPos.xy);
}

Shader zur Erzeugung einer vorberechneten zylindrischen Environmentmap mit automatisch generierten Farben für Ober- und Unterseite

const float PI=3.14159265359;

sampler envmap;

float Horizontuebergang; //Abstand des Randübergangs von der Bildmitte
float Horizontverlauf;   //Verlauf des Übergangs
float xzuy;

#define Abtastpunkte 8 //Anzahl Abtastpunkte für Mittelung der Randfarbe

float4 Envmap_Halbzylinder_Randfarbe(float2 Texpos : TEXCOORD0 ) : COLOR
{
   //berechne halbzylindrisches Mapping
   float2 envmap_uv;
   float Texposz=sqrt(1 - Texpos.x * Texpos.x);
   envmap_uv.x = (atan2(Texpos.x,Texposz) / PI) + 0.5;
   envmap_uv.y = 0.5 * (1 + 0.5 * XzuY * Texpos.y / sqrt((1 - Texpos.y * Texpos.y)))

   //ermittle nächstliegenden Rand der Textur in y-Richtung
   float RandpositionY=0.5 + 0.5 * sign(Texposy);

   //Berechne passende Randfarbe als Mittelwert des vorhandenen Bildrandes
   float4 Randfarbe=0.;
   for(int i=0; i<Abtastpunkte; i++)
   {
     Randfarbe+= 1 / Abtastpunkte * tex2D(envmap,float2(i / Abtastpunkte,RandpositionY));
   }

   //Mischungsverhältnis Randfarbe zu Bildfarbe
   float Mischung=pow(saturate((abs(Texposy) - Horizontuebergang)
                               / (1 - Horizontuebergang)),Horizontverlauf);

   return lerp(tex2D(envmap,envmap_uv),Randfarbe,Mischung);
}

Shader zur Erzeugung einer vorberechneten zylindrischen Environmentmap mit Überblendung zu vorgegebenen Farben für Ober- und Unterseite

const float PI=3.14159265359;

sampler envmap;

float Horizontuebergang; //Abstand des Randübergangs von der Bildmitte
float Horizontverlauf;   //Verlauf des Übergangs
float xzuy;
float4 FarbeOben;
float4 FarbeUnten;

float4 Envmap_Halbzylinder_2xFarbe(float2 Texpos : TEXCOORD0 ) : COLOR
{
   //berechne halbzylindrisches Mapping
   float2 envmap_uv;
   float Texposz=sqrt(1 - Texpos.x * Texpos.x);
   envmap_uv.x = (atan2(Texpos.x,Texposz) / PI) + 0.5;
   envmap_uv.y = 0.5 * (1 + 0.5 * XzuY * Texpos.y / sqrt((1 - Texpos.y * Texpos.y)))

   //ermittle Farbe des nächstliegenden Rands der Textur in y-Richtung
   float Randposition=0.5 + 0.5 * sign(Texposy);
   float4 Randfarbe=lerp(FarbeOben,FarbeUnten,Randposition);

   //Mischungsverhältnis Randfarbe zu Bildfarbe
   float Mischung=pow(saturate((abs(Texposy) - Horizontuebergang)
                               / (1 - Horizontuebergang)),Horizontverlauf);

   return lerp(tex2D(envmap,envmap_uv),Randfarbe,Mischung);
}

Weitere Seiten:

(Auch als PDF-Version verfügbar)
Mail an den Autor: webmeister@deinmeister.de

Hauptseite Programmieren Win32Asm Downloads Software Hardware Cartoons+Co Texte Sitemap