PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit eigenem Texturformat


Einfachkrank
2005-02-20, 19:04:23
Moin,

ich habe mir en simples Texturformat für meine selbstprogrammierten Spiele ausgedacht... Dabei werden einfach mehrere Texturen in einer neuen zusammengelegt. In einer dazugehörenden Textdatei stehen für mehrere Texturestücke dann die dazugehören Koordinaten.

Hier, ein Texturbeispiel:
http://www.michael-eberhardt.de/Files/tex_example.jpg

Hier, ein Texturkoordinaten Beispiel:

s1 0, t1 0, s2 256, t2 256
s1 256, t1 0, s2 512, t2 256
// ...


Jetzt werden die reinen Bilddaten zusammen mit den wichtigesten Information und den Texturkoordinaten in ein neues Dateiformat geschrieben. Hier Code für die Convertier Funktion und den wichtigsten Datenstrukturen:

// CM3DTexture Klasse
class _MDLL CM3DTexture
{
public:
CM3DTexture(void);
~CM3DTexture(void);

bool loadBMP (char *filename);
bool loadTGA (char *filename);
bool loadJPG (char *filename);
bool destroy (void);
bool create (void);

unsigned char *data;
unsigned int object;
int sizex, sizey, channels;
char type;

protected:
bool _memalloc, _used;

void decodeJPG (jpeg_decompress_struct* cinfo, tImageJPG *pImageData);
};

// die Convertierungsfunktion
_MDLL bool convertTextureObject(CM3DTexture texture, char *infoFile, char *outputFile)
{
FILE *info, *output;
int numTiles, sbuf[2], tbuf[2], id, tsize;
float (*s)[2], (*t)[2];

info = fopen(infoFile, "r");
if(!info) return false;

output = fopen(outputFile, "wb");
if(!output) return false;


fscanf(info, "num_tiles %d\n", &numTiles);

s = new float[numTiles][2];
t = new float[numTiles][2];


for(int i=0; i < numTiles; i++)
{
fscanf(info, "s1 %d, t1 %d, s2 %d, t2 %d\n", &sbuf[0], &tbuf[0], &sbuf[1], &tbuf[1]);

s[i][0] = (float)sbuf[0] / (float)texture.sizex;
s[i][1] = (float)sbuf[1] / (float)texture.sizex;
t[i][0] = (float)tbuf[0] / (float)texture.sizey;
t[i][1] = (float)tbuf[1] / (float)texture.sizey;
}

fclose(info);


id = M3D_TILETEX_ID;
switch(texture.type)
{
case M3D_JPG:
tsize = texture.channels * texture.sizey;
break;
case M3D_BMP:
tsize = texture.sizex * texture.sizey * texture.channels;
break;
case M3D_TGA:
case M3D_TGA_A:
tsize = texture.sizex * texture.sizey * texture.channels;
break;
}

fwrite(&id, sizeof(int), 1, output);
fwrite(&numTiles, sizeof(int), 1, output);
fwrite(&tsize, sizeof(int), 1, output);
fwrite(&texture.sizex, sizeof(int), 1, output);
fwrite(&texture.sizey, sizeof(int), 1, output);

for(i = 0; i < numTiles; i++)
{
fwrite(s[i], sizeof(int), 2, output);
fwrite(t[i], sizeof(int), 2, output);
}

fwrite(texture.data, sizeof(unsigned char), tsize, output);

fflush(output);
fclose(output);

return true;
}


Beim Laden und rendern entsteht nun folgener Fehler:
http://www.michael-eberhardt.de/Files/tex_prob.jpg

Habt ihr ne Idee oder Vorschläge?

MFG Einfachkrank

ScottManDeath
2005-02-20, 19:45:52
Das liegt wohl daran dass beim Mipmap filtern Texel aus verschiedenen "Subtexturen" verwendet werden. Insbesondere bei Anisotroper Filterung gibt das dann diese Effekte.

Von NVIDIA gibts auch ein Tool für das sogennannte Texture Atlasing

http://developer.nvidia.com/object/nv_texture_tools.html

und ein Whitepaper, das stehen auch Details zu den Mipmaps drinne.
http://download.nvidia.com/developer/NVTextureSuite/Atlas_Tools/Texture_Atlas_Whitepaper.pdf

