# LWJGL: Performance glBegin, drawList, ...



## Rubber (22. Okt 2013)

Hi,
ich wollte mal nachfragen, wie es am besten ist zu zeichnen.
Momentan nutze ich eigentlich immer 
	
	
	
	





```
glNewList(drawList, GL_COMPILE);
```
.
Habe aber jetzt das Problem, dass meine FPS mächtig in den Keller gehen.
(Was mich nur wundert, ist dass weder CPU noch GraKa eine auslastung von 20% erreichen, aber die FPS zt auf 35 sinken.)
Dabei werden gerade mal um die 200 Objekte gezeichnet.
Die Position der Objekte verändert sich eher selten.

Jetzt bin ich auf der suche, eine bessere Art zu finden, meine Objekte zu zeichnen.

Habt ihr da Tipps für mich?

Gruß


----------



## Rubber (22. Okt 2013)

Ich habe jetzt mal die Zeit gemessen, die das Programm braucht.
Das komische ist, dass bei glCallList folgendes Ergebnis raus kommt:



Spoiler



Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 10
Call List: 2 Time: 0
Call List: 2 Time: 10
Call List: 2 Time: 10
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 0
Call List: 2 Time: 20
Call List: 2 Time: 10
Call List: 2 Time: 0
Call List: 2 Time: 2
Call List: 2 Time: 1
Call List: 2 Time: 2
Call List: 2 Time: 0
Call List: 2 Time: 10
Call List: 2 Time: 0
Call List: 2 Time: 10
Call List: 2 Time: 0
Call List: 2 Time: 0

usw



Woran kann das liegen, dass die Zeit so sehr variiert?


----------



## Rubber (23. Okt 2013)

Hier übrigens meine draw Methode, falls es da noch was zu verbessern geben sollte:

```
glPushMatrix();

glTranslatef(position.x, position.y, position.z); 
glRotatef(rotation.x, 1, 0, 0);
glRotatef(rotation.y, 0, 1, 0);
glRotatef(rotation.z, 0, 0, 1);

glCallList(drawList);

glPopMatrix();
```

Ist es eigentlich Sinnvoller, eine Liste zu haben und die dann immer zu bewegen, oder lieber mehrere Listen und die nicht zu bewegen.


----------



## BuddaKaeks (28. Okt 2013)

Sind die angaben in sekunden oder mllisekunden?
wenns millisekunden sind braucht die methode in etwa immer gleich lang, das liegt dann an system.currenttimemillis, diese methode ist auf 20 millisekunden ungenau oder so.

was deine Frames in den keller treibt ist vermutlich nicht dein render teil, sondern deine sonstige logic etc.


----------



## Rubber (28. Okt 2013)

Hi,
die Zeit ist in ms.
(Danke für die Info mit der ungenauigkeit)

Hatte auch nen kleinen Fehler in der draw Methode.
(eine nicht vorhandene Liste aufgerufen)

Hm...
das komische ist halt, dass ich, als ich noch einfache Quader verwendete um die 400 FPS hatte und jetzt, wo ich nen Obj verwende eben die FPS so abgesunken sind.
Deshalb hätte ich auf die draw Sachen getippt, weil ich an der Logik nichts verändert habe.


----------



## Rubber (29. Okt 2013)

Hab nochmal genau geschaut.
Meine draw-Methode braucht insgesamt um die 200ms.
Der Rest liegt im bereich von unter 10ms.



Spoiler



Zeichnen gesamt: 220
Zeichnen gesamt: 143
Zeichnen gesamt: 194
Zeichnen gesamt: 137
Zeichnen gesamt: 168
Zeichnen gesamt: 148
Zeichnen gesamt: 150
Zeichnen gesamt: 234


----------



## BuddaKaeks (4. Nov 2013)

verwendest du glClear(); ?


----------



## Rubber (4. Nov 2013)

Jo,

```
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
```
immer zu beginn meines Draw-Vorganges


----------



## BuddaKaeks (4. Nov 2013)

gib mal ein KSKB


----------



## BuddaKaeks (4. Nov 2013)

und die methoe wo die diplaylist erstellt und kompiliert wird


----------



## Rubber (4. Nov 2013)

Ich werd mich heut abend mal dran machen.
Ist etwas aufwändiger, da die DisplayList aus einem .OBJ entsteht


----------



## Rubber (5. Nov 2013)

Erstmal ein Danke an dich.
bin gerade noch dran, aber mir ist aufgefallen, dass bei meiner DisplayListe wohl was schief läuft.
Mal sehn, wie es sich verhält, wenn ich den Fehler gefunden habe.


