OpenGl 3+: Kreis mit Shader zeichnen

********************Hallo,

nach längerer Zeit mache ich nun wieder etwas mit OpenGL. Dabei versuche ich mit Hilfe eines Shaders einen Kreis zu zeichnen. Konkret rendere ich ein Quadrat ohne Textur, auf dem dann im Shader ein Kreis gezeichnet werden soll.
Dabei ergeben sich folgende Probleme: Das Quadrat ist ein Rechteck und der Kreis wird nicht gezeichnet, je nach Einstellung ist das „Quadrat“ gar nicht zu sehen oder vollständig mit Farbe ausgefüllt. Das Ganze läuft in einem 2 dimensionalen raum mit einer orthogonalen Matrix und ohne Depth_Test.
Ich vermute das es an falsch übermittelten Textur-Koordinaten liegt, aber leider komme ich nicht auf den genauen Fehler, mehr dazu gleich im Code-Ausschnitt.

Hier die (wahrscheinlich) wichtigsten Code-Abschnitte:
Das VAO/VBO für das Quadrat:

List<Float> data = new ArrayList<Float>();
		List<Attribute> attribs = new ArrayList<>();
		
		// Position                          // Texture 
		data.add(-0.5F); data.add(-0.5F);    data.add(0F); data.add(0F);
		data.add(+0.5F); data.add(-0.5F);    data.add(1F); data.add(0F);
		data.add(-0.5F); data.add(+0.5F);    data.add(0F); data.add(1F);
		data.add(+0.5F); data.add(+0.5F);    data.add(1F); data.add(1F);
		
                                                   //location, elements, stride, offset --> glVertexAttribPointer(location, elements, GL_FLOAT, false, stride, offset);
		attribs.add(new Attribute(0, 2, Float.SIZE/2/*-> /8 für bytes und dann *4*/, 0));
		attribs.add(new Attribute(1, 2, Float.SIZE/2, Float.SIZE/4));
		
		texturedQuad = new VAO(GL_TRIANGLE_STRIP, data.size());
		texturedQuad.addVBO(new VBO(data, attribs), true);

Der Fragment-Shader: (Der Vertex Shader macht nichts großartiges, bei Bedarf findet man ihn aber im KSKB)

#version 330

in vec2 texCoord;
out vec4 outputColor;

uniform vec4 colour;

void main()
{
	float len = length((texCoord - vec2(0.5, 0.5)));
	if( len > 0.4 && len < 0.6 ) {
		outputColor = colour;
	}
	else {
		outputColor = vec4(0, 0, 0, 0);
	}
		
	if(texCoord.x == 0 && texCoord.y == 0) {
		outputColor = vec4(1, 1, 1, 1);          //Hier wird das ganze "rechteckig Quadrat" weiß, verändere ich auch nur eine der beiden Koordinaten zu etwas anderem als 0 tritt dies nicht ein, daher denke ich, dass es an den Texture-Coordinates liegt
	}
}

*** EDIT: ***
Ach ja, die Idee wie der Kreis gezeihnet werden soll ist Folgende: Jeeder Pixel der von der Mitte (0.5 |0.5) den Abstand des Radiuses hat (ebenfalss 0.5) wird mit der angegeben Farbe eingefärbt, alle anderen bleiben schwarz/transparent. Der Abstand wird über einen Vektor ermittelt.
EDIT ENDE

Zusätzlich ist hier noch die Kopie meines Eclipse-Projekts als KSKSB: Link

Ich würde mich freuen wenn ihr mir helfen könntet :slight_smile:

MfG,
~Oneric

Float.SIZE / 8 * 4, obwohl du jeweils 2 floats in den teilen hast? sicher dass das so stimmt?

Ich kann dein kskb leider nicht ausführen, “no lwjgl in path bla bla” obwohl der build eigentlich richtig eingestellt ist…

Es kann sein, dass du die natives neu einbinden musst. Die liegen im Ordner lib/native.

