David Super JLI'ler
Alter: 39 Anmeldedatum: 13.10.2005 Beiträge: 315
Medaillen: Keine
|
Verfasst am: 13.11.2005, 12:16 Titel: DDS File Format und S3TC |
|
|
Hi!
Ich will heute ein wenig über den S3 Texture Kompression (S3TC) Algorithmus erzählen. Außerdem gibts einen kurzen Überblick auf das DDS Dateiformat, welches DXTn (oder S3TC) als Kompressionsalgo unterstützt.
Das DDS Dateiformat
Bei DDS, oder auch Direct Draw Surfaces, handelt es sich um ein Dateiformat welches das Speichern von Texturen, Cubemaps und Volumetrischen Texturen plus der dazugehörigen Mipmaps erlaubt.
Der Grundlegende Aufbau einer DDS Datei
DDS Header
Hauptdatenblock
Angehängter Datenblock
DDS Header
CPP: | struct DDSHeader
{
DWORD Magic;
DWORD Size;
DWORD Flags;
DWORD Height;
DWORD Width;
DWORD PitchOrLinearSize;
DWORD Depth;
DWORD MipMapCount;
DWORD Reserved1[ 11 ];
struct
{
DWORD Size;
DWORD Flags;
DWORD FourCC;
DWORD RGBBitCount;
DWORD RBitMask;
DWORD GBitMask;
DWORD BBitMask;
DWORD RGBAlphaBitMask;
} ddfpPixelFormat;
struct
{
DWORD Caps1;
DWORD Caps2;
DWORD Reserved[ 2 ];
} ddsCaps;
DWORD Reserved2;
};
|
In den Kopfdaten stehen diverse Bildinformationen. Wie Breite, Höhe, Bittiefe, Kompression usw.
DWORD Magic;
Diese 4 Bytes geben dienen also Identifikation für DDS Dateien. Sinnigerweise ist dieser Wert festgelegt auf die Bytes 'D', 'D', 'S', ' '.
DWORD Size;
Dieser Wert enthält die Größe der gesammten Struktur. Er sollte also immer auf 124 gesetzt sein
DWORD Flags;
Hier können bestimmte Bits gesetzt sein um die angegebenen Werte zu Identifizieren. sollte hier Beispielsweise das Bit für DDS_WIDTH gesetzt sein, ist die Breite des Bildes angegeben. Allerdings gibt es eine Anzahl Bits welche immer gesetzt sein müssen, das sind: DDSD_CAPS, DDSD_PIXELFORMAT, DDSD_WIDTH, DDSD_HEIGHT.
DWORD Height;
Hier wird die Höhe der Haupttextur angegeben.
DWORD Width;
Hier wird die Breite der Haupttextur angegeben.
(Beide Angaben sind in Pixel. Die Dimensionen der MipMaps können berechnet werden, wenn man die Dimensionen des vorhergehenden MipMaps durch zwei teilt
DWORD PitchOrLinearSize;
Falls die Daten unkomprimiert vorliegen ist dies die Anzahl der Bytes pro Scanline. In diesem Fall sollte in den Flags DDS_PITCH gesetzt sein.
Falls die Bilddaten komprimiert sind, handelt es sich um die Anzahl der gesammten Bytes für die Bilddaten. Hier sollte DDS_LINEARSIZE gesetzt sein.
DWORD Depth;
Gibt die "Tiefe" für Volume Texturen an. Im dem Falle das es sich um eine Volume Textur handelt sollte DDS_DEPTH in den Flags gesetzt sein.
DWORD MipMapCount;
Dies gibt die Anzahl der Mipmaps an, welche in den "angehängten Datenblock" gespeichert wurden. Falls hier eine Angabe gemacht sein sollte, muss in den Flags das Bit für DDSD_MIPMAPCOUNT gesetzt sein.
DWORD Reserved1[ 11 ];
44 Bytes reserviert. Momentan noch ohne Funktion
ddfpPixelFormat.Size
Gibt die Größe der Struktur (ddfpPixelFormat) an. Hier sollte immer der Wert 32 stehen
ddfpPixelFormat.Flags
Wie in der Hauptstruktur werden auch hier diverse Flags gesetzt um mögliche Vorhandene Informationen zu identifizieren. Für unkomprimierte RGB Bilddaten sollte hier das Bit für DDPF_RGB gesetzt sein. Falls die Bilddaten Komprimiert sind ist hier DDPF_FOURCC gesetzt.
ddfpPixelFormat.RGBBitCount
Falls die Daten unkomprimiert sind, wird hier die Bittiefe derselben angegeben. Im normalfall 16, 24 oder 32.
ddfpPixelFormat.RBitMask
ddfpPixelFormat.GBitMask
ddfpPixelFormat.BBitMask
Dies gibt die Bitmasken für den Rot, Blau und Grünkanal an. Für 32 Bit Farbtiefe sind diese 0x00ff0000, 0x0000ff00, and 0x000000ff.
ddfpPixelFormat.RGBAlphaBitMask
Dies gibt die Bitmaske für den Alphakanal an. für 32 Bit Farbtiefe ist diese 0xff000000. Im Falle das hier eine Angabe steht sollte das Bit für DDPF_ALPHAPIXELS gesetzt sein.
ddsCaps.Caps1
Hier sollte immer das Flag DDSCAPS_TEXTURE gesetzt sein. Falls die Datei Mipmaps enthält ist hier zusätzlich DDSCAPS_MIPMAP gesetzt. Sollten irgendwelche Daten, auser einem einzelnen Surface, gespeichert sein, wird hier das Bit für DDSCAPS_COMPLEX gesetzt.
ddsCaps.Caps2
Falls es sich um eine Cubemap handelt, ist das Bit für DDSCAPS2_CUBEMAP gesetzt. Auserdem für jede Seite die entsprechenden Bits (DDSCAPS2_CUBEMAP_POSITIVEX, DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY, DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ).
Falls es sich um eine Volume Texture handelt ist hier DDSCAPS2_VOLUME gesetzt
ddsCaps.Reserved[ 2 ]
8 Byte bislang ungenutzer Platz
Reserved2
Ungenutzer Platz ohne momentane Funktion
Hauptdatenblock
Hier stehen die (komprimierten/unkomprimierten) Daten für das Hauptsurface
Angehängter Datenblock
Hier stehen die (komprimierten/unkomprimierten) Daten für die angehängten Surfaces
Flags
CPP: | #define DDSD_CAPS 0x00000001
#define DDSD_HEIGHT 0x00000002
#define DDSD_WIDTH 0x00000004
#define DDSD_PITCH 0x00000008
#define DDSD_PIXELFORMAT 0x00001000
#define DDSD_MIPMAPCOUNT 0x00020000
#define DDSD_LINEARSIZE 0x00080000
#define DDSD_DEPTH 0x00800000
#define DDPF_ALPHAPIXELS 0x00000001
#define DDPF_FOURCC 0x00000004
#define DDPF_RGB 0x00000040
#define DDSCAPS_COMPLEX 0x00000008
#define DDSCAPS_TEXTURE 0x00001000
#define DDSCAPS_MIPMAP 0x00400000
#define DDSCAPS2_CUBEMAP 0x00000200
#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
#define DDSCAPS2_VOLUME 0x00200000
|
Die Bedeutung der Flags ist jeweils in unter DDS Header zu finden.
Berechnen der gesammten Datengröße
Für unkomprimierte Bilddaten ist dies nicht weiter kompliziert. Der gesuchte Wert ist die Summe der einzelnen Größen für jedes Surface. Für ein Surface wird die Größe Breite*Höhe*Tiefe berechnet.
Für komprimierte Bilddaten sieht die Berchnung für ein einzelnes Surface etwas anderst aus. Hier wird die Breite mit ( Breite+3 ) >> 2 und die Höhe mit ( Höhe+3 ) >> 2 berechnet. Die Gesammtgröße ist dann dementsprechend:( ( Breite+3 ) >> 2 ) *( ( Höhe+2 ) >> 2 ).
S3TC
Die S3 Texture Kompression unterstützt verschiedene Kompressionsarten:
DXT1
DXT2
DXT3
DXT4
DXT5
DXT1
Dies ist die "kleinste" Variante. Hier werden 16 Pixel in 64 Bit Output gepresst. Dieser setzt sich zusammen aus zwei 16 Bit RGB565 Werten und einer 4x4 großen, 2 Bit, Lookuptabelle.
Sollte der erste Farbwert (C0) größer als der zweite Farbwert (C1) sein, werden die Farbwerte C2 und C3 folgendermasen berechnet:
Code: | C2 = ( 2*C0 + C1 ) / 3
C3 = ( C0 + 2*C1 ) / 3 |
Falls C0 kleiner oder gleich C1 sein sollte wird nur der Wert für C2 berechnet. C3 ist Transparent.
Code: | C2 = ( C0+C1 ) / 2
C3 = 0 |
Die Lookuptabelle enthält Werte zwischen 0 und 3 (2 Bit). Wobei 0 für den Farbwert 0 steht, 1 für den Farbwert 1 usw...
Was evtl noch wichtig ist zu wissen. Wie man aus 16 Bit RGB565 Werten ein 24 Bit R8G8B8 Wert bekommt.
Bei RGB565 werden die Farbwerte in 16 Bit gepackt. Wobei Rotkanal und Blaukanal jeweils 5 Bit belegen, der Grünkanal aber 6 Bits.
Im R8G8B8 Format belegt jeder Kanal 8 Bits:
Code: | RRRRRRRR GGGGGGGG BBBBBBBB |
Mit ein bisschen "Bitsumherschieben" kann man also ganz leicht den entsprechenden R8G8B8 Wert von einem RGB565 Wert berechnen.
CPP: | R = ( ( c1 >> 11 ) & 0x1f ) << 3;
G = ( ( c1 >> 5 ) & 0x3f ) << 2;
B = ( c1 & 0x1f ) << 3;
|
DXT2, DXT3
Bei DXT2/3 werden 16 Pixel in 128 Bits Output gespeichert. Dieser setzt sich zusammen aus einen 64 Bit Alphakanal und dem, von DXT1 bekannten, 64 Bit Farbblock. Bei DXT2 werden die Farbwerte mit den entsprechenden Alphawerten "Vormultipliziert".
DXT4,DXT5
Bei DXT4/5 werden 16 Pixel in 128 Bits Output gespeichert. Dieser setzt sich aus 64 Bit Alphakanal Daten (zwei 8 Bit Alphawerte (a0, a1) und eine 4x4 3 Bit Lookuptabelle) und dem aus DXT1 bekannten 64 Bit Farbblock zusammen.
Falls a0 größer als a1 ist, werden sechs weitere Alphawerte berechnet.
Code: | Ai = ( ( 8-i )*a0 + ( i-1 )*a1 + 3 ) / 7 |
Wobei i zwischen 2 und 7 liegt.
Falls a0 kleiner oder gleich a1 ist werden vier weitere Alphawerte berechnet.
Code: | Ai = ( ( 6-i )*a0 + ( i-1 )*a1 + 2 ) / 5 |
Wobei i zwischen 2 und 5 liegt. a6 ist in den Fall 0 und a7 ist 255.
Bei DXT4 werden die Farbwerte mit den entsprechenden Alphawerten vormultipliziert.
So, ich hoffe das einige nutzen aus dem Tutorial ziehen können, oder vielleicht sogar etwas neues dazugelernt haben.
grüße |
|