----------



## Rubber (11. Nov 2013)

Hi,
hier jetzt mein "K"SKB.
Hat leider etwas gedauert.
Und irgendwie hab ichs nicht kleiner als 5 Klassen bekommen.

Hab alle Texturen und Farbe entfernt.
Läuft trotzdem nur mit rund 80 - 100 fps.
(Auf meinem Notebook)
Und das scheint mir halt sehr wenig dafür, dass eig "nur" etwa 200 Objekte gezeichnet werden.

Durch das beheben mit den Texturekoordinaten Fehlern läuft das Programm jetzt auf meinem Desktop PC mit ~60fps und auf dem Notebook mit etwa 10.

Hier jetzt die Klassen, ich pack sie mal in Spoiler.


Spoiler: Root





```
package kskb;

import static org.lwjgl.opengl.GL11.GL_ALPHA_TEST;
import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST;
import static org.lwjgl.opengl.GL11.GL_LIGHT0;
import static org.lwjgl.opengl.GL11.GL_MODELVIEW;
import static org.lwjgl.opengl.GL11.GL_NO_ERROR;
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
import static org.lwjgl.opengl.GL11.GL_PROJECTION;
import static org.lwjgl.opengl.GL11.GL_PROJECTION_MATRIX;
import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.GL_VERTEX_ARRAY;
import static org.lwjgl.opengl.GL11.glBlendFunc;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glClearColor;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glEnableClientState;
import static org.lwjgl.opengl.GL11.glGetError;
import static org.lwjgl.opengl.GL11.glGetFloat;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
import static org.lwjgl.opengl.GL11.glLoadMatrix;
import static org.lwjgl.opengl.GL11.glMatrixMode;
import static org.lwjgl.opengl.GL11.glOrtho;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.gluErrorString;
import static org.lwjgl.util.glu.GLU.gluPerspective;

import java.nio.FloatBuffer;

import javax.swing.JOptionPane;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

public class Root {
	//Fensterinfos
	public static final int FENSTER_BREITE = 800;
	public static final int FENSTER_HOEHE = 600;
	public static final int FOV = 60;
	public static final float ZNEAR = 0.1f;
	public static final float ZFAR = 100;
	
	//für die FPS
    private static int fps;
    private static int drawingFps;
    private static long lastFPS;
    
    //elemente
    private static World world;
    
    //Matritzen
	private static FloatBuffer perspectiveProjectionMatrix = BufferUtils.createFloatBuffer(16);
	private static FloatBuffer orthographicProjectionMatrix = BufferUtils.createFloatBuffer(16);

	
    public static void main(String[] args) {	
        System.err.println("Starte Grafikinitialisierung");
		//Fenster initialisieren
		createWindow();
		
        //OpenGL initialisieren
        initGl();
        
        System.err.println("Starte Weltinitialisierung");
             
        //Gegenstände erstellen
        createWorld();

	    
		lastFPS = getTime();
        //Hauptschleife
        System.err.println("Starte Hauptschleife");
        while (!Display.isCloseRequested()) {       	
        	//objekte zeichnen
        	draw();
	
        	//FPS berechnen
        	updateFPS();
        	
        	//FPS in Fenstertitel anzeigen
        	Display.setTitle("FPS: " + drawingFps);
        	
            // Update the display
            Display.update();

//            Display.sync(75);

        }
        end(0);
	}
	
	private static void createWindow(){
		try {
            Display.setDisplayMode(new DisplayMode(FENSTER_BREITE, FENSTER_HOEHE));
            Display.setTitle("FPS: " + drawingFps);
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
            end(1);
        }
	}
	
	private static void createWorld() { //initialisiert die welt	
		world = new World();
	}
	
	public static void end(int c) {		
        // Dispose of the display
        Display.destroy();
        // Exit the JVM
        System.exit(c);
		
	}
	
	private static void draw(){ //zeichnet die Objekte
    	//Buffer löschen
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
    	//Matrix zurücksetzen und kamera positionieren
    	glLoadIdentity();
    	glRotatef(180, 0, 1, 0);
//    	glRotatef(10, 0, 0, 1);
    	glTranslatef(-15f, -10f, -25f);
        world.draw();  
    	
	}
	
    public static long getTime() { //gibt die aktuelle Zeit in ms zurück
        return (Sys.getTime() * 1000) / Sys.getTimerResolution();
    }
	
    private static void initGl() { //macht die Einstellungen für OpenGl    
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective((float) FOV, (float) FENSTER_BREITE / (float) FENSTER_HOEHE, ZNEAR, ZFAR);
        glMatrixMode(GL_MODELVIEW);

		glGetFloat(GL_PROJECTION_MATRIX, perspectiveProjectionMatrix);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0, Display.getWidth(), Display.getHeight(), 0, 1, -1);
		glGetFloat(GL_PROJECTION_MATRIX, orthographicProjectionMatrix);
		glLoadMatrix(perspectiveProjectionMatrix);
		glMatrixMode(GL_MODELVIEW);
		
         glEnable(GL_DEPTH_TEST);
        //für transparenz
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_ALPHA_TEST);
        //für Koordinaten
        glEnable(GL_TEXTURE_2D);
        //Licht
        glEnable(GL_LIGHT0);
        //Hintergrund hellblau färben
        glClearColor(0.15f, 0.15f, 1f, 0.0f);
        
        glEnableClientState(GL_VERTEX_ARRAY);
  	}

    private static void updateFPS() { //berechnet die FPS
        if (getTime() - lastFPS > 1000) {
            lastFPS += 1000;
            drawingFps = fps;
            fps = 0;
        }
        fps++;
        System.out.println(getTime());
    }
}
```






