# LWJGL - Texturen flackern



## Seikuassi (15. Dez 2014)

Hallo,

ich versuche momentan ein Voxel-Game zu erstellen. Dies funktioniert ganz gut. Es soll ähnlich wie Minecraft funktionieren.
Die Chunks werden durch ein 16x16x16 Byte-Array beschrieben (als Klasse definiert).
Blöcke zeichne ich mit GL_QUADS, bei denen die Texturkoordinaten gleich mit übergeben werden. Bei der Initialisierung von OpenGL (s.u.) werden die benötigten Texturen geladen und in der Methode drawBlock mit glBindTexture(GL_TEXTURE_2D,textureID[?]) verwendet.
Die Blöcke werden aneinander gerendert. Wird ein Block von 6 Blöcken umschlossen (es also unmöglich ist, den Block zu sehen), so soll er nicht gerendert werden (s. Funktion unten).

Problem:Beim Bewegen und Rotieren in der Welt, flackern alle Texturen. Aus einem Steinblock wird manchmal ein Erdblock und umgekehrt (s. Bilder weiter unten).
Aktuell habe ich als Test nur Erde und Stein als Textur mit eingebunden.

Frage: Wo ist das Problem bzw. was muss ich bei OpenGL konfigurieren, damit die Texturen richtig dargestellt werden?

Es gilt:
ID 0=Luft (nichts zeichnen)​ID 1=Erdblock​ID 2=Steinblock​
init-Methode, die OpenGL initialisiert:

```
public static void init()
throws FileNotFoundException,IOException{
	glEnable(GL_CULL_FACE); // Backface Culling aktivieren
	glEnable(GL_DEPTH_TEST); // Tiefenpuffer aktivieren
	glEnable(GL_NORMALIZE); // automatisches Normalisieren aktivieren
	glEnable(GL_TEXTURE_2D); // Texturenrendering aktivieren
	glClearColor(0.54f,0.89f,1f,1f); // Hintergrundfarbe (hellblau) festlegen
	{ // Nebel konfigurieren
		FloatBuffer buf=BufferUtils.createFloatBuffer(4);
		
		buf.put(new float[]{0.9f,0.9f,0.9f,1f}).flip();
		glFogi(GL_FOG_MODE,GL_LINEAR); // linearen Modus festlegen
		glFog(GL_FOG_COLOR,buf); // Farbe des Nebels festlegen
		glFogf(GL_FOG_START,1f); // Entfernung festlegen, in der Nebel sichtbar ist
		glFogf(GL_FOG_END,5f); // Entfernung festlegen, in der der Nebel und die Sichtweite zu Ende ist
		glHint(GL_FOG_HINT,GL_FASTEST); // Berechnung des Nebels auf Vertexbasis
		glEnable(GL_FOG); // Nebel aktivieren
	}
	{ // Texturen laden
		textureID[0]=loadTexture("/resources/textures/dirt.png");
		textureID[1]=loadTexture("/resources/textures/stone.png");
	}
	return;
}
```
loadTexture-Methode, die Texturen lädt und eine ID zuweist (vllt. liegt es an evtl. falsch eingestellten Mipmap-Werten?):

```
private static int loadTexture(String path)
throws FileNotFoundException,IOException{
	ByteBuffer buffer;
	BufferedImage img=classes.util.ResourceLoader.loadImage(path);
	int[]pixels=new int[img.getWidth()*img.getHeight()];
	int textureID;
	
	img.getRGB(0,0,img.getWidth(),img.getHeight(),pixels,0,img.getWidth());
	buffer=BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*4);
	for(int pixel=0,y=0;y<img.getHeight();y++){
		for(int x=0;x<img.getWidth();x++){
			pixel=pixels[y*img.getWidth()+x];
			buffer.put((byte)((pixel>>16)&0xFF));
			buffer.put((byte)((pixel>>8)&0xFF));
			buffer.put((byte)(pixel&0xFF));
			buffer.put((byte)((pixel>>24)&0xFF));
		}
	}
	buffer.flip();
	textureID=glGenTextures();
	glBindTexture(GL_TEXTURE_2D,textureID);
	{ // Textureeinstellungen vornehmen
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	}
	glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,img.getWidth(),img.getHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,buffer);
	glGenerateMipmap(GL_TEXTURE_2D);
	return textureID;
}
```
draw-Methode, die Blöcke in die Szene zeichnet:

```
public static void draw(float x,float y,float z,float roll,float yaw){
	glMatrixMode(GL_MODELVIEW); // Modell-Matrix aktivieren
	{
		glLoadIdentity(); // Standard-Matrix laden
		glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
		glRotatef(-roll,1f,0f,0f); // X-Achse rotieren
		glRotatef(yaw,0f,1f,0f); // Y-Achse rotieren
		glTranslatef(-x,-y,z); // Position festlegen
		for(int i=0;i<classes.Game.chunks.size();i++){ // alle Chunks zeichnen
			ChunkDrawer.drawChunk(classes.Game.chunks.get(i));
		}
	}
	return;
}
```
drawChunk-Methode, die einen Chunk in die Szene zeichnet:

```
public static void drawChunk(Chunk c){
	glPushMatrix(); // Matrix auf den Stack legen
	glTranslatef((float)c.getXPos()*Chunk.X_size*BlockSize,(float)c.getYPos()*Chunk.Y_size*BlockSize,(float)c.getZPos()*Chunk.Z_size*BlockSize); // Chunk-Position festlegen
	for(short x=0;x<Chunk.X_size;x++){
		if(x!=0){
			glTranslatef(BlockSize*2,0f,0f); // Position auf der X-Achse verschieben
		}
		for(short y=0;y<Chunk.Y_size;y++){
			if(y!=0){
				glTranslatef(0f,BlockSize*2,0f); // Position auf der Y-Achse verschieben
			}
			for(short z=0;z<Chunk.Z_size;z++){
				if(z!=0){
					glTranslatef(0f,0f,BlockSize*2); // Position auf Z-Achse verschieben
				}
				if(checkBlock(c,x,y,z)==true){ // wenn Block gezeichnet werden muss
					drawBlock(c.getBlock(x,y,z),c.getBlockData(x,y,z)); // Block zeichnen
				}
			}
			glTranslatef(0f,0f,(float)-(Chunk.Z_size-1)*BlockSize*2); // Position auf der Z-Achse zuruecksetzen
		}
		glTranslatef(0f,(float)-(Chunk.Y_size-1)*BlockSize*2,0f); // Position auf der Y-Achse zuruecksetzen
	}
	glPopMatrix(); // Matrix vom Stack nehmen
	return;
}
```
checkBlock-Methode, die überprüft, ob ein Block gezeichnet werden muss:

```
private static boolean checkBlock(Chunk c,int x,int y,int z){
	if(c.getBlock(x,y,z)==0){ // wenn der Block Luft ist
		return false;
	}else if(x>0&&x<Chunk.X_size-1&&y>0&&y<Chunk.Y_size-1&&z>0&&z<Chunk.Z_size-1){ // wenn sich Bloecke um den Block befinden koennten
		if(c.getBlock(x-1,y,z)==0&&c.getBlock(x,y-1,z)==0&&c.getBlock(x,y,z-1)==0&&c.getBlock(x+1,y,z)==0&&c.getBlock(x,y+1,z)==0&&c.getBlock(x,y,z+1)==0){
			return false;
		}
	}
	return true;
}
```
drawBlock, die einen Block in die Welt zeichnet (glBindTexture evtl. falsch?):

