Opengl Particles

Nö, eigentlich nicht:

Was Du davon nicht nutzen kannst, ist: advanced interleaving, doubles and alignment, in-shader specification und feedback objects. Das ist alles OpenGL4+. Brauchst Du aber alles nicht.

Vielleicht hat Dich das verwirrt:

Du benutzt aber doch kein glCreateShaderProgram sondern baust mit glCompileShader, glAttachShader und glLinkProgram. Und genau zwischen die letzten beiden gehört jetzt das neue glTransformFeedbackVaryings.

Viele Grüße
Fancy

Ach ich bin auch blind. Steht ja “core in version: 4.4” und “core since version: 3.0”, aber letzteres habe ich natürlich übersehen. Okay.

*** Edit ***

Ich verstehe eine Sache nicht.
Woher genau weiß mein Shader denn jetzt wo er was zeichnen soll?
gl_Position wird ja weggelassen wenn ich es richtig verstanden habe?

Es gibt Verfahren, die in zwei (oder mehr) Schritten arbeiten, also erst rechnen und dann zeichnen und es gibt Verfahren die machen beides gleichzeitig in einem einzigen Schritt. Anfangen solltest Du vermutlich mit einem Schritt. Sieh Dir meinen Shader auf der vorherigen Seite noch mal an.

Mit vIn kommen die Positionsdaten herein.
Mit vOut werden die nach oben verschobenen neuen Positionsdaten rausgeschrieben (über Transform Feedback).
Und mit gl_Position wird die übrige OpenGL Pipeline zur Darstellung versorgt.

Viele Grüße
Fancy

Also, ich konnte die Woche nicht so viel arbeiten, jedenfalls… ich bin nicht weiter gekommen.
Habe vergeblich versucht irgendwie irgendetwas einzubauen mit den Dingen die
man im Netz so findet, aber wie gesagt, vergeblich. Ich versteh ja nicht ein mal
das Prinzip zu 100%.
Aus dem Zeug das ich gelesen habe, mein (Nicht-) Verständniss:

  • Ich hab ein VBO, in das packe ich alle Positionen der Partikel (auf der Cpu?)
    Das mache ich jedes mal wenn ich ein neues Particle spawnen will?

  • Ich hab ne “out” variable im vertex shader, dieses out wird beschrieben wie normalerweise gl_Position ?

  • Ich sage irgendwann glBeginTransformFeedback, das heißt so viel wie das er obiges machen soll und die render pipeline nicht zum
    Ende führt, oder?

  • Ich habe also 2 Draw calls, einmal mit TF, und da wird NICHTS gezeichent, und dann nach TF, da wird aber was gezeichnet - und davor
    muss ich dann den ganzen Buffer wieder updaten oder wie?

  • Habe ich dann 2 Shader Programme oder wie, wobei das eine ohne Fragment Shader da steht??

Das Problem ist irgendwie das ich sehr wenig Zeug dazu finde, wenn dann meistens mit Opengl 4 und einfach nur
schlecht erklärt, nach dem Motto “Ja und das funktioniert jetzt halt.”, was wo wie genau siehe obigen Fragen hab ich
immer noch nicht Begriffen…

Danke Leute falls hier noch mal jmd Zeit opfert ^^

[QUOTE=mymaksimus]- Ich hab ein VBO, in das packe ich alle Positionen der Partikel (auf der Cpu?)
Das mache ich jedes mal wenn ich ein neues Particle spawnen will?[/QUOTE]

Ja, neue Partikel werden auf der CPU in ein VAO/VBO gepackt und über den Render-Prozess in den Transform Feedback Buffer geschrieben.

Ja, siehe mein Shader auf der vorherigen Seite.

Nein, die Pipeline wird normal abgearbeitet. Man kann diese explizit deaktivieren, aber man kann auch gleichzeitig Rendern und Transform Feedback nutzen. (Hoffe zumindest das das auch mit OpenGL 3 schon geht, in der Spec sehe ich aber nichts was dagegen spricht)

Möglich, das wäre ein Multi-Pass Verfahren. Möglich sind aber auch Single-Pass Verfahren, also gleichzeitig rechnen und zeichnen.

Bei einem Multi-Pass Verfahren hättest Du mehrere Shader-Programme. Bei einem Single-Pass nur einen. Ein Fragment-Shader muss aber immer vorhanden sein, auch wenn dieser nur eine leere Methode enthält.

