# Jogl:Textur auf GLUquadric wird vertikal spiegelverkehrt dargestellt



## decay (27. Aug 2010)

Guten Abend allerseits!

ich habe eine Klasse implementiert (JFrame), welche ein Rechteck und eine Kugel (mit Hilfe von GLUquadric) auf einem GLJPanel darstellt. Das Rechteck wird mit der Textur "stars.bmp" belegt, die Kugel mit der Textur "earth.bmp". Es soll also eine vereinfachte Erde vor einem Sternenhintergrund dargestellt werden. Nun besteht das Problem, dass die Textur der Erde an der vertikalen Achse gespiegelt wird. Afrika befindet sich also westlich von Südamerika (siehe Bild im Anhang).

Die Texturen werden ordnungsgemäß aus den Dateien geladen, die Hintergrundtextur wird richtig dargestellt.

Hier der Quellcode:


```
public class TexturesTestApp extends JFrame implements GLEventListener {

	private static final long serialVersionUID = 1L;
	
	private GLProfile _glProfile;
	private GLCapabilities _glCaps;
	private GLJPanel _panel = null;
	private TextureData _earthTextureData = null;
	private TextureData _backgroundTextureData = null;
	
	public TexturesTestApp()
	{
		super();
		this.setTitle("Texture Test");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this._glProfile = GLProfile.getDefault();
		this._glCaps = new GLCapabilities(this._glProfile);
		this._panel = new GLJPanel(this._glCaps);
		this._panel.addGLEventListener(this);
		this.setSize(600, 600);
		this.setLayout(new BorderLayout());
		this.getContentPane().add(this._panel, BorderLayout.CENTER);
		this.centerWindow();
	}
	
	public void centerWindow()
	{
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension frameSize = this.getSize();
		
		if (frameSize.width > screenSize.width)
			frameSize.width = screenSize.width;
		if (frameSize.height > screenSize.height)
			frameSize.height = screenSize.height;
		this.setLocation(
				(screenSize.width - frameSize.width) >> 1, 
				(screenSize.height - frameSize.height) >> 1
				);
	}
	
	public static void main(String[] args) 
	{
		SwingUtilities.invokeLater(
				new Runnable()
				{
					public void run()
					{
						TexturesTestApp app = new TexturesTestApp();
						app.setVisible(true);
					}
				}
				);
	}

	@Override
	public void display(GLAutoDrawable drawable) 
	{
		try
		{
			GL2 someGL2 = drawable.getGL().getGL2();
			GLU someGLU = GLU.createGLU(someGL2);
			someGL2.glClear(
					GL.GL_COLOR_BUFFER_BIT |
					GL.GL_DEPTH_BUFFER_BIT);
			
			someGL2.glTexEnvf(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_TEXTURE_ENV_MODE, GL2ES1.GL_DECAL);
			
			Texture texBackground = TextureIO.newTexture(this._backgroundTextureData);
			texBackground.enable();
			texBackground.bind();
			someGL2.glBegin(GL2.GL_QUADS);
			
				TextureCoords coords = texBackground.getImageTexCoords();
				someGL2.glTexCoord2f(coords.left(), coords.bottom());
				someGL2.glVertex3i(-15, -6, -12);
				someGL2.glTexCoord2f(coords.left(), coords.top());
				someGL2.glVertex3i(-15, 6, -12);
				someGL2.glTexCoord2f(coords.right(), coords.top());
				someGL2.glVertex3i(15, 6, -12);
				someGL2.glTexCoord2f(coords.right(), coords.bottom());
				someGL2.glVertex3i(15, -6, -12);
			
			someGL2.glEnd();
			texBackground.disable();
			
			Texture texEarth = TextureIO.newTexture(this._earthTextureData);
			someGL2.glPushMatrix();
			someGL2.glRotatef(90.0F, 1.0F, 0.0F, 0.0F);
			someGL2.glRotatef(180.0F, 0.0F, 0.0F, 1.0F);
			GLUquadric earth = someGLU.gluNewQuadric();
			texEarth.enable();
			texEarth.bind();
			someGLU.gluQuadricTexture(earth, true);
			someGLU.gluQuadricDrawStyle(earth, GLU.GLU_FILL); 
			someGLU.gluQuadricNormals(earth, GLU.GLU_SMOOTH);
			someGLU.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE);
	        someGLU.gluSphere(earth, 1.0, 100, 360);
	        someGLU.gluDeleteQuadric(earth);
	       	texEarth.disable();
			someGL2.glPopMatrix();
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}

	@Override
	public void dispose(GLAutoDrawable arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void init(GLAutoDrawable drawable) 
	{
		
		try
		{
			GL2 someGL2 = drawable.getGL().getGL2();
			GLU someGLU = GLU.createGLU(someGL2);
			
			InputStream stream = this.getClass().getResourceAsStream("earth.bmp");
			this._earthTextureData = TextureIO.newTextureData(stream, false, "bmp");
			stream = this.getClass().getResourceAsStream("stars.bmp");
			this._backgroundTextureData = TextureIO.newTextureData(stream, false, "bmp");
			
			someGL2.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
			someGL2.glLoadIdentity();
			someGL2.glClearColor(
					0.0F,
					0.0F,
					0.0F,
					1.0F);
			double aspect = 
				((Component) drawable).getWidth() /
				((Component) drawable).getHeight();
			someGLU.gluPerspective(60.0, aspect, 2.0, 40.0);
			
			someGL2.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
			someGL2.glLoadIdentity();
			someGLU.gluLookAt(
					0.0, 0.0, 10.0, 
					0.0, 0.0, 0.0, 
					0.0, 1.0, 0.0);
			float[] position = {-5.0F, 0.0F, 5.0F, 1.0F};
			float[] diffuse = { 0.5F, 0.5F, 0.5F, 1.0F};
			float[] ambient = { 0.001F, 0.001F, 0.001F, 1.0F};
			someGL2.glEnable(GLLightingFunc.GL_LIGHTING);
			someGL2.glEnable(GLLightingFunc.GL_LIGHT0);
			someGL2.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_POSITION, position, 0);
			someGL2.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_DIFFUSE, diffuse, 0);
			someGL2.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_AMBIENT, ambient, 0);
			someGL2.glEnable(GL2.GL_DEPTH_TEST);
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}

	}

	@Override
	public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3,
			int arg4) {
		// TODO Auto-generated method stub

	}
}
```

