LWJGL VBO rendern

Hallo,
ich habe mich in letzter Zeit wieder mit LWJGL auseinandergesetzt und dazu dieses Tutorial genutzt.
Mein Programm soll ein rotes Dreieck auf einen cyan-farbigen Hintergrund zeichnen. Hier mein Code:

(Die TriangleTest.class wird einmal in der main()-Methode erstellt)

TriangleTest.class
[spoiler]

package de.turakar.lwjgl_tests.triangle;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

public class TriangleTest implements Runnable {
	
	private Thread thread;
	private boolean stop;
	
	private Triangle triangle;

	public TriangleTest() {
		thread = new Thread(this, "LWJGLThread");
		thread.start();
	}

	@Override
	public void run() {
		stop = false;
		try {
			Display.setDisplayMode(new DisplayMode(800, 600));
			Display.setTitle("Triangle");
			Display.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
			stop();
		}
		init();
		while(!stop) {
			render();
			Display.update();
			Display.sync(60);
			if(Display.isCloseRequested()) {
				stop();
			}
		}
		destroy();
		Display.destroy();
	}

	private void init() {
		GL11.glViewport(0, 0, 800, 600);
		GL11.glClearColor(0f, 0.8f, 1f, 1f);
		
		triangle = new Triangle();
		triangle.init();
	}

	private void render() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
		triangle.render();
	}

	private void destroy() {
		triangle.destroy();
	}

	private void stop() {
		stop = true;
	}
	
}

[/spoiler]

Triangle.class
[spoiler]

package de.turakar.lwjgl_tests.triangle;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;

/**
 * A example class for the use of VBOs and Shaders.
 * @author Turakar
 */
public class Triangle {
	
	private int vboHandle;
	private int program;

	/**
	 * This method creates and initializes the buffer and the shader.
	 */
	public void init() {
		// define vertices
		float[] verticesArray = new float[] {
				200f, 200f, 0f,
				600f, 200f, 0f,
				200f, 600f, 0f
		};
		FloatBuffer vertices = ByteBuffer.allocateDirect(verticesArray.length * (Float.SIZE / 8)).asFloatBuffer();
		vertices.put(verticesArray);
		vertices.flip();
		
		// generate buffer
		IntBuffer handleBuffer = ByteBuffer.allocateDirect(1 * (Integer.SIZE / 8)).asIntBuffer();
		GL15.glGenBuffers(handleBuffer);
		vboHandle = handleBuffer.get();
		
		// write to buffer
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandle);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW);
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
		
		// create the shaders
		int vertexShader = createShader(GL20.GL_VERTEX_SHADER, "res/shaders/simple_vertex.shader");
		int fragmentShader = createShader(GL20.GL_FRAGMENT_SHADER, "res/shaders/simple_fragment.shader");
		program = createProgram(vertexShader, fragmentShader);
	}
	
	/**
	 * This method creates a shader.
	 * @param type the gl constant (e.g. GL_FRAGMENT_SHADER)
	 * @param sourcePath the path of the file with the shader´s source
	 * @return the shader handle
	 */
	private int createShader(int type, String sourcePath) {
		// create the Shader
		int shader = GL20.glCreateShader(type);
		// load the file
		try {
			StringBuilder sb = new StringBuilder();
			byte[] buffer = new byte[1];
			FileInputStream sourceStream = new FileInputStream(sourcePath);
			while(sourceStream.read(buffer) > 0) {
				sb.append((char) buffer[0]);
			}
			sourceStream.close();
			// set the shader´s source
			GL20.glShaderSource(shader, sb.toString());
		} catch (IOException e) {
			e.printStackTrace();
		}
		// compile
		GL20.glCompileShader(shader);
		// check the status
		int status = GL20.glGetShaderi(shader, GL20.GL_COMPILE_STATUS);
		if(status == GL11.GL_FALSE) {
			// get the log
			int logLength = GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH);
			String log = GL20.glGetShaderInfoLog(shader, logLength);
			// throw an error
			throw new RuntimeException("Shader in file " + sourcePath + "wasn´t compiled correctly! Log:
" + log);
		} else {
			// get the log
//			int logLength = GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH);
//			String log = GL20.glGetShaderInfoLog(shader, logLength);
//			System.out.println(log);
		}
		return shader;
	}
	
	/**
	 * This method creates a program and links the shaders to it.
	 * @param handles
	 * @return the handle of the program
	 */
	private int createProgram(int... handles) {
		// create program
		int program = GL20.glCreateProgram();
		// attach the shaders
		for(int handle : handles) {
			GL20.glAttachShader(program, handle);
		}
		// link the program
		GL20.glLinkProgram(program);
		// error checking
		int status = GL20.glGetProgrami(program, GL20.GL_LINK_STATUS);
		if(status == GL11.GL_FALSE) {
			// get the log
			int logLength = GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH);
			String log = GL20.glGetProgramInfoLog(program, logLength);
			// throw an error
			throw new RuntimeException("Program wasn´t linked correctly! Log:
" + log);
		} else {
//			// get the log
//			int logLength = GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH);
//			String log = GL20.glGetProgramInfoLog(program, logLength);
//			System.out.println(log);
		}
		// detach the shaders
		for(int handle : handles) {
			GL20.glDetachShader(program, handle);
		}
		return program;
	}

	/**
	 * This method renders the Triangle.
	 */
	public void render() {
		// set the program
		GL20.glUseProgram(program);
		// bind buffer
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandle);
		// set attributes
		GL20.glEnableVertexAttribArray(0);
		GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, (long) 0);
		// render
		GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, 3);
		// unbind
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
		GL20.glUseProgram(0);
	}

	/**
	 * This method deletes the buffer and the shader program.
	 */
	public void destroy() {
		//delete buffer
		GL15.glDeleteBuffers(vboHandle);
	}

}

