# LWJGL Texturen



## Sphinx2k (28. Jan 2012)

Hallo,
Ein Problem was mich gerade kirre macht sind Textren bei OpenGL. Ich hab ein Testprojekt mit LWJGL am laufen und nutze die SLICK-Util um PNG Dateien als Textur einzuladen. Hat auch funktioniert bis zu dem Moment wo ich mir im Programm eine zusätzliche Texture zur Laufzeit erstellt hatte. 
Fehlersuche ergab dann das irgendwie das Texture.bind() nicht richtig gearbeitet hat. 
Gut nach ewigem fummeln ohne Lösung dachte ich das ich einfach mal ein GL11.glBindTexture(GL_TEXTURE_2D, texture.getTextureID());
anstelle von texture.bind() einsetze. Und siehe da mein Programm hat wieder funktioniert. 

OK jetzt kam eine zweite Textur dazu und damit gibt es wieder Probleme das sie nicht auf dem zweiten Grafikobjekt angezeigt wird. Also hab ich beim testen mal das glBindTexture ausgeklammert...die Textur war immer noch auf dem ersten obwohl ich sie nirgendwo gebunden hab. 

Lange rede kurzer Sinn, irgendwie raffe ich das mit dem binden von Texturen nicht. Warum er die Textur nicht ändern wenn ich glBindTexture aufrufe ist mir einfach nicht ersichtlich. Eine Kontrolle der Textur ID ergibt das diese eine andere ist. Nur richtig gebunden wird offensichtlich nichts. Und ich verstehe absolut nicht warum. Kennt irgendjemand Probleme die in diesem Zusammenhang auftreten die man irgendwie umschiffen muss?

Ok ich hab es weiter eingegrenzt. Ich hatte das so verstanden das ein glBindTexture die alte gebundene(?) Textur durch die neue ersetzt. Offensichtlich Blendet er aber die Texturen bei mir ineinander oder so etwas in der Art. Wie säubere ich den meine Texturspeicher um eine neue Textur mit z.b. glTexCoord2f(x,y); auf ein Quadrat aufzubringen?


----------



## Guest2 (28. Jan 2012)

Moin,

ich bin kein Slick Nutzer und ohne konkreten Code zu sehen, lässt sich da eh nur schwer was zu sagen.

Allerdings hast Du es schon mal ohne Slick versucht? Auch wen man es selber macht, ist das laden und verwenden von Texturen nicht so schwer.

Beispiel:


```
public class Sample {

    private final List<TextureIO> textures = new ArrayList<TextureIO>();


    public Sample() throws IOException {

        textures.add(new TextureIO(getClass().getClassLoader().getResourceAsStream("1.png")));
        textures.add(new TextureIO(getClass().getClassLoader().getResourceAsStream("2.png")));

    }


    public void init() throws LWJGLException {

        Display.setDisplayMode(new DisplayMode(500, 500));
        Display.create(new PixelFormat());

        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glLoadIdentity();
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glLoadIdentity();

        GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE);

        for (final TextureIO texture : textures)
            texture.init();

    }


    public void display() {

        while (!Display.isCloseRequested()) {

            GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
            GL11.glLoadIdentity();

            textures.get(0).bind();

            GL11.glBegin(GL11.GL_TRIANGLES);

            GL11.glTexCoord2f(0.0f, 0.0f);
            GL11.glVertex3f(-1.0f, -1.0f, -0.5f);

            GL11.glTexCoord2f(1.0f, 0.0f);
            GL11.glVertex3f(-0.1f, -1.0f, -0.5f);

            GL11.glTexCoord2f(1.0f, 1.0f);
            GL11.glVertex3f(-0.1f, +1.0f, -0.5f);

            GL11.glEnd();


            textures.get(1).bind();

            GL11.glBegin(GL11.GL_TRIANGLES);

            GL11.glTexCoord2f(0.0f, 0.0f);
            GL11.glVertex3f(+0.1f, -1.0f, -0.5f);

            GL11.glTexCoord2f(1.0f, 0.0f);
            GL11.glVertex3f(+1.0f, -1.0f, -0.5f);

            GL11.glTexCoord2f(0.0f, 1.0f);
            GL11.glVertex3f(+0.1f, +1.0f, -0.5f);

            GL11.glEnd();


            Display.update();

        }

        Display.destroy();

    }


    public static void main(final String[] args) throws IOException, LWJGLException {

        final Sample sample = new Sample();
        sample.init();
        sample.display();

    }
}
```