```
private static void drawBlock(byte ID,byte data){
	if(ID==1){ // wenn ein Erdblock gezeichnet werden soll
		glBindTexture(GL_TEXTURE_2D,OpenGL.textureID[0]);
	}else if(ID==2){ // wenn ein Steinblock gezeichnet werden soll
		glBindTexture(GL_TEXTURE_2D,OpenGL.textureID[1]);
	}
	glBegin(GL_QUADS);
	{ // Zeichnung starten
		glColor3f(1f,1f,1f); // Farbe (weiss) festlegen
		// vorne
		glNormal3f(0f,0f,BlockSize);
		glTexCoord2s((short)1,(short)1);
		glVertex3f(BlockSize,BlockSize,BlockSize);
		glTexCoord2s((short)0,(short)1);
		glVertex3f(-BlockSize,BlockSize,BlockSize);
		glTexCoord2s((short)0,(short)0);
		glVertex3f(-BlockSize,-BlockSize,BlockSize);
		glTexCoord2s((short)1,(short)0);
		glVertex3f(BlockSize,-BlockSize,BlockSize);
		// hinten
		glNormal3f(0f,0f,-BlockSize);
		glTexCoord2s((short)1,(short)1);
		glVertex3f(-BlockSize,BlockSize,-BlockSize);
		glTexCoord2s((short)0,(short)1);
		glVertex3f(BlockSize,BlockSize,-BlockSize);
		glTexCoord2s((short)0,(short)0);
		glVertex3f(BlockSize,-BlockSize,-BlockSize);
		glTexCoord2s((short)1,(short)0);
		glVertex3f(-BlockSize,-BlockSize,-BlockSize);
		// links
		glNormal3f(-BlockSize,0f,0f);
		glTexCoord2s((short)1,(short)1);
		glVertex3f(-BlockSize,BlockSize,BlockSize);
		glTexCoord2s((short)0,(short)1);
		glVertex3f(-BlockSize,BlockSize,-BlockSize);
		glTexCoord2s((short)0,(short)0);
		glVertex3f(-BlockSize,-BlockSize,-BlockSize);
		glTexCoord2s((short)1,(short)0);
		glVertex3f(-BlockSize,-BlockSize,BlockSize);
		// rechts
		glNormal3f(BlockSize,0f,0f);
		glTexCoord2s((short)1,(short)1);
		glVertex3f(BlockSize,BlockSize,-BlockSize);
		glTexCoord2s((short)0,(short)1);
		glVertex3f(BlockSize,BlockSize,BlockSize);
		glTexCoord2s((short)0,(short)0);
		glVertex3f(BlockSize,-BlockSize,BlockSize);
		glTexCoord2s((short)1,(short)0);
		glVertex3f(BlockSize,-BlockSize,-BlockSize);
		// oben
		glNormal3f(0f,BlockSize,0f);
		glTexCoord2s((short)1,(short)1);
		glVertex3f(BlockSize,BlockSize,-BlockSize);
		glTexCoord2s((short)0,(short)1);
		glVertex3f(-BlockSize,BlockSize,-BlockSize);
		glTexCoord2s((short)0,(short)0);
		glVertex3f(-BlockSize,BlockSize,BlockSize);
		glTexCoord2s((short)1,(short)0);
		glVertex3f(BlockSize,BlockSize,BlockSize);
		// unten
		glNormal3f(0f,-BlockSize,0f);
		glTexCoord2s((short)1,(short)1);
		glVertex3f(BlockSize,-BlockSize,BlockSize);
		glTexCoord2s((short)0,(short)1);
		glVertex3f(-BlockSize,-BlockSize,BlockSize);
		glTexCoord2s((short)0,(short)0);
		glVertex3f(-BlockSize,-BlockSize,-BlockSize);
		glTexCoord2s((short)1,(short)0);
		glVertex3f(BlockSize,-BlockSize,-BlockSize);
	}
	glEnd();
	return;
}
```
Zwei Bilder noch: Das zweite Bild ist leicht nach links rotiert (man sieht, dass die Erdtexturen durch Steintexturen ersetzt wurden (es flackert)).



Danke im Voraus!

Mit freundlichen Grüßen
Seikuassi


----------



## Seikuassi (22. Dez 2014)

Hallo nochmal,

Problem gelöst . Die Chunks waren zu eng aneinander positioniert, sodass die Grafikkarte manchmal die eine Textur und manchmal die andere gerendert hat.
Jetzt flackert nichts mehr.


----------



## Seikuassi (22. Dez 2014)

Ich benutze jetzt übrigens auch VBO's, da ja glBegin() etc. nicht mehr aktuell sind.

Wen's interessiert...hier ist der init()-Code für OpenGL (hier werden weiter unten auch die VBO's initialisiert):