Insgesamt muss die ist die Position des nächsten Attributs glichen Typs ja 4 Floats von der Startposition entfernt. (2 * Position + 2* Texture). Ich hatte, dass vorher hier nachgeschaut und es sollte eigentlich passen, allerdings habe ich es bisher auch noch nicht anders ausprobiert :stumm:, am Besten mache ich das gleich mal.

Also wenn ich den stride zu Float.SIZE/8 * 2 ändere, ist das Objekt nicht einmal mehr Viereckig, da sich die Vertex und Texture Koordinaten mischen, der stride sollte also so schon stimmen. :slight_smile:

MfG,
~Oneric

“Es kann sein, dass du die natives neu einbinden musst. Die liegen im Ordner lib/native.”

Hab ich ja… aber ging trotzdem nicht…

Moin,

ich habe mir das gerade mal versucht anzusehen. Aber ich kann kein RAR öffnen (unfrei) und in den 36 MB habe ich dann leider auch kein KSKB gefunden.

Ein KSKB zu Deinem Problem sollte etwa so aussehen:



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_FALSE;
import static org.lwjgl.opengl.GL11.GL_FLOAT;
import static org.lwjgl.opengl.GL11.GL_TRIANGLE_STRIP;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_SHORT;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glDrawElements;
import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS;
import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER;
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.GL_VERTEX_SHADER;
import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glCompileShader;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glCreateShader;
import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
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.GL20.glLinkProgram;
import static org.lwjgl.opengl.GL20.glShaderSource;
import static org.lwjgl.opengl.GL20.glUseProgram;
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glDeleteVertexArrays;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;

import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

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.PixelFormat;


public final class GL33Circle {

    private static final int WIDTH = 1200;
    private static final int HEIGHT = 800;

    private static final int GL_MAJOR_VERSION = 3;
    private static final int GL_MINOR_VERSION = 3;

    private static final int VERTEX_COORD_LOCATION = 0;
    private static final int TEXTURE_COORD_LOCATION = 1;

    private static final String VERTEX_SHADER = ""

            + "#version 330                                                      
"
            + "                                                                  
"
            + "layout(location = " + VERTEX_COORD_LOCATION + ") in vec3 v;       
"
            + "layout(location = " + TEXTURE_COORD_LOCATION + ") in vec2 vt;     
"
            + "                                                                  
"
            + "out vec2 fvt;                                                     
"
            + "                                                                  
"
            + "void main() {                                                     
"
            + "                                                                  
"
            + "    fvt = vt;                                                     
"
            + "    gl_Position = vec4(v.xyz * 0.5, 1);                           
"
            + "                                                                  
"
            + "}                                                                 
";

    private static final String FRAGMENT_SHADER = ""

            + "#version 330                                                      
"
            + "                                                                  
"
            + "in vec2 fvt;                                                      
"
            + "                                                                  
"
            + "out vec4 color;                                                   
"
            + "                                                                  
"
            + "void main() {                                                     
"
            + "                                                                  
"
            + "    float len = length(fvt - vec2(0.5, 0.5));                     
"
            + "                                                                  
"
            + "    if(len < 0.5)                                                 
"
            + "        color = vec4(1, 1, 1, 1);                                 
"
            + "                                                                  
"
            + "    else                                                          
"
            + "        color = vec4(1, 0, 0, 1);                                 
"
            + "                                                                  
"
            + "}                                                                 
";

    private static final short[] QUAD_IBO = new short[] { 1, 2, 0, 3 };

    // x, y, z, s, t
    private static final float[] QUAD_VBO = new float[] {

            -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
            +1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
            +1.0f, +1.0f, 0.0f, 1.0f, 1.0f,
            -1.0f, +1.0f, 0.0f, 0.0f, 1.0f,

    };


    private int handleVAO;
    private int handleIBO;
    private int handleVBO;


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