[/spoiler]

simple_vertex.shader
[spoiler]

#version 330

layout(location = 0) in vec4 position;
void main()
{
    gl_Position = position;
}

[/spoiler]

simple_fragment.shader
[spoiler]


#version 330

out vec4 outputColor;
void main()
{
   outputColor = vec4(1.0f, 0f, 0f, 1.0f);
}

[/spoiler]

Die momentan installierte LWJGL-Version ist 4.0.0.

EDIT: Folgende Sachen habe ich geprüft:

  • die Shaders werden richtigf aus der Datei geladen
  • der Buffer wird korrekt mit Daten befüllt
  • Code mindestens fünf mal durchgelsesen und keinen Fehler gefunden
  • gl_FragColor statt out wert genutzt

Und der Fehler ist… … …?

Meine Kristallkugel sagt mir: Es wird nichts angezeigt.

Gut, so weit schafft das jede billige Kristallkugel von Supermarkt. Meine zeigt aber noch mehr. Muss nur schnell die Lottozahlen von nächster Woche wegwischen wisch … so, sie zeigt: Du verwendest kein VAO (Vertex Array Object). Bei den neuesten OpenGL-Versionen MUSS man immer wenn man ein VBO rendern will auch ein VAO anlegen. FALLS es das ist, musst du ggf. nur grob sowas wie

int vertexArrayObject = GL30.glGenVertexArray();
glBindVertexArray(vertexArrayObject);
// Rest wie vorher:

// generate buffer
IntBuffer handleBuffer = ByteBuffer.allocateDirect(1 * (Integer.SIZE / 8)).asIntBuffer();
GL15.glGenBuffers(handleBuffer);
vboHandle = handleBuffer.get();
....

in deiner Triangle.java einfügen.

BTW: Man kann da einige Sachen einfacher schreiben. Im speziellen bietet LWJGL überladene Funktionen für das erstellen einzelner Buffers an. D.h. das “generate buffer” sollte man auch als

vboHandle = GL15.glGenBuffer();

schreiben können. Und wenn man static imports verwendet…

import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL30.*;
...

kann man auch die ganzen “GL15.”-usw. Präfixe weglassen…

Danke für deine Antwort. Die Präfixe werde ich drin lassen, da ich Eclipse bei Strg+Shift+O dann immer jede Methode einzelnd importiert. In die VAO werde ich mich wohl einlesen müssen, schließlich sollte ich ja auch ca verstehen was ich da schreibe. Bin aber grad nur am iPod.