Verwendet wird JOGL Version 2.0 und Java 6 Update 21. Als IDE kommt Eclipse 3.5.1. zum Einsatz. 

Wenn ich folgende Zeile:


```
someGLU.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE);
```

wie folgt abändere


```
someGLU.gluQuadricOrientation(earth, GLU.GLU_INSIDE);
```

wird die Textur richtig dargestellt, allerdings muss die Erde dann um 270 Grad gedreht werden, da sie sonst auf dem Kopf stünde. Ich nehme aber mal an, dass dies nur eine "Quick and dirty"-Lösung darstellen kann, die Richtung der Normalen der Quadric nach innen zeigen zu lassen. Zumal in allen Code-Beispielen in der Literatur stehts der Parameter GLU_OUTSIDE verwendet wird. 

Muss man hierfür eine Änderung an der Texturmatrix vornehmen? (nach Umschalten auf glMatrixMode(GL.GL_TEXTURE); )

Vielen Dank bereits im Voraus!


----------



## Guest2 (28. Aug 2010)

Moin,



decay hat gesagt.:


> Muss man hierfür eine Änderung an der Texturmatrix vornehmen? (nach Umschalten auf glMatrixMode(GL.GL_TEXTURE); )



Genau richtig!

Das Problem ist, das in den meisten Bildformaten das 0/0 Pixel oben links ist. In den Texturen von OpenGL aber unten links. Bei Deinem Hintergrund fällt dies nicht auf, da Du die generierten Texturkoordinaten von TextureIO nutzt, dadurch wird die Textur in der horizontalen gekippt. 

Das glu* hält sich an den Koordinaten aber nicht auf, das erwartet das 0/0 unten links ist. Da die Textur aber in der horizontalen gekippt ist, wird aus süd/ost erstmal nord/ost und da Du die Erde um 180° drehst, wird daraus süd/west. Es sieht damit so aus als ob die Textur um die vertikale gespiegelt wäre, was sie aber nicht ist.

Du hast vom Prinzip zwei Möglichkeiten, entweder die Textur von Hand einzulesen und zu spiegeln oder die Textur über die Texturmatrix zu spiegeln.

Der weg über die Texturmatrix sähe dann so aus:
(Dein Beispiel nur aufgeräumt, da bei Dir auch noch einiges anderes nicht so sauber war. Z.B. erzeugst Du jedes Frame eine neue Textur, manches was in der init() steht gehört in die resize() und  centerWindow() ist nicht viel anders als ein frame.setLocationRelativeTo(null); )