```
public class TextureIO {

    private final IntBuffer texture;
    private final int       width;
    private final int       height;

    private int             id;


    public TextureIO(final InputStream inputStream) throws IOException {

        BufferedImage image = ImageIO.read(inputStream);

        width = image.getWidth();
        height = image.getHeight();

        final AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
        tx.translate(0, -height);

        final AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
        image = op.filter(image, null);

        final int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
        texture = BufferUtils.createIntBuffer(pixels.length);
        texture.put(pixels);
        texture.rewind();

    }


    public void init() {

        GL11.glEnable(GL11.GL_TEXTURE_2D);

        final IntBuffer buffer = BufferUtils.createIntBuffer(1);
        GL11.glGenTextures(buffer);
        id = buffer.get(0);

        GL11.glBindTexture(GL11.GL_TEXTURE_2D, id);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);

        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, texture);

        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);

    }


    public void bind() {

        GL11.glBindTexture(GL11.GL_TEXTURE_2D, id);

    }


    public void unbind() {

        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);

    }


}
```

Viele Grüße,
Fancy


----------



## Guest2 (28. Jan 2012)

Sphinx2k hat gesagt.:


> Ok ich hab es weiter eingegrenzt. Ich hatte das so verstanden das ein glBindTexture die alte gebundene(?) Textur durch die neue ersetzt. Offensichtlich Blendet er aber die Texturen bei mir ineinander oder so etwas in der Art. Wie säubere ich den meine Texturspeicher um eine neue Textur mit z.b. glTexCoord2f(x,y); auf ein Quadrat aufzubringen?



Da sind die beiden Kommandos [c]GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE);[/c] und [c]GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);[/c] relevant.

Viele Grüße,
Fancy


----------



## Sphinx2k (28. Jan 2012)

Das ist mein Zeichencode, am am liebsten möchte ich das egal was ich zeichne alles vorher auf 0 setzt was vom letzten Zeichnen übrig ist und da keine Leichen und verweise übrig bleiben. 
Aktuell eben beim ersten Objekt mit Textur 1 eben alles OK, beim zweiten Objekt ein mischmasch aus textur 1 und textur 2 hab ich das gefühl.


```
private void drawGraphic(){
	float zoom=UniverseSystem.zoom;
		
		GL11.glEnable(GL11.GL_TEXTURE_2D);  
	  //glEnable(GL_BLEND);  //Aktivieren damit wieder Transparente Bereiche da sind
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glColor4f(1.0f,1.0f,1.0f,1.0f); //line color

		
//		if (isSelected){
// TODO
//		}
		
		
		GL11.glBindTexture(GL_TEXTURE_2D, texture.getTextureID());
	
		
		//TODO Größen behandlung je nach Zoomstufe...noch überarbeiten.
		double drawWidth,drawHeight;
		if (zoom>1.3f){
			drawWidth=width*0.5*zoom;
			drawHeight=height*0.5*zoom;
		} else {
			drawWidth=width*zoom;
			drawHeight=height*zoom;
		}

		
		glBegin(GL_QUADS);
		glTexCoord2f(tx,ty);
		glVertex2i((int)(((x-UniverseSystem.viewportX)-(drawWidth/2))*zoom),(int)((y-UniverseSystem.viewportY-drawHeight/2)*zoom));
		glTexCoord2f(tx+twidth,0);
		glVertex2i((int)(((x-UniverseSystem.viewportX)+(drawWidth/2))*zoom), (int)((y-UniverseSystem.viewportY-drawHeight/2)*zoom));
		glTexCoord2f(tx+twidth,0.125f);
		glVertex2i((int)((x-UniverseSystem.viewportX+drawWidth/2)*zoom), (int)((y-UniverseSystem.viewportY+drawHeight/2)*zoom));
		glTexCoord2f(tx,0.125f);
		glVertex2i((int)((x-UniverseSystem.viewportX-drawWidth/2)*zoom), (int)((y-UniverseSystem.viewportY+drawHeight/2)*zoom));
		glEnd();
		
	
}
```