Einfachkrank
2005-02-22, 14:07:53
Jo, mit antistrophischer Filterung hat es anscheinend was zu tun, denn ich habe mal aus Spaß an der Freud' den Filterwert bei meiner Radeon 9800Pro von 2x auf 16x gestellt und die Anwendung noch mal laufen lassen... Die Texturfehler wurden deutlich kleiner, aber sie waren nicht weg.

Ich programmiere mit Visual C++ 6.0 und OpenGL als Grafik API. Hier en Auszug aus der Funktion, die mir ne Textur erzeugt...

gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, sizex, sizey, GL_RGB,
GL_UNSIGNED_BYTE, data);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR_MIPMAP_LINEAR);

Asmodeus
2005-02-22, 17:03:14
Ganz vermeiden lässt sich dieser unerwünschte Effekt meiner Meinung nach nur, wenn Du von Deinen einzelnen Ausgangstexturen die Mipmaps seperat erzeugst, und diese auch wieder in größeren Texturen auf die gleiche Art zusammenfasst wie in Deiner jetzigen "Container-Textur".

EDIT:

Außerdem würd ich Dir empfehlen, beim Texturparameter für die "Minification" GL_LINEAR_MIPMAP_LINEAR anstatt GL_LINEAR_MIPMAP_NEAREST zu verwenden. Und bei der "Magnification" reicht GL_LINEAR, da die kleinste, verfügbare Mipmapstufe ja die 0 ist.

Gruss, Carsten.

Einfachkrank
2005-02-22, 21:17:15
@Asmodeus
Also, die Texturen lege ich in nem Bildbearbeitungsprogramm schon zusammen und konvertiere dann das Bild in mein Format. Meinst du, dass ich die Daten in einzelne Bilder zerlegen soll, also im Programm während der Laufzeit?

micki
2005-02-23, 00:07:52
ich denke, falls deine texturen so sind wie im beispiel, dass ein problem darin besteht, dass du 3 texturen nebeneinander hast, würden das 2 oder 4 sein, wäre viel weniger texturebleeding vorhanden, weil dann beim verkleinern der texturen zu mipmaps immernoch die selben texturen einer page zu einem mipmappixel zusammengefasst würden, bis du ca auf level 1 oder 2 bist.

du kannst das auch ein wenig verbessern, indem du die uv-sets einen halben pixel nach innen zur textur verschiebst (also für jede textur der texturepage).

MfG
micki

Asmodeus
2005-02-23, 07:40:47
@Asmodeus
Also, die Texturen lege ich in nem Bildbearbeitungsprogramm schon zusammen und konvertiere dann das Bild in mein Format. Meinst du, dass ich die Daten in einzelne Bilder zerlegen soll, also im Programm während der Laufzeit?

Nein, nicht ganz. Bis jetzt nimmst Du die Einzeltexturen packst sie in eine "Container-Textur" und erzeugst Dir dann von dieser Container-Textur die Mipmap Stufen. Dadurch entstehen dann diese Randfehler. Also nimm die Einzeltexturen packe sie in eine Container-Textur und nimm das nur als Textur für Mipmap Stufe 0. Dann erzeugst Du für jede Einzeltextur die Mipmap Stufe 1 und packst diese alle wieder in der selben Anordnung in eine weitere Container-Textur, das ist dann die Container-Textur für Mipmap Stufe 1 usw.
Aber versuche auf jeden Fall erstmal die Vorschläge von micki umzusetzen, das dürfte wohl schon mit weniger Aufwand zu sehr guten Ergebnissen führen.

Gruss, Carsten.

zeckensack
2005-02-26, 00:44:26
Ich würde dieses Zusammenpacken der Texturen einfach komplett sein lassen.

Wenn's dir das Dateimanagement vereinfacht, dann kannst du das ja beibehalten, und dann beim Laden auseinanderdröseln. Die Bilddaten in einem GL-Texturobjekt sollten jedoch wirklich nur eine Textur enthalten. Es gibt sonst einfach viel zu viele Probleme. Und irgendwelche Vorteile, um die ganzen Probleme aufzuwiegen, wird dir diese Technik kaum bringen. In dem kleinen Maßstab garantiert keine.

