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);
}