Übrigens, wo hast du deine Kristallkugel gekauft? Es wird nämlich wirklich nichts gerendert.

Gesendet von meinem iPod touch mit Tapatalk

*** Edit ***

Habe jetzt versucht das Gesagte umzusetzen und hab mich auch nochmal in VAOs eingelesen. Trotzdem wird nichts gerendert.

Triangle.class
[spoiler]

package de.turakar.lwjgl_tests.triangle;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;

/**
 * A example class for the use of VBOs and Shaders.
 * @author Turakar
 */
public class Triangle {
	private int vaoHandle;
	private int program;

	/**
	 * This method creates and initializes the buffers and the shaders.
	 */
	public void init() {
		// define vertices
		float[] verticesArray = new float[] {
				200f, 200f, 0f,
				600f, 200f, 0f,
				200f, 600f, 0f
		};
		FloatBuffer vertices = ByteBuffer.allocateDirect(verticesArray.length * (Float.SIZE / 8)).asFloatBuffer();
		vertices.put(verticesArray);
		vertices.flip();
		
		// generate buffer
		int vboHandle = GL15.glGenBuffers();
		
		// write to buffer
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandle);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW);
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);

		// generate VAO
		vaoHandle = GL30.glGenVertexArrays();
		GL30.glBindVertexArray(vaoHandle);
		GL20.glEnableVertexAttribArray(0);
		
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandle);
		GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
		
		// create the shaders
		int vertexShader = createShader(GL20.GL_VERTEX_SHADER, "res/shaders/simple_vertex.shader");
		int fragmentShader = createShader(GL20.GL_FRAGMENT_SHADER, "res/shaders/simple_fragment.shader");
		program = createProgram(vertexShader, fragmentShader);
	}
	
	/**
	 * This method creates a shader.
	 * @param type the gl constant (e.g. GL_FRAGMENT_SHADER)
	 * @param sourcePath the path of the file with the shader´s source
	 * @return the shader handle
	 */
	private int createShader(int type, String sourcePath) {
		// create the Shader
		int shader = GL20.glCreateShader(type);
		// load the file
		try {
			StringBuilder sb = new StringBuilder();
			byte[] buffer = new byte[1];
			FileInputStream sourceStream = new FileInputStream(sourcePath);
			while(sourceStream.read(buffer) > 0) {
				sb.append((char) buffer[0]);
			}
			sourceStream.close();
			// set the shader´s source
			GL20.glShaderSource(shader, sb.toString());
		} catch (IOException e) {
			e.printStackTrace();
		}
		// compile
		GL20.glCompileShader(shader);
		// check the status
		int status = GL20.glGetShaderi(shader, GL20.GL_COMPILE_STATUS);
		if(status == GL11.GL_FALSE) {
			// get the log
			int logLength = GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH);
			String log = GL20.glGetShaderInfoLog(shader, logLength);
			// throw an error
			throw new RuntimeException("Shader in file " + sourcePath + "wasn´t compiled correctly! Log:
" + log);
		} else {
//			// get the log
//			int logLength = GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH);
//			String log = GL20.glGetShaderInfoLog(shader, logLength);
//			System.out.println(log);
		}
		return shader;
	}
	
	/**
	 * This method creates a program and links the shaders to it.
	 * @param handles
	 * @return the handle of the program
	 */
	private int createProgram(int... handles) {
		// create program
		int program = GL20.glCreateProgram();
		// attach the shaders
		for(int handle : handles) {
			GL20.glAttachShader(program, handle);
		}
		// link the program
		GL20.glLinkProgram(program);
		// error checking
		int status = GL20.glGetProgrami(program, GL20.GL_LINK_STATUS);
		if(status == GL11.GL_FALSE) {
			// get the log
			int logLength = GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH);
			String log = GL20.glGetProgramInfoLog(program, logLength);
			// throw an error
			throw new RuntimeException("Program wasn´t linked correctly! Log:
" + log);
		} else {
//			// get the log
//			int logLength = GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH);
//			String log = GL20.glGetProgramInfoLog(program, logLength);
//			System.out.println(log);
		}
		// detach the shaders
		for(int handle : handles) {
			GL20.glDetachShader(program, handle);
		}
		return program;
	}

	/**
	 * This method renders the Triangle.
	 */
	public void render() {
		// set the program
		GL20.glUseProgram(program);
		// VAO
		GL30.glBindVertexArray(vaoHandle);
		GL20.glEnableVertexAttribArray(0);
		// render
		GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, 3);
		// unbind
		GL30.glBindVertexArray(0);
		GL20.glUseProgram(0);
	}

	/**
	 * This method deletes the buffer
	 */
	public void destroy() {
		//delete buffer
		GL30.glDeleteVertexArrays(vaoHandle);
	}

}