Spoiler: World





```
package kskb;

import static org.lwjgl.opengl.GL11.GL_COMPILE;
import static org.lwjgl.opengl.GL11.GL_CULL_FACE;
import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST;
import static org.lwjgl.opengl.GL11.GL_LIGHTING;
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glDisable;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glEndList;
import static org.lwjgl.opengl.GL11.glGenLists;
import static org.lwjgl.opengl.GL11.glNewList;
import static org.lwjgl.opengl.GL11.glNormal3d;
import static org.lwjgl.opengl.GL11.glTexCoord2d;
import static org.lwjgl.opengl.GL11.glVertex3d;

import java.util.LinkedList;

import org.lwjgl.util.vector.Vector3f;

public class World {	
	private static final int BAEUME = 200;
	
	private static LinkedList<Tree> tree = new LinkedList<Tree>();

	private static Ground ground;
	private static int treeDisplayList = newDisplayList(1);
	
	public World(){
		createGround();
		createSomeTree(BAEUME);
	}

	
	private static void createGround(){ //erstellt den boden  
		ground = new Ground();
		System.out.println("Ground created");
	}

	
	/**
	 * Erstellt einen neuen Baum
	 * @param position
	 * @return
	 */
	private static Tree createTree(Vector3f position){
		Tree t = new Tree();
		t.setPosition(position);
		return t;
	}

	
	/** erstellt mehrere Bäume */
	private static void createSomeTree(int anzahl){
		Tree t;
		boolean error = false;
		for(int i = 0; i < anzahl; i++){
			t = createTree(new Vector3f((int) myRandom(Ground.BODEN_MIN_X, Ground.BODEN_MAX_X), 0, (int) myRandom(Ground.BODEN_MIN_Z, Ground.BODEN_MAX_Z)));
			for(Tree e : tree){
				if(e.getPosition().equals(t.getPosition())){
					error = true;
					break;
				}
			}
			if(error == false){
				tree.add(t);
			}else{
				i--;
				error = false;
			}
		}
	}
	
	public void draw(){
		glEnable(GL_DEPTH_TEST);
		glEnable(GL_CULL_FACE);
		glEnable(GL_LIGHTING);
		
		//Boden malen
		ground.draw();
	    	
//		long lastStep = System.currentTimeMillis();
		//jeden Baum malen
		for(Tree t : tree){
			t.draw();
		}
//		System.out.println("Zeichnen: " + (System.currentTimeMillis() - lastStep) + " (" + ((System.currentTimeMillis() - lastStep) / BAEUME) + ")");

		glDisable(GL_LIGHTING);
		glDisable(GL_CULL_FACE);
//        glDisable(GL_DEPTH_TEST);
	}

	public static int getDisplayList(int id){
		switch(id){
		case 1: //Baum
			return treeDisplayList;
		}
		
		return 0;
	}
	
	public static double myRandom(double low, double high) {
		return Math.random() * (high - low) + low;
	}
	
	private static int newDisplayList(int object){
		int drawList = 0;
		switch(object){
		case 1: //Baum
			drawList = glGenLists(1);
	        glNewList(drawList, GL_COMPILE);
	        {		        	

                     //
                     // Inhalt der Liste kommt in nen neuen Beitrag
                     //

	        }
	        glEndList();
		}
		return drawList;	
	}

}
```






Spoiler: Entity