In meinem KSKB sieht die Render-Schleife so aus:


        vao2.bindAsTransformFeedbackBuffer();
        glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
        glBeginTransformFeedback(GL_POINTS);

        final int newParticleCount = Math.min((int) (500 * delta), vaoEmitter.size);
        final int oldParticleCount = Math.min(currentParticleCount, vao2.size - newParticleCount);

        vaoEmitter.populate();
        vaoEmitter.bind();
        glDrawArrays(GL_POINTS, 0, newParticleCount);

        vao1.bind();
        glDrawArrays(GL_POINTS, 0, oldParticleCount);

        glEndTransformFeedback();
        glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
        currentParticleCount = glGetQueryObjecti(query, GL_QUERY_RESULT);

        final VAO temp = vao1;
        vao1 = vao2;
        vao2 = temp;```

- Transform Feedback und Rendern passiert gleichzeitig
- neue Partikel werden über vaoEmitter hinzugefügt
- in vao1 befinden sich die Partikel aus dem vorherigen Frame
- in vao2 werden die neuen und die alten hineingeschrieben
- jedes Frame wird vao1 und vao2 getauscht

Viele Grüße
Fancy

vao2.bindAsTransformFeedbackBuffer();
?

In dem Beispiel gibt es drei verschiedene VAO/VBO. Es bietet sich also an, das in eine Klasse auszulagern. Etwa:


        private final int size;
        private final int handleVAO;
        private final int handleVBO;

        private float[] points;
        private FloatBuffer buffer;


        public VAO(final int size) {

            this.size = size;

            handleVAO = glGenVertexArrays();
            glBindVertexArray(handleVAO);

            handleVBO = glGenBuffers();
            glBindBuffer(GL_ARRAY_BUFFER, handleVBO);
            glBufferData(GL_ARRAY_BUFFER, size * 4 * 4, GL_STREAM_DRAW);
            glEnableVertexAttribArray(VERTEX_COORD_LOCATION);
            glVertexAttribPointer(VERTEX_COORD_LOCATION, 4, GL_FLOAT, false, 4 * 4, 0 * 4);

        }


        public void populate() {

            if (points == null || buffer == null) {

                points = new float[size * 4];
                buffer = BufferUtils.createFloatBuffer(points.length);

            }

            for (int i = 0; i < size; i++) {

                points[i * 4 + 0] = (float) (Math.random() - 0.5) * 0.5f;
                points[i * 4 + 1] = (float) (Math.random() - 0.5) * 0.1f - 1.0f;
                points[i * 4 + 2] = (float) (Math.random() - 0.5) * 0.5f;
                points[i * 4 + 3] = 1;

            }

            buffer.put(points);
            buffer.flip();

            glBindBuffer(GL_ARRAY_BUFFER, handleVBO);
            glBufferData(GL_ARRAY_BUFFER, buffer, GL_STREAM_DRAW);

        }


        public void bind() {

            glBindVertexArray(handleVAO);

        }


        public void bindAsTransformFeedbackBuffer() {

            glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, handleVBO, 0, size * 4 * 4);

        }

    }

Viele Grüße
Fancy

ja das ist mir klar,
wollte nur wissen was diese methode macht ^^

So, ich hatte das ganze doch noch etwas weiter beseite gelegt.
Nun mach ich weiter ^^

Hab das ganze erstmal ohne rendern versucht, sprich überhaupt erstmal nur das transform feedback zum laufen zu bekommen.
Ich hab mir natürlich deine Sachen angeguckt Fancy, (Nix umsonst! ^^), aber wie gesagt, wollte es erst ohne rendern versuchen.
Hier das Tutorial anhand dessen ich es versucht hab: link

Das ganze klappt so aber nicht.
Mein Code dazu:
(fast alles ausgeschrieben [nur eine sache mit AGL…] weil ich das bei neuen dingen immer erst so ausprobiere.)

package de.skysoldier.lwjgltest;

import java.nio.FloatBuffer;

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

import de.skysoldier.abstractgl.lib.AGL;
import de.skysoldier.abstractgl.lib.AGLCaps.AGLDisplayCap;

public class TransformFeedbackTest {
	
	public TransformFeedbackTest(){
		AGL.createLwjglContext(AGLDisplayCap.NONE);
	
		String vshaderString = 
				"in float invert; 
" + 
				"varying out float outvert; 
" + 
				"void main(){ 
" + 
				"outvert = sqrt(invert); 
" + 
				"} 
";
		
		int vshaderId = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
		GL20.glShaderSource(vshaderId, vshaderString);
		GL20.glCompileShader(vshaderId);
		
		int programId = GL20.glCreateProgram();
		GL20.glAttachShader(programId, vshaderId);
		
		GL30.glTransformFeedbackVaryings(programId, new String[]{"vout"}, GL30.GL_INTERLEAVED_ATTRIBS);
		
		GL20.glLinkProgram(programId);
		GL20.glUseProgram(programId);
		
		int compileStatus = GL20.glGetShaderi(vshaderId, GL20.GL_COMPILE_STATUS);
        if (compileStatus == GL11.GL_FALSE) {
            int infoLogLength = GL20.glGetShaderi(vshaderId, GL20.GL_INFO_LOG_LENGTH);
            String infoLog = GL20.glGetShaderInfoLog(vshaderId, infoLogLength);
            throw new RuntimeException(infoLog);
        }
        System.out.println("Compile Errors: " + GL20.glGetProgramInfoLog(programId, GL20.glGetProgrami(programId, GL20.GL_INFO_LOG_LENGTH)));
		
		int vao = GL30.glGenVertexArrays();
		GL30.glBindVertexArray(vao);
		
		FloatBuffer fbuffer = BufferUtils.createFloatBuffer(4);
		fbuffer.put(0.4f);
		fbuffer.put(0.754f);
		fbuffer.put(0.9f);
		fbuffer.put(900.0f);
		int vbo = GL15.glGenBuffers();
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, fbuffer, GL15.GL_STATIC_DRAW);
		
		int inputvert = GL20.glGetAttribLocation(programId, "invert");
		GL20.glEnableVertexAttribArray(inputvert);
		GL20.glVertexAttribPointer(inputvert, 3, GL11.GL_FLOAT, false, 5 * Float.SIZE / 8, 0);
		
		int buffer2 = GL15.glGenBuffers();
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buffer2);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(0), GL15.GL_STATIC_READ);
		
		GL11.glEnable(GL30.GL_RASTERIZER_DISCARD);
		GL30.glBindBufferBase(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer2);
		
		GL30.glBeginTransformFeedback(GL11.GL_POINTS);
		GL11.glDrawArrays(GL11.GL_POINTS, 0, 4);
		GL30.glEndTransformFeedback();
		GL11.glFlush();
		
		FloatBuffer result = BufferUtils.createFloatBuffer(4);
		GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
	}
	
	public static void main(String[] args){
		new TransformFeedbackTest();
	}
}

So klappt es leider nicht. FOlgende meldung:


Compile Errors: Vertex info
-----------
(0) : error C5145: must write to gl_Position

Link info
---------
error: Programs must have a vertex, geometry, or tessellation shader assigned to use transform Feedback varyings.


Okay. Also genau das was ich nicht machen will, zu gl_Position schreiben…

Lasse ich übrigens das “varying” in Zeile 2 des Shaders weg, (also von outvert), [so wie im tutorial?..]
Bekomme ich folgende Meldung:


Exception in thread "main" java.lang.RuntimeException: 0(2) : error C5060: out can't be used with non-varying outvert

	at de.skysoldier.lwjgltest.TransformFeedbackTest.<init>(TransformFeedbackTest.java:42)
	at de.skysoldier.lwjgltest.TransformFeedbackTest.main(TransformFeedbackTest.java:89)

Why ever…

Jemand ne Idee was ich falsch gemacht habe?

Du musst im Shader die Version angeben, sonnst wird das als uralt GLSL interpretiert.

Nur das Notwendigste korrigiert und ich bin mir nicht sicher, wie kompatibel das so ist:


import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS;
import static org.lwjgl.opengl.GL20.GL_INFO_LOG_LENGTH;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetProgrami;
import static org.lwjgl.opengl.GL20.glGetShaderInfoLog;
import static org.lwjgl.opengl.GL20.glGetShaderi;
import static org.lwjgl.opengl.GL30.GL_TRANSFORM_FEEDBACK_BUFFER;
import static org.lwjgl.opengl.GL30.glBindBufferRange;

import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.PixelFormat;

public class TransformFeedbackTest {

    public TransformFeedbackTest() throws LWJGLException {

        final DisplayMode displayMode = new DisplayMode(800, 600);
        final PixelFormat pixelFormat = new PixelFormat();
        final ContextAttribs contextAttribs = new ContextAttribs(3, 1);

        Display.setDisplayMode(displayMode);
        Display.create(pixelFormat, contextAttribs);


        final String vshaderString = ""
                + "#version 140           
"
                + "in float invert;       
"
                + "out float vout;        
"
                + "void main() {          
"
                + "  vout = sqrt(invert); 
"
                + "} 
";

        final int vshaderId = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
        GL20.glShaderSource(vshaderId, vshaderString);
        GL20.glCompileShader(vshaderId);

        if (GL_FALSE == glGetShaderi(vshaderId, GL_COMPILE_STATUS)) {

            final int length = glGetShaderi(vshaderId, GL_INFO_LOG_LENGTH);
            final String log = glGetShaderInfoLog(vshaderId, length);

            throw new RuntimeException(log);

        }


        final int programId = GL20.glCreateProgram();
        GL20.glAttachShader(programId, vshaderId);

        GL30.glTransformFeedbackVaryings(programId, new String[] { "vout" }, GL30.GL_INTERLEAVED_ATTRIBS);

        GL20.glLinkProgram(programId);

        if (GL_FALSE == glGetProgrami(programId, GL_LINK_STATUS)) {

            final int length = glGetProgrami(programId, GL_INFO_LOG_LENGTH);
            final String log = glGetProgramInfoLog(programId, length);

            throw new RuntimeException(log);

        }

        GL20.glUseProgram(programId);

        final int buffer2 = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, buffer2);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, 5 * 4, GL15.GL_STATIC_READ);
        glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer2, 0, 5 * 4);

        final int vao = GL30.glGenVertexArrays();
        GL30.glBindVertexArray(vao);

        final FloatBuffer fbuffer = BufferUtils.createFloatBuffer(5);
        fbuffer.put(1.0f);
        fbuffer.put(2.0f);
        fbuffer.put(3.0f);
        fbuffer.put(4.0f);
        fbuffer.put(5.0f);
        fbuffer.rewind();
        final int vbo = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, fbuffer, GL15.GL_STATIC_DRAW);

        final int inputvert = GL20.glGetAttribLocation(programId, "invert");
        GL20.glEnableVertexAttribArray(inputvert);
        GL20.glVertexAttribPointer(inputvert, 1, GL11.GL_FLOAT, false, 4, 0);

        GL11.glEnable(GL30.GL_RASTERIZER_DISCARD);
        GL30.glBeginTransformFeedback(GL11.GL_POINTS);
        GL11.glDrawArrays(GL11.GL_POINTS, 0, 5);
        GL30.glEndTransformFeedback();
        GL11.glFlush();

        final FloatBuffer result = BufferUtils.createFloatBuffer(5);
        GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);

        for (int i = 0; i < result.capacity(); i++)
            System.out.println(result.get(i));

    }


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

        new TransformFeedbackTest();

    }
}

Viele Grüße
Fancy

Ups.
Kommt davon…

Danke erstmal, schau mir später mal an was genau du korrigiert hast.
Was genau hat es nun mit der Kompatibilität auf sich?..

*** Edit ***

nice danke, jetzt gehts auch bei mir.
Die schwerwiegenden fehler waren offensichtlich das 5 * Float.Size / 8 [why ever, glaube reflex aus einem altem kskb…],
das ich die size nicht mit Float.Size / 8 verrechnet hab, (also 4), und glBindBufferRange. Wieso geht es mit glBindBufferBase eigentlich?
Und was genau bringt das? Laut opengl.org binde ich das buffer object zu einem bestimmten
index - okay. aber was bringt das opengl? Ich benutze diesen index doch nicht nirgendwo, ich hab doch die buffer id?
Ach und was bringt der offset bei vielen methoden? zB bei getBufferSubData…

*** Edit ***

Hm. Wenn ich jetzt einfach nur einen fragment shader einbaue, das rasterizer discard rausnehme, nur 3 werte in das input object packe, auf gl_Position im vertex shader schreibe, und GL_TRIANGLES bei beiden modi angaben benutze - müsste ich doch was sehen oder? Tu ich aber nicht…

Das was du gemacht hast mit buffer swapen und so, das brauch ich doch erst wenn ich neue werte (partikel…) reinschreiben will, oder?

Mit der Kompatibilität meinte ich, das ich mir nicht sicher bin ab welcher OpenGL Version es erlaubt ist den Fragmentshader wegzulassen, bzw. welche Grafikkarten damit zurechtkommen. Im Zweifelsfall würde ich einen Fragmentshader mit einer leeren main() anhängen. Das glEnable(GL_RASTERIZER_DISCARD) sorgt ja bereits dafür, dass nach dem Vertexshader nicht mehr viel passiert.

Da waren noch einige andere Punkte, z.B.: Die Reihenfolge in denen die Buffer gebunden wurden (ursprünglich: vao, vbo, buffer2), dann ist aber (erstmal) buffer2 ans vao gebunden. Bei glVertexAttribPointer die Größe und Anzahl der Elemente (das war bei Dir für ein vec3/vec2) und der Name der Variable bei glTransformFeedbackVaryings.

Mit dem Index beziehen die sich auf die Position der Variable im Shader, also dem vout. Du kannst Dir die Variablen im Shader wie in einem Array vorstellen, der Index beschreibt dann, an welcher Position des Arrays die Variable liegt. Hier gib es nur eine “out” entsprechend ist der Index 0.

Ein Buffer kann viel größer sein als der Bereich, der benötigt wird. Das Offset ist dann die Position des Buffers, ab dem gelesen/geschrieben werden soll.

Wenn Du Dreiecke rendern willst, musst Du 3 vec3 (oder vec2) in den Buffer packen, also 9 (bzw. 6 Werte). glVertexAttribPointer musst Du entsprechend anpassen.

Du Brauchst immer zwei Buffer, einen zum lesen (das vbo) und einen zum schreiben. Wen Du mehr als ein Frame rendern willst, solltest Du die beiden Buffer tauschen, aus dem, in dem gerade noch geschrieben wurde, wird dann gelesen und in den anderen geschrieben. Dazu solltest Du 2 VAOs verwenden.

Viele Grüße
Fancy

“Wenn Du Dreiecke rendern willst, musst Du 3 vec3 (oder vec2) in den Buffer packen, also 9 (bzw. 6 Werte). glVertexAttribPointer musst Du entsprechend anpassen.”

What the… nachts programmieren und mittags fragen stellen tut mit nicht gut xD

Danke ^^ zu den 2 buffern: ja eben, wenn ich nichts lesen wollen wuerde, wie ohne transform feedback - muesste es doch gehen oder?

*** Edit ***

Also ohne die zu tauschen

Ja, nur vorhanden sein muss der trotzdem (und groß genug).

Viele Grüße
Fancy

Gut das ich diesen Thread nochmal finde… geht wieder um transform feedback :stuck_out_tongue:

Habe den Code von Post #29 genommen, und deine verbesserungen eingebaut.
Dann hab ich einen fragment shader dazugeschaltet, und gl_Position beschrieben.
Ich sehe nun also Punkte auf dem Schirm.

folgendes Problem:

        GL30.glBindBufferRange(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer, 0, argumentCount * floatSizeInBytes);
        GL30.glBeginTransformFeedback(GL11.GL_POINTS);
        GL30.glBindVertexArray(firstVao);
        GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
        GL30.glEndTransformFeedback();
        
        FloatBuffer result = BufferUtils.createFloatBuffer(argumentCount);
        GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
        System.out.println("-- data in transform feedback buffer: ");
        for (int i = 0; i < result.capacity(); i++){
            System.out.println(result.get(i));
        }
        System.out.println("-- end, preparing second run..
");
        
        /** run 2 **/
        GL30.glBindBufferRange(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, firstBuffer, 0, argumentCount * floatSizeInBytes);
        GL30.glBeginTransformFeedback(GL11.GL_POINTS);
        GL30.glBindVertexArray(secondVao);
        GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
        GL30.glEndTransformFeedback();
        
        result = BufferUtils.createFloatBuffer(argumentCount);
        GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
        System.out.println("-- data in transform feedback buffer after round 2: ");
        for (int i = 0; i < result.capacity(); i++){
            System.out.println(result.get(i));
        }
        System.out.println("-- end, preparing third run..
");
    
        /** run 3 **/
        GL30.glBindBufferRange(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer, 0, argumentCount * floatSizeInBytes);
        GL30.glBeginTransformFeedback(GL11.GL_POINTS);
        GL30.glBindVertexArray(firstVao);
        GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
        GL30.glEndTransformFeedback();
        
        result = BufferUtils.createFloatBuffer(argumentCount);
        GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
        System.out.println("-- data in transform feedback buffer after round 3: ");
        for (int i = 0; i < result.capacity(); i++){
            System.out.println(result.get(i));
        }
        System.out.println("-- end.
");```