Und selbst wenn du irgendwann soviele Texturwechsel vermeiden kannst, dass du sagen wir mal 30% Performance gewinnst, wär's mir das trotzdem nicht wert um auf sauberes Mipmapping, Repeat-Modi und AF zu verzichten. IMO alles Quatsch und kontraproduktiv.

Einfachkrank
2005-02-27, 13:47:00
Die Leistung war auch der einzige Hintergrund bei der Sache und ich musste feststellen dass es schon ganz schön was bringt...

Aber das Spiel ist so oder so mein erstes 3D Game und stellt daher nichts Perfektes dar.

Chris Lux
2005-02-27, 14:25:14
mal ne frage dazu. atlas-texturen (ähnlich wie hier) werden doch auch bei hl2 eingesetzt und ich kann mich erinnern, dass gegen diese hier aufgetretenen artefekte das so genannte centriod sampling (http://www.3dcenter.de/artikel/2003/08-06_a.php) eingesetzt wurde. wie kann man das unter opengl überhaupt nutzen? dies würde ja einfachkranks probleme lösen... IMO müssten aber auf jeden fall immer power of 2 texturen nebeneinander/untereinander in der atlasmap sein, damit das mipmapping weiterhin funktioniert...

Kant
2005-02-27, 14:52:01
mal ne frage dazu. atlas-texturen (ähnlich wie hier) werden doch auch bei hl2 eingesetzt und ich kann mich erinnern, dass gegen diese hier aufgetretenen artefekte das so genannte centriod sampling (http://www.3dcenter.de/artikel/2003/08-06_a.php) eingesetzt wurde. wie kann man das unter opengl überhaupt nutzen? dies würde ja einfachkranks probleme lösen... IMO müssten aber auf jeden fall immer power of 2 texturen nebeneinander/untereinander in der atlasmap sein, damit das mipmapping weiterhin funktioniert...

Nein, das Centroid-Sampling bezieht sich nur auf Probleme beim Antialiasing. Einfachkranks Probleme kommen aber schon beim normalen Texturieren (wenn MipMaps verwendet werden) zum Tragen.

Wenn er Mickis Ratschläge befolgt, dürfte er die Artefakte aber weitestgehend eliminieren können... und dann kann er sich mit den Anti-Aliasing Artefakten beschäftigen ;)

Einfachkrank
2005-02-27, 16:24:54
Problem ist schon gelöst ;) -> Great Thanks!!!

http://www.michael-eberhardt.de/Files/tex_yes.jpg

Chris Lux
2005-02-28, 16:43:23
Nein, das Centroid-Sampling bezieht sich nur auf Probleme beim Antialiasing. Einfachkranks Probleme kommen aber schon beim normalen Texturieren (wenn MipMaps verwendet werden) zum Tragen.
IMO nicht nur bei AA, denn auch ohne AA kann sowas passieren (in den skizzen des artikels schön zu sehen), wenn in der mitte des pixels gesamplet wird können die texturkoordinaten auch schon einen tick im benachbarten image liegen (der selben atlas map), oder irre ich mich da? schlimmer kann es doch auch bei AF werden, unter flachen wineln, wenn ein pixel ein recht großes stück der textur überdeckt?

Kant
2005-02-28, 17:01:02
IMO nicht nur bei AA, denn auch ohne AA kann sowas passieren (in den skizzen des artikels schön zu sehen), wenn in der mitte des pixels gesamplet wird können die texturkoordinaten auch schon einen tick im benachbarten image liegen (der selben atlas map), oder irre ich mich da? schlimmer kann es doch auch bei AF werden, unter flachen wineln, wenn ein pixel ein recht großes stück der textur überdeckt?

Das Centroid-Sampling bezieht sich nur auf das Problem mit AA. Bei "normalem" Rendern ist die Position des Textur-Samples und der Geometrie ja identisch. (Beides in der Mitte). D.h. entweder liegt der Punkt im Polygon, dann stimmt die Textur-Koordinate, oder eben nicht: dann wird der Pixel verworfen.

Aber ansonsten hast du Recht. AF kann ein Problem werden, genauso wie sehr kleine Mip-Maps. Im Prinzip hat Zeckensack es schon gesagt: Die Probleme tauchen an allen Ecken und Enden auf. Einige kann man kaschieren, andere komplett beseitigen, aber einige bleiben auch.