----------



## Sphinx2k (28. Jan 2012)

Also ich hab mir das selber Laden von einem PNG in der Tat noch nicht angeschaut. Für ein BMP war das recht simpel und meist war dabei ein Verweis das PNG recht kompliziert zu laden sein soll. Aber ich werde mir deinen Code mal anschauen. Bin eigentlich ein Fan davon so etwas selbst zu implementieren weshalb mir das natürlich gelegen kommt.

GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE); 
Wenn ich mir das in der OpenGL SDK Dokumentation anschaue bin ich schlicht und ergreifend überfordert. 

GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
Hatte ich auch schon gefunden. Wenn ich das richtig sehe setzt man damit die Texture auf die default Textur von OpenGL zurück. 

Irgendwie hat mir das ganze noch kein Licht aufgehen lassen wieso es bei mir absolut nicht will.


----------



## Sphinx2k (29. Jan 2012)

Ich hab jetzt einmal über den weg von Guest2 versucht. Jetzt steht die Textur auf dem Kopf. Ach dieses OpenGL ist einfach bis man den Grundüberblick hat sehr kompliziert. Wie löse ich das Problem?


----------



## Helgon (29. Jan 2012)

Vielleicht liegen die Texturkordinaten falsch? 
	
	
	
	





```
glTexCoord2f(tx,ty);
```


----------



## Guest2 (29. Jan 2012)

Grundsätzlich ist bei Java normalerweise die (0,0)-Bildecke oben links. In OpenGL ist die (0,0)-Bildecke jedoch normalerweise als unten links definiert. Der obrige Beispielcode berücksichtigt dies, in dem in der TextureIO in den Zeilen 17 - 21 das Bild in der horizontalen gekippt wird. Eigentlich sollte das so passen. Es kann jedoch 3 Gründe geben, warum das Bild bei Dir auf dem Kopf steht:

1.: In einigen Bildformaten ist der (0,0)-Eckpunkt selbst nicht eindeutig definiert, so das nicht klar ist ob gekippt werden muss. Bei der obrigen Kombination aus PNG, ImageIO und dem Beispielcode würde mich das aber etwas wundern. Könntest Du das Bild vielleicht mal online stellen? Dann könnte man sich das Mal ansehen.

2.: Irgendwo wurde möglicherweise die Texturmatrix verändert. Einige Texture-Utilklassen machen dies, anstatt das eigentliche Bild zu kippen. Ist bei Dir im Code vielleicht noch etwas, das Einfluss auf die Texturmatrix nimmt?

3.: Die Texturkoordinaten sind evtl. falsch. Grundsätzlich sollten die Vertices immer gegen den Uhrzeigersinn angeordnet sein. Dabei sollte die (0,0)-Texturkoordinate auf das Vertex unten links fallen.


Viele Grüße,
Fancy


----------



## Helgon (29. Jan 2012)

Ich missbrauch mal kurz den Thread und hake hier nach, weil ich so oft immer leicht unterschiedliche Sachen lese.



> 3.: Die Texturkoordinaten sind evtl. falsch. Grundsätzlich sollten die Vertices immer gegen den Uhrzeigersinn angeordnet sein. Dabei sollte die (0,0)-Texturkoordinate auf das Vertex unten links fallen.




Die Vertices sollen gegen der Uhrzeigernsinn laufen. Spielt es eine Rolle wo man anfängt das Polygon zu zeichnen? (Welche Ecke)

Ich bin mir ziemlich sicher öfter gesehen zu haben das (0|0) der Textur links oben war, kann das sein? (Also klar kann das sein, aber ist es so auch korrekt, oder kommt es dann später dadurch zu Fehlern?)

Grüße


----------