Bei diesem code, also quasi 3 frames nacheinander, bekomme ich folgenden output:


– filling buffer
-0.45
-0.2
– finished initialization

– data in transform feedback buffer:
-0.35
-0.1
– end, preparing second run…

– data in transform feedback buffer after round 2:
0.1
0.1
– end, preparing third run…

– data in transform feedback buffer after round 3:
0.2
0.2
– end.



Also einmal funktioniert es, danach kommt murks raus. warum? Wo ist der denkfehler?


Dann, was bringt bindBufferRange, im vergleich zu bindBufferBase? Aus der Opengl doc:


> glBindBufferRange binds a range the buffer object buffer represented by offset and size to the binding point at index index of the array of targets specified by target. Each target represents an indexed array of buffer binding points, as well as a single general binding point that can be used by other buffer manipulation functions such as glBindBuffer or glMapBuffer. In addition to binding a range of buffer to the indexed buffer binding target, glBindBufferRange also binds the range to the generic buffer binding point specified by target.
 

Irgendwie.. versteh ich das nicht :(

*** Edit ***

ah und noch eine sache. wir haben ja gesagt, 2 buffer, die ständig getauscht werden. mit dem einen wird gemalt, in den anderen geschrieben.
Aber: Die Buffer bekommen doch mit glBufferData eine funktion zugeschrieben, DRAW READ oder COPY. Aber so kommt es doch, das wir mit beiden buffern
beides machen, oder nicht? Darf man das etwa?

Moin,

  • wie immer: KSKB?

  • glBindBufferBase ist glBindBufferRange ohne die letzten beiden Parameter.

  • der usage Parameter bei glBufferData bezieht sich erst mal darauf, was Du mit den Daten machen möchtest. Transform Feedback sollte mit allen funktionieren.

Gruß
Fancy

biddeschön

kskb
[spoiler]```package de.skysoldier.agl2test;

import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS;
import static org.lwjgl.opengl.GL20.GL_INFO_LOG_LENGTH;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetProgrami;
import static org.lwjgl.opengl.GL20.glGetShaderInfoLog;
import static org.lwjgl.opengl.GL20.glGetShaderi;
import static org.lwjgl.opengl.GL30.GL_TRANSFORM_FEEDBACK_BUFFER;

import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;

public class TransformFeedbackPorting {

private int floatSizeInBytes = Float.SIZE / 8;
private int argumentCount = 3;
private int firstVao, secondVao;
private int firstBuffer, secondBuffer;

public TransformFeedbackPorting() throws LWJGLException {

// AGLDisplay d = new AGLDisplay(AGLDisplayCap.NONE);
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create();

	String vertexShaderContent = 
			"#version 150

"+
"in float input;
"+
"out float output;
"+
"void main(){
"+
"output = input + 0.1f;
"+
"gl_Position = vec4(input, 0, 0, 1);
"+
“}”;
final int vshaderId = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
GL20.glShaderSource(vshaderId, vertexShaderContent);
GL20.glCompileShader(vshaderId);
checkCompileErrors(vshaderId);

    String fragmentShaderContent = 
    		"#version 150

"+
"out vec4 outColor;
"+
"void main(){
"+
"outColor = vec4(1, 0, 0, 1);
"+
“}”;
final int fshaderId = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
GL20.glShaderSource(fshaderId, fragmentShaderContent);
GL20.glCompileShader(fshaderId);
checkCompileErrors(fshaderId);

    final int programId = GL20.glCreateProgram();
    GL20.glAttachShader(programId, vshaderId);
    GL20.glAttachShader(programId, fshaderId);
    
    GL30.glTransformFeedbackVaryings(programId, new String[] { "output" }, GL30.GL_INTERLEAVED_ATTRIBS);
    
    GL20.glLinkProgram(programId);
    checkLinkErrors(programId);
    GL20.glUseProgram(programId);

    
    secondVao = GL30.glGenVertexArrays();
    GL30.glBindVertexArray(secondVao);
    
    secondBuffer = GL15.glGenBuffers();
    
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, secondBuffer);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, argumentCount * floatSizeInBytes, GL15.GL_DYNAMIC_READ);
    
    GL30.glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer, 0, argumentCount * floatSizeInBytes);

// GL30.glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer);

    firstVao = GL30.glGenVertexArrays();
    GL30.glBindVertexArray(firstVao);

    
    final FloatBuffer dataBuffer = BufferUtils.createFloatBuffer(argumentCount);
   
    System.out.println("-- filling buffer");
    for(int i = 0; i < argumentCount; i++){
    	float value = (float) (((i) / (double) argumentCount) * 0.5 - 0.5);
    	System.out.println(value);
    	dataBuffer.put(value);
    }
    dataBuffer.rewind();
    System.out.println("-- finished initialization

");

    firstBuffer = GL15.glGenBuffers();
    
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, firstBuffer);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, dataBuffer, GL15.GL_DYNAMIC_DRAW);
    
    final int inputvert = GL20.glGetAttribLocation(programId, "input");
    GL20.glEnableVertexAttribArray(inputvert);
    GL20.glVertexAttribPointer(inputvert, 1, GL11.GL_FLOAT, false, 4, 0);
    
    GL11.glPointSize(10);

// testLoop();
testStepByStep();
}

private void testLoop(){
	while(!Display.isCloseRequested()){
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
        //in buffer2 soll output geschrieben werden
        GL30.glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer, 0, argumentCount * floatSizeInBytes);
        GL30.glBeginTransformFeedback(GL11.GL_POINTS);
        //von buffer1 (vao1) soll gelesen also gerendert werden
        GL30.glBindVertexArray(firstBuffer);
        GL30.glEndTransformFeedback();
        GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
        Display.update();
       
        //switch alles (vao und buffer id's)
        int temp = secondVao;
        secondVao = firstVao;
        firstVao = temp;
        temp = secondBuffer;
        secondBuffer = firstBuffer;
        firstBuffer = temp;
    }
}
    
private void testStepByStep(){
    /** run 1 **/
    GL30.glBindBufferRange(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer, 0, argumentCount * floatSizeInBytes);
    GL30.glBeginTransformFeedback(GL11.GL_POINTS);
    GL30.glBindVertexArray(firstVao);
    GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
    GL30.glEndTransformFeedback();
    
    FloatBuffer result = BufferUtils.createFloatBuffer(argumentCount);
    GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
    System.out.println("-- data in transform feedback buffer: ");
    for (int i = 0; i < result.capacity(); i++){
        System.out.println(result.get(i));
    }
    System.out.println("-- end, preparing second run..

");

    /** run 2 **/
    GL30.glBindBufferRange(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, firstBuffer, 0, argumentCount * floatSizeInBytes);
    GL30.glBeginTransformFeedback(GL11.GL_POINTS);
    GL30.glBindVertexArray(secondVao);
    GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
    GL30.glEndTransformFeedback();
    
    result = BufferUtils.createFloatBuffer(argumentCount);
    GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
    System.out.println("-- data in transform feedback buffer after round 2: ");
    for (int i = 0; i < result.capacity(); i++){
        System.out.println(result.get(i));
    }
    System.out.println("-- end, preparing third run..

");

    /** run 3 **/
    GL30.glBindBufferRange(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer, 0, argumentCount * floatSizeInBytes);
    GL30.glBeginTransformFeedback(GL11.GL_POINTS);
    GL30.glBindVertexArray(firstVao);
    GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
    GL30.glEndTransformFeedback();
    
    result = BufferUtils.createFloatBuffer(argumentCount);
    GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
    System.out.println("-- data in transform feedback buffer after round 3: ");
    for (int i = 0; i < result.capacity(); i++){
        System.out.println(result.get(i));
    }
    System.out.println("-- end.

");
}

private void checkCompileErrors(int shaderId){
	if (GL_FALSE == glGetShaderi(shaderId, GL_COMPILE_STATUS)){
        final int length = glGetShaderi(shaderId, GL_INFO_LOG_LENGTH);
        final String log = glGetShaderInfoLog(shaderId, length);
        throw new RuntimeException(log);
    }
}

private void checkLinkErrors(int programId){
	if (GL_FALSE == glGetProgrami(programId, GL_LINK_STATUS)) {
        final int length = glGetProgrami(programId, GL_INFO_LOG_LENGTH);
        final String log = glGetProgramInfoLog(programId, length);
        throw new RuntimeException(log);
    }
}

public static void main(final String[] args) throws LWJGLException {
    try{
    	new TransformFeedbackPorting();
    }
    catch(Exception e){
    	e.printStackTrace();
    }
}

}```[/spoiler]

also bei testLoop flackert alles und ich sehe einen punkt bei (0, 0) der eigentlich nicht existiert,
bei testStepByStep erhalte ich ziemlich seltsame ergebnise… aber siehe selbst

Siehst Du, ein KSKB und schon ist das Problem klar:

glVertexAttribPointer bezieht sich auf das jeweils gebundene VAO. Du setzt dies jedoch nur bei Deinem firstVao. Für secondVao ist nichts gesetzt, entsprechend wird input als 0 interpretiert.

Mein Treiber erlaubt im GLSL auch kein input als Variablenname. Außerdem sollte die OpenGL Version beim Erzeugen immer angegeben werden, um ein reproduzierbares verhalten zu ermöglichen.



import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS;
import static org.lwjgl.opengl.GL20.GL_INFO_LOG_LENGTH;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetProgrami;
import static org.lwjgl.opengl.GL20.glGetShaderInfoLog;
import static org.lwjgl.opengl.GL20.glGetShaderi;
import static org.lwjgl.opengl.GL30.GL_TRANSFORM_FEEDBACK_BUFFER;

import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.PixelFormat;


public class TransformFeedbackPorting {

    private final int floatSizeInBytes = Float.SIZE / 8;
    private final int argumentCount = 3;
    private final int firstVao, secondVao;
    private final int firstBuffer, secondBuffer;


    public TransformFeedbackPorting() throws LWJGLException {

        final DisplayMode displayMode = new DisplayMode(800, 600);
        final PixelFormat pixelFormat = new PixelFormat();
        final ContextAttribs contextAttribs = new ContextAttribs(3, 1); // <--
        Display.setDisplayMode(displayMode);
        Display.create(pixelFormat, contextAttribs);

        final String vertexShaderContent = ""
                + "#version 150                          
"
                + "in float vIn;                         
" // <--
                + "out float vOut;                       
" // <--
                + "void main(){                          
"
                + "  vOut = vIn + 0.1f;                  
" // <--
                + "  gl_Position = vec4(vIn, 0, 0, 1);   
" // <--
                + "}";
        final int vshaderId = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
        GL20.glShaderSource(vshaderId, vertexShaderContent);
        GL20.glCompileShader(vshaderId);
        checkCompileErrors(vshaderId);

        final String fragmentShaderContent = ""
                + "#version 150                          
"
                + "out vec4 outColor;                    
"
                + "void main(){                          
"
                + "  outColor = vec4(1, 0, 0, 1);        
"
                + "}";
        final int fshaderId = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
        GL20.glShaderSource(fshaderId, fragmentShaderContent);
        GL20.glCompileShader(fshaderId);
        checkCompileErrors(fshaderId);

        final int programId = GL20.glCreateProgram();
        GL20.glAttachShader(programId, vshaderId);
        GL20.glAttachShader(programId, fshaderId);

        GL30.glTransformFeedbackVaryings(programId, new String[] { "vOut" }, GL30.GL_INTERLEAVED_ATTRIBS); // <--

        GL20.glLinkProgram(programId);
        checkLinkErrors(programId);
        GL20.glUseProgram(programId);


        secondVao = GL30.glGenVertexArrays();
        GL30.glBindVertexArray(secondVao);

        secondBuffer = GL15.glGenBuffers();

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, secondBuffer);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, argumentCount * floatSizeInBytes, GL15.GL_STREAM_DRAW);

        GL30.glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer, 0, argumentCount * floatSizeInBytes);

        final int inputvert = GL20.glGetAttribLocation(programId, "vIn"); // <--
        GL20.glEnableVertexAttribArray(inputvert); // <--
        GL20.glVertexAttribPointer(inputvert, 1, GL11.GL_FLOAT, false, 4, 0); // <--


        firstVao = GL30.glGenVertexArrays();
        GL30.glBindVertexArray(firstVao);


        final FloatBuffer dataBuffer = BufferUtils.createFloatBuffer(argumentCount);

        System.out.println("-- filling buffer");
        for (int i = 0; i < argumentCount; i++) {
            final float value = (float) (((i) / (double) argumentCount) * 0.5 - 0.5);
            System.out.println(value);
            dataBuffer.put(value);
        }
        dataBuffer.rewind();
        System.out.println("-- finished initialization
");


        firstBuffer = GL15.glGenBuffers();

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, firstBuffer);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, dataBuffer, GL15.GL_STREAM_DRAW);

        GL20.glEnableVertexAttribArray(inputvert);
        GL20.glVertexAttribPointer(inputvert, 1, GL11.GL_FLOAT, false, 4, 0);

        testStepByStep();
    }


    private void testStepByStep() {

        /** run 1 **/
        GL30.glBindBufferRange(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer, 0, argumentCount * floatSizeInBytes);
        GL30.glBeginTransformFeedback(GL11.GL_POINTS);
        GL30.glBindVertexArray(firstVao);
        GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
        GL30.glEndTransformFeedback();


        FloatBuffer result = BufferUtils.createFloatBuffer(argumentCount);
        GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
        System.out.println("-- data in transform feedback buffer: ");
        for (int i = 0; i < result.capacity(); i++)
            System.out.println(result.get(i));
        System.out.println("-- end, preparing second run..
");

        /** run 2 **/
        GL30.glBindBufferRange(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, firstBuffer, 0, argumentCount * floatSizeInBytes);
        GL30.glBeginTransformFeedback(GL11.GL_POINTS);
        GL30.glBindVertexArray(secondVao);
        GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
        GL30.glEndTransformFeedback();

        result = BufferUtils.createFloatBuffer(argumentCount);
        GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
        System.out.println("-- data in transform feedback buffer after round 2: ");
        for (int i = 0; i < result.capacity(); i++)
            System.out.println(result.get(i));
        System.out.println("-- end, preparing third run..
");

        /** run 3 **/
        GL30.glBindBufferRange(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, secondBuffer, 0, argumentCount * floatSizeInBytes);
        GL30.glBeginTransformFeedback(GL11.GL_POINTS);
        GL30.glBindVertexArray(firstVao);
        GL11.glDrawArrays(GL11.GL_POINTS, 0, argumentCount);
        GL30.glEndTransformFeedback();

        result = BufferUtils.createFloatBuffer(argumentCount);
        GL15.glGetBufferSubData(GL30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, result);
        System.out.println("-- data in transform feedback buffer after round 3: ");
        for (int i = 0; i < result.capacity(); i++)
            System.out.println(result.get(i));
        System.out.println("-- end.
");
    }


    private void checkCompileErrors(final int shaderId) {

        if (GL_FALSE == glGetShaderi(shaderId, GL_COMPILE_STATUS)) {
            final int length = glGetShaderi(shaderId, GL_INFO_LOG_LENGTH);
            final String log = glGetShaderInfoLog(shaderId, length);
            throw new RuntimeException(log);
        }
    }


    private void checkLinkErrors(final int programId) {

        if (GL_FALSE == glGetProgrami(programId, GL_LINK_STATUS)) {
            final int length = glGetProgrami(programId, GL_INFO_LOG_LENGTH);
            final String log = glGetProgramInfoLog(programId, length);
            throw new RuntimeException(log);
        }
    }


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

        try {
            new TransformFeedbackPorting();
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }
}

Gruß
Fancy

Och man… ich bin so blöd ^^ danke dir :slight_smile:
klar, wenn ich den anderen buffer dann zum rendern benutze, müssen die attribute ja auch gesetzt sein… ._.
wie war das, den wald vor lauter bäumen nicht sehen… ^^

Welche Grafikkarte hast du? Meine ist bei dem namen anscheinend tolerant ^^ aber ich änder das mal…

meinst du mit „opengl version angeben“ dieses ContextAttribs?
Und was genau bringt ein pixelFormat, den du anschließend sowieso nicht veränderst?

Getestet habe ich das gerade mit einer GTX 760 unter Linux mit dem open source Treiber. Das Verhalten ist aber auch korrekt, laut GLSL Specification ist input (und output) reserved for future use.

Genau, die OpenGL Version wird über die ContextAttribs angegeben. PixelFormat ist nur da weil Display.create das eben braucht. :wink:

Gruß
Fancy