```
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.InputStream;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
import javax.media.opengl.awt.GLJPanel;
import javax.media.opengl.fixedfunc.GLLightingFunc;
import javax.media.opengl.glu.GLU;
import javax.media.opengl.glu.GLUquadric;
import javax.swing.JFrame;

import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureCoords;
import com.jogamp.opengl.util.texture.TextureIO;


public class TexturesTestApp implements GLEventListener {

    private GL2           gl;
    private GLU           glu;

    private Texture       backgroundImage;
    private TextureCoords backgroundCoords;

    private Texture       earthImage;

    private float         r = 0;


    @Override
    public void init(final GLAutoDrawable drawable) {

        gl = drawable.getGL().getGL2();
        glu = new GLU();

        final float[] position = { -5.0f, 0.0f, 5.0f, 1.0f };
        final float[] diffuse = { 0.5f, 0.5f, 0.5f, 1.0f };
        final float[] ambient = { 0.001f, 0.001f, 0.001f, 1.0f };

        gl.glEnable(GLLightingFunc.GL_LIGHTING);
        gl.glEnable(GLLightingFunc.GL_LIGHT0);
        gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_POSITION, position, 0);
        gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_DIFFUSE, diffuse, 0);
        gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_AMBIENT, ambient, 0);

        gl.glEnable(GL.GL_DEPTH_TEST);


        try {

            final InputStream backgroundStream = getClass().getResourceAsStream("stars.bmp");
            backgroundImage = TextureIO.newTexture(backgroundStream, false, "bmp");
            backgroundCoords = backgroundImage.getImageTexCoords();
            backgroundStream.close();

            final InputStream earthStream = getClass().getResourceAsStream("earth.bmp");
            earthImage = TextureIO.newTexture(earthStream, false, "bmp");
            earthStream.close();

        } catch (final GLException e) {

            throw new RuntimeException(e);

        } catch (final IOException e) {

            throw new RuntimeException(e);

        }

        gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
        gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);

    }


    @Override
    public void display(final GLAutoDrawable drawable) {

        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        gl.glLoadIdentity();
        glu.gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

        // background
        backgroundImage.enable();
        backgroundImage.bind();
        gl.glBegin(GL2.GL_QUADS);
        gl.glTexCoord2f(backgroundCoords.left(), backgroundCoords.bottom());
        gl.glVertex3i(-15, -6, -12);
        gl.glTexCoord2f(backgroundCoords.left(), backgroundCoords.top());
        gl.glVertex3i(-15, 6, -12);
        gl.glTexCoord2f(backgroundCoords.right(), backgroundCoords.top());
        gl.glVertex3i(15, 6, -12);
        gl.glTexCoord2f(backgroundCoords.right(), backgroundCoords.bottom());
        gl.glVertex3i(15, -6, -12);
        gl.glEnd();
        backgroundImage.disable();

        // earth
        gl.glMatrixMode(GL2.GL_TEXTURE);
        gl.glPushMatrix();
        gl.glScalef(1f, -1f, 1f);
        gl.glMatrixMode(GL2.GL_MODELVIEW);

        gl.glPushMatrix();
        gl.glRotatef(r++, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f);
        final GLUquadric earth = glu.gluNewQuadric();
        earthImage.enable();
        earthImage.bind();
        glu.gluQuadricTexture(earth, true);
        glu.gluQuadricDrawStyle(earth, GLU.GLU_FILL);
        glu.gluQuadricNormals(earth, GLU.GLU_SMOOTH);
        glu.gluQuadricOrientation(earth, GLU.GLU_OUTSIDE);
        glu.gluSphere(earth, 1.0, 100, 360);
        glu.gluDeleteQuadric(earth);
        earthImage.disable();
        gl.glPopMatrix();

        gl.glMatrixMode(GL2.GL_TEXTURE);
        gl.glPopMatrix();
        gl.glMatrixMode(GL2.GL_MODELVIEW);

    }


    @Override
    public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, int height) {

        if (height <= 0)
            height = 1;

        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(60.0f, (float) width / (float) height, 2.0, 40.0);
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();

    }


    @Override
    public void dispose(final GLAutoDrawable arg0) {

    }


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

        final TexturesTestApp texturesTestApp = new TexturesTestApp();
        final JFrame frame = new JFrame();
        final GLJPanel canvas = new GLJPanel();
        final Animator animator = new Animator(canvas);

        canvas.addGLEventListener(texturesTestApp);
        frame.setTitle("Texture Test");
        frame.add(canvas);
        frame.setSize(600, 600);
        frame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(final WindowEvent e) {

                new Thread(new Runnable() {
                    public void run() {

                        animator.stop();
                        System.exit(0);

                    }

                }).start();
            }
        });

        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        animator.start();

    }

}
```

Gruß,
Fancy


----------



## decay (28. Aug 2010)

Hallo Fancy,

vielen Dank für Deine schnelle und kompetente Antwort!

vG
decay


----------