        final DisplayMode displayMode = new DisplayMode(WIDTH, HEIGHT);
        final PixelFormat pixelFormat = new PixelFormat();
        final ContextAttribs contextAttribs = new ContextAttribs(GL_MAJOR_VERSION, GL_MINOR_VERSION).withProfileCore(true);

        new GL33Circle().run(displayMode, pixelFormat, contextAttribs);

    }


    void run(final DisplayMode displayMode, final PixelFormat pixelFormat, final ContextAttribs contextAttribs) throws LWJGLException {

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

        glInit();

        while (!Display.isCloseRequested()) {

            glDisplay();
            Display.update();

        }

        glDispose();
        Display.destroy();

    }


    private void glInit() {

        glInitVAO();
        glInitIBO();
        glInitVBO();
        glInitShader();

    }


    private void glInitVAO() {

        handleVAO = glGenVertexArrays();
        glBindVertexArray(handleVAO);

    }


    private void glInitIBO() {

        final ShortBuffer buffer = BufferUtils.createShortBuffer(QUAD_IBO.length);
        buffer.put(QUAD_IBO);
        buffer.flip();

        handleIBO = glGenBuffers();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handleIBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

    }


    private void glInitVBO() {

        final FloatBuffer buffer = BufferUtils.createFloatBuffer(QUAD_VBO.length);
        buffer.put(QUAD_VBO);
        buffer.flip();

        handleVBO = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, handleVBO);
        glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

        glEnableVertexAttribArray(VERTEX_COORD_LOCATION);
        glVertexAttribPointer(VERTEX_COORD_LOCATION, 3, GL_FLOAT, false, Float.BYTES * 5, 0);

        glEnableVertexAttribArray(TEXTURE_COORD_LOCATION);
        glVertexAttribPointer(TEXTURE_COORD_LOCATION, 2, GL_FLOAT, false, Float.BYTES * 5, Float.BYTES * 3);

    }


    private void glInitShader() {

        final int vs = buildShader(GL_VERTEX_SHADER, VERTEX_SHADER);
        final int fs = buildShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER);
        final int p = buildProgram(vs, fs);
        glUseProgram(p);

    }


    private int buildShader(final int type, final String source) {

        final int handle = glCreateShader(type);

        glShaderSource(handle, source);
        glCompileShader(handle);

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

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

            throw new RuntimeException(log);

        }

        return handle;

    }


    private int buildProgram(final int... shaders) {

        final int handle = glCreateProgram();

        for (final int shader : shaders)
            glAttachShader(handle, shader);

        glLinkProgram(handle);

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

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

            throw new RuntimeException(log);

        }

        return handle;

    }


    private void glDisplay() {

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glDrawElements(GL_TRIANGLE_STRIP, QUAD_IBO.length, GL_UNSIGNED_SHORT, 0);

    }


    private void glDispose() {

        glDeleteBuffers(handleVBO);
        glDeleteBuffers(handleIBO);
        glDeleteVertexArrays(handleVAO);

    }


}

Gruß
Fancy

So, ich habe das Ganze noch einmal überarbeitet und 3 überflüssige Klassen rausgeschmissen. Außerdem liegen die Shader nun als String in der Hauptklasse vor. Aber in eine einzige Datei/Klasse werde ich das wohl nicht bekommen ohne das Alles unübersichtlich wird.

Die Natives habe ich auch noch mal überprüft, in Eclipse wurden noch auf die LWJGL-Natives aus dem Original-Projekt verlinkt, ich habe die Verlinkung auf das KSKB-Projekt geändert.

Hier ist mein Eclipse-Projekt also noch mal in einer stärker minimalisierten Form und dieses Mal auch als Zip-Archiv. :slight_smile:
Die Hauptklasse ist src\glCircleKSKB\src\Main.java, die Libaries und die Natives befinden sich in lib.

MfG,
~Oneric

ok jetzt läuft es… ich bin aber zu blöd den fehler zu finden… ich denke
das kann fancy besser…