```
public static void init()
throws FileNotFoundException,IOException{
	glAlphaFunc(GL_GREATER,0f);
	glEnable(GL_ALPHA_TEST); // Alpha-Test aktivieren
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND); // Blending aktivieren
	glEnable(GL_CULL_FACE); // Backface Culling aktivieren
	glEnable(GL_DEPTH_TEST); // Tiefenpuffer aktivieren
	glEnable(GL_TEXTURE_2D); // 2D-Texturen aktivieren
	glEnable(GL_VERTEX_ARRAY); // Vertex-Arrays (VBOs) verwenden
	glClearColor(0.54f,0.89f,1f,1f); // Hintergrundfarbe (hellblau) festlegen
	{ // Nebel konfigurieren
		FloatBuffer buf=BufferUtils.createFloatBuffer(4);
		
		buf.put(new float[]{0.9f,0.9f,0.9f,1f}).flip();
		glFogi(GL_FOG_MODE,GL_LINEAR); // linearen Modus festlegen
		glFog(GL_FOG_COLOR,buf); // Farbe des Nebels festlegen
		glFogf(GL_FOG_START,1f); // Entfernung festlegen, in der Nebel sichtbar ist
		glFogf(GL_FOG_END,(float)visibility/10f); // Entfernung festlegen, in der der Nebel und die Sichtweite zu Ende ist
		glHint(GL_FOG_HINT,GL_FASTEST); // Berechnung des Nebels auf Vertexbasis
		glEnable(GL_FOG); // Nebel aktivieren
	}
	{ // Texturen laden
		textureID[0]=loadTexture("/resources/textures/dirt.png");
		textureID[1]=loadTexture("/resources/textures/stone.png");
		textureID[2]=loadTexture("/resources/textures/glass.png");
		textureID[3]=loadTexture("/resources/textures/bedrock.png");
		textureID[4]=loadTexture("/resources/textures/brick.png");
		textureID[5]=loadTexture("/resources/textures/clay.png");
		textureID[6]=loadTexture("/resources/textures/cobblestone.png");
		textureID[7]=loadTexture("/resources/textures/gravel.png");
		textureID[8]=loadTexture("/resources/textures/obsidian.png");
		textureID[9]=loadTexture("/resources/textures/sand.png");
	}
	{ // VBO's initialisieren
		ShortBuffer SbufferNormal;
		ShortBuffer SbufferTexCoord;
		FloatBuffer FbufferVertex;
		
		{ // Block
			final short[]normals={
				// vorne
				(short)0,(short)0,(short)1,
				// hinten
				(short)0,(short)0,(short)-1,
				// links
				(short)-1,(short)0,(short)0,
				// rechts
				(short)1,(short)0,(short)0,
				// oben
				(short)0,(short)1,(short)0,
				// unten
				(short)0,(short)-1,(short)0
			};
			final short[]texCoords={
				// vorne
				(short)0,(short)0,
				(short)0,(short)1,
				(short)1,(short)1,
				(short)1,(short)0,
				// hinten
				(short)0,(short)0,
				(short)0,(short)1,
				(short)1,(short)1,
				(short)1,(short)0,
				// links
				(short)0,(short)0,
				(short)0,(short)1,
				(short)1,(short)1,
				(short)1,(short)0,
				// rechts
				(short)0,(short)0,
				(short)0,(short)1,
				(short)1,(short)1,
				(short)1,(short)0,
				// oben
				(short)0,(short)0,
				(short)0,(short)1,
				(short)1,(short)1,
				(short)1,(short)0,
				// unten
				(short)0,(short)0,
				(short)0,(short)1,
				(short)1,(short)1,
				(short)1,(short)0,
			};
			final float[]vertices={
				// vorne
				-BlockSize,-BlockSize,BlockSize,
				BlockSize,-BlockSize,BlockSize,
				BlockSize,BlockSize,BlockSize,
				-BlockSize,BlockSize,BlockSize,
				// hinten
				BlockSize,-BlockSize,-BlockSize,
				-BlockSize,-BlockSize,-BlockSize,
				-BlockSize,BlockSize,-BlockSize,
				BlockSize,BlockSize,-BlockSize,
				// links
				-BlockSize,-BlockSize,-BlockSize,
				-BlockSize,-BlockSize,BlockSize,
				-BlockSize,BlockSize,BlockSize,
				-BlockSize,BlockSize,-BlockSize,
				// rechts
				BlockSize,-BlockSize,BlockSize,
				BlockSize,-BlockSize,-BlockSize,
				BlockSize,BlockSize,-BlockSize,
				BlockSize,BlockSize,BlockSize,
				// oben
				-BlockSize,BlockSize,BlockSize,
				BlockSize,BlockSize,BlockSize,
				BlockSize,BlockSize,-BlockSize,
				-BlockSize,BlockSize,-BlockSize,
				// unten
				-BlockSize,-BlockSize,-BlockSize,
				BlockSize,-BlockSize,-BlockSize,
				BlockSize,-BlockSize,BlockSize,
				-BlockSize,-BlockSize,BlockSize
			};
			
			VBO.NormalCount[0]=3; // Anzahl Normalkoordinaten pro Flaeche
			VBO.TexCount[0]=2; // Anzahl Koordinaten pro Texturvertex
			VBO.VertexCount[0]=3; // Anzahl Koordinaten pro Vertex
			{ // Puffer erstellen und initialisieren
				SbufferNormal=BufferUtils.createShortBuffer(normals.length);
				SbufferTexCoord=BufferUtils.createShortBuffer(texCoords.length);
				FbufferVertex=BufferUtils.createFloatBuffer(vertices.length);
				SbufferNormal.put(normals).flip(); // Normalen in Puffer kopieren
				SbufferTexCoord.put(texCoords).flip(); // Texturdaten in Puffer kopieren
				FbufferVertex.put(vertices).flip(); // Vertices in Puffer kopieren
				VBO.NormalSize[0]=normals.length;
				VBO.TexSize[0]=texCoords.length;
				VBO.VertexSize[0]=vertices.length;
			}
			{ // Normalen-Grafik-Puffer erzeugen
				VBO.NormalID[0]=glGenBuffers(); // Normalenpuffer auf Grafikkarte allokieren
				glBindBuffer(GL_ARRAY_BUFFER,VBO.NormalID[0]); // Normalenpuffer binden
				glBufferData(GL_ARRAY_BUFFER,SbufferNormal,GL_STATIC_DRAW); // Normalendaten in Puffer schreiben
				glBindBuffer(GL_ARRAY_BUFFER,0); // keinen Puffer binden
			}
			{ // Texture-Grafik-Puffer erzeugen
				VBO.TexID[0]=glGenBuffers(); // Texturpuffer auf Grafikkarte allokieren
				glBindBuffer(GL_ARRAY_BUFFER,VBO.TexID[0]); // Texturpuffer binden
				glBufferData(GL_ARRAY_BUFFER,SbufferTexCoord,GL_STATIC_DRAW); // Texturdaten in Puffer schreiben
				glBindBuffer(GL_ARRAY_BUFFER,0); // keinen Puffer binden
			}
			{ // Vertex-Grafik-Puffer erzeugen
				VBO.VertexID[0]=glGenBuffers(); // Vertexpuffer auf Grafikkarte allokieren
				glBindBuffer(GL_ARRAY_BUFFER,VBO.VertexID[0]); // Vertexpuffer binden
				glBufferData(GL_ARRAY_BUFFER,FbufferVertex,GL_STATIC_DRAW); // Vertexdaten in Puffer schreiben
				glBindBuffer(GL_ARRAY_BUFFER,0); // kein Puffer binden
			}
		}
	}
	return;
}
```
Die VBO-Klasse, in denen alle VBO's gespeichert sind:

```
class VBO{
	protected static int[]NormalCount=new int[2];
	protected static int[]NormalID=new int[2];
	protected static int[]NormalSize=new int[2];
	protected static int[]TexCount=new int[2];
	protected static int[]TexID=new int[2];
	protected static int[]TexSize=new int[2];
	protected static int[]VertexCount=new int[2];
	protected static int[]VertexID=new int[2];
	protected static int[]VertexSize=new int[2];
}
```
loadTexture()-Methode:

```
private static int loadTexture(String path)
throws FileNotFoundException,IOException{
	ByteBuffer buffer;
	BufferedImage img=classes.util.ResourceLoader.loadImage(path);
	int[]pixels=new int[img.getWidth()*img.getHeight()];
	int textureID;
	
	img.getRGB(0,0,img.getWidth(),img.getHeight(),pixels,0,img.getWidth()); // Pixeldaten vom Bild laden
	buffer=BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*4);
	for(int pixel=0,y=0;y<img.getHeight();y++){ // Pixel in Puffer laden
		for(int x=0;x<img.getWidth();x++){
			pixel=pixels[y*img.getWidth()+x];
			buffer.put((byte)((pixel>>16)&0xFF));
			buffer.put((byte)((pixel>>8)&0xFF));
			buffer.put((byte)(pixel&0xFF));
			buffer.put((byte)((pixel>>24)&0xFF));
		}
	}
	buffer.flip();
	textureID=glGenTextures(); // neues Texturenobjekt auf der Grafikkarte allokieren
	glBindTexture(GL_TEXTURE_2D,textureID); // Textur binden
	{ // Textureeinstellungen vornehmen
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	}
	glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,img.getWidth(),img.getHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,buffer); // Bild in Puffer auf Grafikkarte kopieren
	glBindTexture(GL_TEXTURE_2D,0); // keine Textur binden
	return textureID;
}
```
Die setProjection()-Methode, die bei jedem Rendervorgang aufgerufen wird:

```
public static void setProjection(int height,int width){
	glMatrixMode(GL_PROJECTION); // Projektions-Matrix aktivieren
	{
		glLoadIdentity(); // Standard-Matrix laden
		gluPerspective(65d,(double)width/(double)height,0.1d,(double)visibility/10d); // Perspektive festlegen
	}
	return;
}
```
gluPerspective()-Methode, die nicht in LWJGL 3.0.0a vorhanden ist:

```
private static void gluPerspective(double fovY,double aspect,double zNear,double zFar){
	double fH=Math.tan(fovY/360d*Math.PI)*zNear;
	double fW=fH*aspect;
	
	glFrustum(-fW,fW,-fH,fH,zNear,zFar); // Frustum festlegen
	return;
}
```
freeMemory() gibt alle OpenGL-Objekte frei:

```
public static void freeMemory(){
	glDeleteBuffers(VBO.NormalID[0]);
	glDeleteBuffers(VBO.TexID[0]);
	glDeleteBuffers(VBO.VertexID[0]);
	for(int i=0;i<textureID.length;i++){ // Texturen freigeben
		glDeleteTextures(textureID[i]);
	}
	return;
}
```
Die draw-Methode wird von der Hauptklasse immer wieder neu aufgerufen (normaler Rendervorgang):

```
public static void draw(float x,float y,float z,float roll,float yaw){
	glMatrixMode(GL_MODELVIEW); // Modell-Matrix aktivieren
	{
		glLoadIdentity(); // Standard-Matrix laden
		glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
		glRotatef(-roll,1f,0f,0f); // X-Achse rotieren
		glRotatef(yaw,0f,1f,0f); // Y-Achse rotieren
		glTranslatef(-x,-y,z); // Position festlegen
		for(int i=0;i<classes.Game.chunks.size();i++){ // alle Chunks zeichnen
			drawChunk(classes.Game.chunks.get(i));
		}
	}
	return;
}
```
Die drawChunk-Methode zeichnet einen Chunk in die Szene:

```
private static void drawChunk(Chunk c){
	glPushMatrix(); // Matrix auf den Stack legen
	glTranslatef((float)c.getXPos()*Chunk.size*2*BlockSize,(float)c.getYPos()*Chunk.size*2*BlockSize,(float)c.getZPos()*Chunk.size*2*BlockSize); // Chunk-Position festlegen
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);
	{
		glBindBuffer(GL_ARRAY_BUFFER,VBO.NormalID[0]);
		glNormalPointer(GL_SHORT,0,0l);
		glBindBuffer(GL_ARRAY_BUFFER,VBO.TexID[0]);
		glTexCoordPointer(VBO.TexCount[0],GL_SHORT,0,0l);
		glBindBuffer(GL_ARRAY_BUFFER,VBO.VertexID[0]);
		glVertexPointer(VBO.VertexCount[0],GL_FLOAT,0,0l);
	}
	for(short x=0;x<Chunk.size;x++){
		if(x!=0){
			glTranslatef(BlockSize*2,0f,0f); // Position auf der X-Achse verschieben
		}
		for(short y=0;y<Chunk.size;y++){
			if(y!=0){
				glTranslatef(0f,BlockSize*2,0f); // Position auf der Y-Achse verschieben
			}
			for(short z=0;z<Chunk.size;z++){
				if(z!=0){
					glTranslatef(0f,0f,BlockSize*2); // Position auf Z-Achse verschieben
				}
				if(c.getBlock(x,y,z)!=0){ // wenn ein solider Block gezeichnet werden soll
					glBindTexture(GL_TEXTURE_2D,textureID[c.getBlock(x,y,z)-1]); // Textur binden
					glDrawArrays(GL_QUADS,0,VBO.VertexSize[0]); // Block zeichnen
				}
			}
			glTranslatef(0f,0f,(float)-(Chunk.size-1)*BlockSize*2); // Position auf der Z-Achse zuruecksetzen
		}
		glTranslatef(0f,(float)-(Chunk.size-1)*BlockSize*2,0f); // Position auf der Y-Achse zuruecksetzen
	}
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	glPopMatrix(); // Matrix vom Stack nehmen
	return;
}
```
Zur drawChunk-Methode nochmal eine Frage: Ist es irgendwie hier möglich effizienteren Code einzuarbeiten. Ich meine, das Spiel hackt schon ein wenig. Gibt es irgendwie eine OpenGL-Lösung, bei der man nicht sichtbare Blöcke auch nicht zeichnet.
Gibt es da nicht etwas mit dem Framebuffer oder so was? Wäre dankbar für euren Rat!

MfG

Seikuassi


----------