## Spacerat (29. Jan 2012)

Es kommt später zu Fehlern... spätestens, wenn man Backfaceculling aktiviert. Ohne BackfaceCulling haben alle Polygone zwei sichtbare Seiten, von denen eine logischerweise irgendwie immer korrekt (Spiegelbild der jeweils anderen Seite) aussieht. Erst wenn BackfaceCulling aktiviert wurde, erkennt man, welche Polygone korrekt gezeichnet wurden, nämlich genau dann, wenn sie ausschliesslich das erwartete Ergebnis zeigen, weil die 2. Seite ausgeblendet wurde.
[OT]OMG... ich und Erklärungen...:bahnhof:[/OT]


----------



## Sphinx2k (30. Jan 2012)

So nach fummeln und mehr und mehr Code verstehen hab ich es hin bekommen. 

Die Zeilen 

```
final AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
        tx.translate(0, -height);
 
        final AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
        image = op.filter(image, null);
```
erledigen wie beschrieben letztendlich die Spiegelung des Bildes. Ohne wird das PNG wie erstellt geladen. 
Es klappt jetzt auch mit mehreren Texturen wie es soll und ich hab ein Grundgerüst mit dem ich jetzt angefangen hab herum zuspielen um zu sehen welche Werte und Einstellungen was bewirken. 

Wenn neue Fragen sind melde ich mich wieder. Danke für die Hilfe.


----------



## Guest2 (30. Jan 2012)

@Helgon:
Wo Du mit dem Polygon anfängst, ist egal. Z.B. (rechts/oben), (links/oben), (links/unten) ist genauso gültig wie z.B. (links/unten), (rechts/oben), (links/oben).

In OpenGL ist die (0,0)-Ecke einer Textur immer unten links (es sei den die Texturmatrix wurde verändert)(Ausnahmen bilden wohl lediglich einige alte OpenGL ES Implementationen unter Android - es war ein Fehler und sollte inzwischen behoben sein.):



			
				http://www.opengl.org/archives/resources/features/KilgardTechniques/oglpitfall/ hat gesagt.:
			
		

> Given a sheet of paper, people write from the top of the page to the bottom. The origin for writing text is at the upper left-hand margin of the page (at least in European languages). However, if you were to ask any decent math student to plot a few points on an X-Y graph, the origin would certainly be at the lower left-hand corner of the graph. Most 2D rendering APIs mimic writers and use a 2D coordinate system where the origin is in the upper left-hand corner of the screen or window (at least by default). On the other hand, 3D rendering APIs adopt the mathematically minded convention and assume a lower left-hand origin for their 3D coordinate systems.
> 
> If you are used to 2D graphics APIs, this difference of origin location can trip you up. When you specify 2D coordinates in OpenGL, they are generally based on a lower left-hand coordinate system.




@Sphinx2k:
Kannst Du vielleicht mal eines Deiner PNGs online stellen? Wie geschrieben, mich wundert das Verhalten und ich würde das gerne mal nachvollziehen.

Viele Grüße,
Fancy


----------



## Sphinx2k (30. Jan 2012)

Hier bitte 
Bild


----------



## Guest2 (30. Jan 2012)

Danke. Allerdings wird dieses PNG bei mir mit dem obrigen Beispielcode (TextureIO) und der darin enthaltenen Spiegelung in der horizontalen korrekt eingelesen. Wenn Du bei Dir die Spiegelung rausnehmen musstest, damit das bei Dir stimmt, dann ist vermutlich bei Dir irgendwo etwas nicht ganz richtig. Vermutlich stört Dich dies im Moment nicht sonderlich (es funktioniert ja jetzt auch) allerdings solltest Du das im Hinterkopf behalten, falls später die Orientierung der Texturen mal "spinnt". (Es könnte sein, dass Du zurzeit einen "Fehler" mit einem anderen "Fehler" korrigierst)

Viele Grüße,
Fancy


----------



## Sphinx2k (31. Jan 2012)

Ok danke werde es auf jeden fall im Hinterkopf behalten sollte wieder irgendwas komisch sein mit den Texturen.


----------