```
package kskb;

import static org.lwjgl.opengl.GL11.glCallList;
import static org.lwjgl.opengl.GL11.glPopMatrix;
import static org.lwjgl.opengl.GL11.glPushMatrix;
import static org.lwjgl.opengl.GL11.glRotatef;
import static org.lwjgl.opengl.GL11.glTranslatef;

import org.lwjgl.util.vector.Vector3f;

public abstract class Entity{

	protected Vector3f position = new Vector3f(0, 0, 0);
	protected Vector3f rotation = new Vector3f(0, 0, 0);

	protected int drawList;
	protected int texture;
	
	public void draw(){  
		glPushMatrix();

        glTranslatef(position.x, position.y, position.z); 
        glRotatef(rotation.x, 1, 0, 0);
        glRotatef(rotation.y, 0, 1, 0);
        glRotatef(rotation.z, 0, 0, 1);
        
        glCallList(drawList);

        glPopMatrix();
	}

	public Vector3f getPosition(){
		return position;
	}
	
	public void setPosition(Vector3f position){
		this.position = position;
	}
}
```






Spoiler: Ground





```
package kskb;

import static org.lwjgl.opengl.GL11.GL_COMPILE;
import static org.lwjgl.opengl.GL11.GL_QUADS;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glEndList;
import static org.lwjgl.opengl.GL11.glGenLists;
import static org.lwjgl.opengl.GL11.glNewList;
import static org.lwjgl.opengl.GL11.glNormal3f;
import static org.lwjgl.opengl.GL11.glTexCoord2f;
import static org.lwjgl.opengl.GL11.glVertex3f;

public class Ground extends Entity{
	public static final int BODEN_MIN_X = 0;
	public static final int BODEN_MAX_X = 200;
	public static final int BODEN_MIN_Z = 0;
	public static final int BODEN_MAX_Z = 200;
	
	public Ground(){
		setup();
	}
	
	private void setup(){
		drawList = glGenLists(1);
		
//		setTexture("ground.jpg");
		
        glNewList(drawList, GL_COMPILE);
        glBindTexture(GL_TEXTURE_2D, texture);
        
        glBegin(GL_QUADS);

        glNormal3f(0f, 1f, 0f);
        glTexCoord2f(0, 0);
        glVertex3f(BODEN_MIN_X, 0, BODEN_MIN_Z);
        
        glTexCoord2f(0, 1);
        glVertex3f(BODEN_MIN_X, 0, BODEN_MAX_Z);
        
        glTexCoord2f(1, 1);
        glVertex3f(BODEN_MAX_X, 0, BODEN_MAX_Z);
        
        glTexCoord2f(1, 0);
        glVertex3f(BODEN_MAX_X, 0, BODEN_MIN_Z);
        glEnd();
        glEndList();	
	}
}
```






Spoiler: Tree





```
package kskb;
public class Tree extends Entity{
	
	public Tree(){
		setup();
	}
	
	public Tree(int id){
		setup();
	}
	
	public void setup() {	
		//Objekt Koordinaten und Textur erstellen
		drawList = World.getDisplayList(1);
	}
}
```


----------



## Rubber (11. Nov 2013)

Und hier der Inhalt der Displaylist (Beitrag war zu groß)
Eigentlich lade ich sie aus einer .obj Datei.

[-.- immernoch zu groß]
Ich lad sie hoch.

DisplayList


----------



## BuddaKaeks (11. Nov 2013)

also, anstatt von

```
glBegin(GL_TRIANGLES);
dreieck1();
glEnd();
glBegin(GL_TRIANGLES);
dreieck2();
glEnd()
```

schreibst du


```
glBegin(GL_TRIANGLES);
dreieck1();
dreieck2();
glEnd()
```

Dann aufrufe mittels glBegin/glEnd sind sehr langasam, benutze ieer glDrawArrays() und die glVertex/normal/texcoordPointer() methoden


----------



## Rubber (11. Nov 2013)

Ok - klingt erstmal logisch ^^
Werd ich mal rein basteln und dann sollte ich ja langsam wiedre auf ne annehmbare FPS Zahl kommen ^^

Vielen Dank, für deine Unterstützung!
Gruß,
David


----------



## Rubber (12. Nov 2013)

Jetzt sinds etwa 100 FPS.
auf jedefall schonmal ein großer Erfolg, wenn ich bedenke, wie langsam es noch war, als ich den Thread hier eröffnete.
Aber irgendwie kommt es mir trotzdem komisch vor - weil 100 halt dafür, dass ich kaum was male recht viel ist.
Oder schätze ich das eifnach falsch ein?

Oder wird das nochmal deutlich mehr, wenn ich von dem glBegin/End komplett weg bin?


----------