[/spoiler]

Edit:
Hab nochmal meine Shaders geändert: (Ich habe noch einen in vec4 und nicht in vec3 benutzt)

simple_vertex.shader
[spoiler]

#version 330

layout(location = 0) in vec3 position;
void main()
{
    gl_Position = vec4(position, 1f);
}

[/spoiler]

simple_fragment.shader
[spoiler]

#version 330

out vec4 outputColor;
void main()
{
   outputColor = vec4(1.0f, 0f, 0f, 1.0f);
}

[/spoiler]

Moin,

die Koordinaten am Ausgang des Vertex-Shaders sind Clip-Space Koordinaten, müssen also im [-1,+1]³ liegen (genauer [-w,+w]³). Also entweder eine entsprechende Transformationsmatrix verwenden, oder Vertex Koordinaten, die innerhalb dieses Bereichs liegen.

Außerdem ist die ByteOrder des Buffers wichtig. Und der Inhalt des Buffers muss noch mit glVertexAttribPointer beschrieben werden.

Die 1f im Shader sind auch gefährlich, nicht jeder Treiber akzeptiert das.

Also:


        // define vertices
        final float[] verticesArray = new float[] {
                -0.5f, -0.5f, 0f, // <--
                +0.5f, -0.5f, 0f, // <--
                +0.0f, +0.5f, 0f // <--
        };
        final FloatBuffer vertices = ByteBuffer.allocateDirect(verticesArray.length * (Float.SIZE / 8)).order(ByteOrder.nativeOrder()).asFloatBuffer(); // <--
        vertices.put(verticesArray);
        vertices.flip();

        // generate VAO
        vaoHandle = GL30.glGenVertexArrays();
        GL30.glBindVertexArray(vaoHandle);

        // generate buffer
        final int vboHandle = GL15.glGenBuffers();

        // write to buffer
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandle);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW);

        GL20.glEnableVertexAttribArray(0);
        GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 3 * 4, 0 * 4); // <--

        // create the shaders
        int vertexShader = createShader(GL20.GL_VERTEX_SHADER, "res/shaders/simple_vertex.shader");
        int fragmentShader = createShader(GL20.GL_FRAGMENT_SHADER, "res/shaders/simple_fragment.shader");

        program = createProgram(vertexShader, fragmentShader);


    }```


#version 330

layout(location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position, 1.0); // <–
}




#version 330

out vec4 outputColor;
void main()
{
outputColor = vec4(1.0, 0, 0, 1.0); // <–
}



Viele Grüße
Fancy

Es ist nicht klar, ob du das willst, oder gerade NICHT willst, aber man kann bei Eclipse einen “Threshold” einstellen, ab dem er - statt der einzelnen imports - ein “.*” verwenden soll. Mal in den Optionen schauen, ggf. kann ich’s raussuchen.

@Fancy
Den Code werde ich gleich testen. Schonmal danke im voraus. @marco
Bei mir hat das dann auch dazu geführt, dass er aus mehreren Klassen-Imports auch package-der-klassen.* gemacht hat, was ich unschön fand. (Mein Ziel wär übrigens, dass er die statics nicht in die Member unterteilt sondern in zb GL15.* zusammenfasst.

Gesendet von meinem iPod touch mit Tapatalk

*** Edit ***

Danke für die antworten, es klappt jetzt! :smiley:

Ich hab’ auf meinem Desktop eine Textdatei mit diesem Inhalt

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL21.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL31.*;
import static org.lwjgl.opengl.GL32.*;
import static org.lwjgl.opengl.GL33.*;
import static org.lwjgl.opengl.GL40.*;

Braucht man gelegentlich mal zwinker