aber da wird auf jeden fall etwas falsch an die grafikkarte gesendet.
ich habe gerade mal versucht aus coordinates und position ein vec4 data zu machen,
alle daten quasi auf einmal zu schicken (nur ein attribute) und die eben erst im shader zu splitten… hat
auch nicht wirklich geklappt…

*** Edit ***

ich hab keine ahnung von layout qualifiers, aber das bei beiden attribitutes layout(location=0) steht kann doch nicht richtig sein, oder?

*** Edit ***

Main Zeile 53, meinst du vielleicht out vec2 texCoord; statt out texCoord;

jetzt ist das bild schwarz… hmm…

Ja, das ist so schon einmal definitiv falsch :o, schnell mal ausbessern

Dieser fehlerhafte Übermittlung würde erklären, warum alle Texturen-Koordinaten „0“ zu sein scheinen.
Aber das Bild ist jetzt selbst dann komplett schwarz wenn ich die main-Methode des Fragment-Shaders auf outputColor = colour; reduziere, was davor immerhin funktioniert hat.
Ich habe jetzt noch nicht einmal eine Vermutung, woran das liegen könnte… :confused:

MfG,
~Oneric

ich leider auch nicht :frowning: ich hoffe jetzt auch auf fancy…

Mein KSKB zeigt doch genau das was Du eigentlich haben wolltest. Du hättest es nur vergleichen müßen.

Wie auch immer (nur das notwendigste korrigiert und unnötiges entfernt):



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_TRIANGLE_STRIP;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER;
import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER;
import glCircleKSKB.util.buffers.Attribute;
import glCircleKSKB.util.buffers.VAO;
import glCircleKSKB.util.buffers.VBO;
import glCircleKSKB.util.shader.Shader;
import glCircleKSKB.util.shader.ShaderProgramm;

import java.util.ArrayList;
import java.util.List;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.util.vector.Vector4f;


public class Main {


    public static final String shader_vert =
            "#version 330  									
" +
                    "  												
" +
                    "layout (location = 0) in vec2 position;  		
" +
                    "layout (location = 1) in vec2 coordinates;  	
" + // <------------------
                    "  												
" +
                    "out vec2 texCoord;  						    
" + // <------------------
                    " 					 							
" +
                    "void main()  									
" +
                    "{  											
" +
                    "	gl_Position = vec4(position.xy, 0, 1);      
" + // <------------------
                    "	texCoord = coordinates;  					
" +
                    "}  											";


    public static final String shader_frag =
            "#version 330  									
" +
                    "  												
" +
                    "in vec2 texCoord;  							
" +
                    "out vec4 outputColor;  						
" +
                    "  												
" +
                    "uniform vec4 colour;  							
" +
                    " 					 							
" +
                    "void main()  									
" +
                    "{  											
" +
                    "	float len = length((texCoord - vec2(0.5, 0.5)));
" +
                    "	if( len > 0.4 && len < 0.6 ) {				
" +
                    "		outputColor = colour;					
" +
                    "	}											
" +
                    "	else {										
" +
                    "	outputColor = vec4(0, 0, 0, 0);				
" +
                    "	}											
" +
                    "												
" +
                    "	if(texCoord.x == 0 && texCoord.y == 0) {	
" +
                    "		outputColor = vec4(1, 1, 1, 1);			
" +
                    "	}											
" +
                    "}												";


    public static ShaderProgramm shCircle;
    public static VAO texturedQuad;


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

        setUpDisplay();

        initShaders();
        loadModels();

        while (!Display.isCloseRequested()) {

            render();

            Display.update();

        }

        dispose();

    }


    private static void dispose() {

        shCircle.dispose();
        texturedQuad.dispose();

        Display.destroy();

    }


    private static void loadModels() {

        final List<Float> data = new ArrayList<Float>();
        final List<Attribute> attribs = new ArrayList<>();

        // Position                          // Texture 
        data.add(-0.5F); data.add(-0.5F);    data.add(0F); data.add(0F);
        data.add(+0.5F); data.add(-0.5F);    data.add(1F); data.add(0F);
        data.add(-0.5F); data.add(+0.5F);    data.add(0F); data.add(1F);
        data.add(+0.5F); data.add(+0.5F);    data.add(1F); data.add(1F);

        attribs.add(new Attribute(0, 2, Float.SIZE / 2/* -> /8 f�r bytes und dann *4 */, 0));
        attribs.add(new Attribute(1, 2, Float.SIZE / 2, Float.SIZE / 4));

        texturedQuad = new VAO(GL_TRIANGLE_STRIP, data.size() / 4); // <-------------------------------------
        texturedQuad.addVBO(new VBO(data, attribs), true);

    }


    private static void initShaders() {

        final Shader shCircleVert = new Shader();
        final Shader shCircleFrag = new Shader();

        if (!shCircleVert.loadShaderFromSource(shader_vert, GL_VERTEX_SHADER))
            throw new RuntimeException("vertex shader error");

        if (!shCircleFrag.loadShaderFromSource(shader_frag, GL_FRAGMENT_SHADER))
            throw new RuntimeException("fragment shader error");

        shCircle = new ShaderProgramm();
        shCircle.createProgramm();
        shCircle.addShaderToProgramm(shCircleFrag);
        shCircle.addShaderToProgramm(shCircleVert);

        if (!shCircle.linkProgramm())
            throw new RuntimeException("link error");

    }


    private static void setUpDisplay() {

        try {

            Display.setDisplayMode(new DisplayMode(800, 500));
            Display.setVSyncEnabled(true);

            final ContextAttribs attribs = new ContextAttribs(3, 3).withProfileCore(true);
            Display.create(new PixelFormat(), attribs);

        } catch (final LWJGLException e) {

            throw new RuntimeException("The display wasn't initialised correctly. :(");

        }
    }


    private static void render()
    {

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        shCircle.useProgramm();
        shCircle.setUniform("colour", new Vector4f(0.2F, 1F, 0.2F, 1F));
        texturedQuad.render();

    }


    public static interface Disposable {

        public void dispose();

    }


}```

Gruß
Fancy

Danke :D, ich habe jetzt noch ein paar Kleinigkeiten geändert (mit orthoMatrix, Quadrat etwas vergrößert) und jetzt funktioniert alles wunderbar.
Die Fehler mit der doppelt belegten „0“-location und dem fehlenden vec2 wären zwar wirklich vermeidbar, gewesen, aber ohne eure Hilfe hätte ich das wohl noch eine ganze Weile übershehen.

Hier ein Bild vom Ergebnis, sowie den fertigen Shader-Code:

Vertex:

#version 330

layout (location = 0) in vec2 position;
layout (location = 1) in vec2 coordinates;

uniform mat4 orthoMatrix;

out vec2 texCoord;

void main()
{
	gl_Position = orthoMatrix*vec4(position, 0.0, 1.0);
	//gl_Position = vec4(position.xy, 0, 1);
	texCoord = coordinates;
}

Fragment:

#version 330

in vec2 texCoord;
out vec4 outputColor;

uniform vec4 colour;

float thickness = 0.008;

void main()
{
	float len = length((texCoord - vec2(0.5, 0.5)));
	if( len > (0.5 - thickness) && len <= 0.5 ) {
		outputColor = colour;
	}
	else {
		outputColor = vec4(0, 0, 0, 0);
	}
        
        //Falls man den Mittelpunkt einzeichnen will
        //if(texCoord.x >= (0.5 - thickness) && texCoord.x <= (0.5 + thickness) && texCoord.y >= (0.5 - thickness) && texCoord.y <= (0.5 + thickness) ) {
	//	outputColor = vec4(1, 1, 1, 1);
	//}
}

Noch einmal danke für eure Hilfe !
MfG,
~Oneric