OpenGL 4: Mehrere Dreiecke zeichnen, um ein Quadrat zu zeichen



  • #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    #include <stdio.h>
    
    int main () {
        // start GL context and O/S window using the GLFW helper library
        if (!glfwInit ()) {
            fprintf (stderr, "ERROR: could not start GLFW3\n");
            return 1;
        }
    
        // uncomment these lines if on Apple OS X
        glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2);
        glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
        glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
        GLFWwindow* window = glfwCreateWindow (640, 480, "OpenGL Test", NULL, NULL);
        if (!window) {
            fprintf (stderr, "ERROR: could not open window with GLFW3\n");
            glfwTerminate();
            return 1;
        }
        glfwMakeContextCurrent (window);
    
        // start GLEW extension handler
        glewExperimental = GL_TRUE;
        glewInit ();
    
        // get version info
        const GLubyte* renderer = glGetString (GL_RENDERER); // get renderer string
        const GLubyte* version = glGetString (GL_VERSION); // version as a string
        printf ("Renderer: %s\n", renderer);
        printf ("OpenGL version supported %s\n", version);
    
        // tell GL to only draw onto a pixel if the shape is closer to the viewer
        glEnable (GL_DEPTH_TEST); // enable depth-testing
        glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
    
        /* OTHER STUFF GOES HERE NEXT */
    
        float points[] = {
            0.0f,  0.5f,  0.0f,
            0.5f, -0.5f,  0.0f,
            -0.5f, -0.5f,  0.0f,
            -0.5f,  0.5f,  0.0f,
            0.0f, 0.5f,  0.0f,
            -0.5f, -0.5f,  0.0f,
            0.0f,  0.5f,  0.0f,
            0.5f, 0.5f,  0.0f,
            0.5f, -0.5f,  0.0f
        };
    
        // 2-Koordinaten-Mengen, um aus dem Dreieck mit zwei weiteren Dreiecken, ein Quadrat herzustellen.
        float points2[] = {
            -0.5f,  0.5f,  0.0f,
            0.0f, 0.5f,  0.0f,
            -0.5f, -0.5f,  0.0f,
        };
    
        float points3[] = {
            0.0f,  0.5f,  0.0f,
            0.5f, 0.5f,  0.0f,
            0.5f, -0.5f,  0.0f
        };
    
        GLuint vbo = 0;
        glGenBuffers (1, &vbo);
        glBindBuffer (GL_ARRAY_BUFFER, vbo);
        glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (float), points, GL_STATIC_DRAW);
    
        // Vertex-Buffer-Object für das zweite Dreieck. Das Dritte fehlt noch.
        GLuint vbo2 = 1;
        glGenBuffers (1, &vbo);
        glBindBuffer (GL_ARRAY_BUFFER, vbo2);
        glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (float), points, GL_STATIC_DRAW);
    
        GLuint vao = 0;
        glGenVertexArrays (1, &vao);
        glBindVertexArray (vao);
        glEnableVertexAttribArray (0);
        glBindBuffer (GL_ARRAY_BUFFER, vbo);
        glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
    
        // Vertex-Attribute-Object des zweiten Dreiecks. Vom dritten fehlt es noch.
        GLuint vao2 = 0;
        glGenVertexArrays (1, &vao2);
        glBindVertexArray (vao2);
        glEnableVertexAttribArray (0);
        glBindBuffer (GL_ARRAY_BUFFER, vbo2);
        glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
    
        const char* vertex_shader =
        "#version 400\n"
        "in vec3 vp;"
        "void main () {"
        "  gl_Position = vec4 (vp.x + 0.5, vp.y, vp.z, 1.0);"
        "}";
    
        const char* fragment_shader =
        "#version 400\n"
        "out vec4 frag_colour;"
        "void main () {"
        "  frag_colour = vec4 (0.529, 0.808, 0.980, 1.0);"
        "}";
    
        GLuint vs = glCreateShader (GL_VERTEX_SHADER);
        glShaderSource (vs, 1, &vertex_shader, NULL);
        glCompileShader (vs);
        GLuint fs = glCreateShader (GL_FRAGMENT_SHADER);
        glShaderSource (fs, 1, &fragment_shader, NULL);
        glCompileShader (fs);
    
        GLuint shader_programme = glCreateProgram ();
        glAttachShader (shader_programme, fs);
        glAttachShader (shader_programme, vs);
        glLinkProgram (shader_programme);
    
        while (!glfwWindowShouldClose (window)) {
            // wipe the drawing surface clear
            glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glUseProgram (shader_programme);
            glBindVertexArray (vao);
            glBindVertexArray (vao2);
            // draw points 0-3 from the currently bound VAO with current in-use shader
            glDrawArrays (GL_TRIANGLES, 0, 3);
            // Hier mein Versuch das zweite Dreick zu rendern.
            // Ich schätze mal, man muss beim Index 3 anfangen, da die ersten Drei 0-2 schon besetzt sind.
            glDrawArrays (GL_TRIANGLES, 3, 3);
            // update other events like input handling
            glfwPollEvents ();
            // put the stuff we've been drawing onto the display
            glfwSwapBuffers (window);
        }
    
        // close GL context and any other GLFW resources
        glfwTerminate();
        return 0;
    }
    

    Ich möchte aus den Dreieck, der durch den Array points definiert wird ein Quadrat mit Hilfe zweier anderer Dreiecke erstellen. Dazu müssen die zwei anderen Dreiecke gezeichnet werden, aber ich scheiterte an diesem Vorhaben. Der Code ist kommentiert. Hab beim zweiten Dreieck ein VBO und ein VAO erstellt. Beim dritten werde ich es noch machen sobald ich das zweite gezeichnet habe.



  • Ist denn OpenGL nicht durch Vulkan ersetzt worden oder kurz davor?



  • Vulkan ist kein Ersatz für OpenGL. Die Vorteile von Vulkan werden durch mehr Verantwortung und sehr viel mehr Arbeit erkauft. Und es gibt nur wenige die von den Vorteilen profitieren.



  • Ich habe mich mit dem Thema vor geraumer Zeit befasst. Es sollte eine Funktionssammlung zum Darstallen von Rechtecken dabei entstehen. Vielleicht kann sie etwas zur Loesung beitragen:

    C_Sprite_Core.h

    /** @brief		2D-Objekte mit OpenGL darstellen
     *
     *  @details	Zeichnet ein Quadrat mit Textur in ein Fenster mit OpenGL-Kontext (C++14)
     *
     *  @author		Uriens The Gray
     *
     *  @version	0.1
     *
     *  @date		11.10.2015(Ersterstellung)
     *
     *  @pre		Setzt auf C_System_Core auf.
     *
     *  @copyright	GNU Public License v3 (https://www.gnu.org/licenses/gpl.html) (See also http://copyleft.org/guide/)
     *
     */
    
    // Praeprozessor (Guard)
    //----------------------
    #ifndef C_SPRITE_CORE_H
    #define C_SPRITE_CORE_H
    
    // Benoetigte Header-Datei(en)
    // ---------------------------
    #include	<array>				// STL Container-Klasse Array
    #include	"E_Sprite_Core.h"	// Enumeratoren der Klasse
    #include	"glm/glm.hpp"		// GLM Core
    #include	"SDL2/SDL.h"		// SDL2
    
    // Klassendeklaration
    // ------------------
    class	C_Sprite_Core	{
    
    	// Schnittstelle
    	// -------------
    	public:
    
    		/**	@brief	Core: Konstruktor
    		 *
    		 *	Der Konstruktor startet das Programm ...
    		 *
    		 */
    						C_Sprite_Core	();
    
    		/**	@brief	Core: Destruktor
    		 *
    		 *	Der Destruktor beendet das Programm ...
    		 *
    		 */
    						~C_Sprite_Core	();
    
    		/**	@brief	Core: Initialisator
    		 *
    		 *	Stellt wichtige Variablen ein.
    		 *	Erzeugt das Shader-Programm.
    		 *
    		 *	@return	bool	Liefert TRUE wenn die Initialisierung erfolgreich war, FALSE, wenn es dabei einen Fehler gab.
    		 *
    		 */
    		static	bool	Init			();
    
    		/**	@brief	Sprite: Zeichnet ein Sprite auf den Bildschirm
    		 *
    		 *	@param	Sprite_Core_Target_s &target	- Zeiger auf Struktur mit den benoetigten Daten
    		 *
    		 *	@return	bool							- Liefert TRUE bei Erfolg.
    		 *
    		 */
    		static	bool	Draw			(const Sprite_Core_Target_s &target);
    
    	// Klasseninterna
    	private:
    
    		// Benoetigte (interne) Variablen
    		// ----------------------------
    		static	struct	Sprite_Core_s	{
    			std::array<float, 8>	vertices;
    			std::array<float, 8>	texels;
    			std::array<Uint8, 6>	elements;
    			Uint32					ProgramID;
    			Uint32					VAO;
    			Uint32					VBOvertex;
    			Uint32					VBOtexel;
    			Uint32					EBO;
    			Uint32					model;
    			Uint32					projection;
    			Uint32					texture;
    			Uint32					colors;
    			glm::mat4				orthograph;
    		}	static	SpCore;
    
    // Ende der Klassendeklaration, instanziert ein Objekt der Klasse
    // --------------------------------------------------------------
    }	static	Sprite;
    
    // Praeprozessor (Guard)
    //----------------------
    #endif // C_SPRITE_CORE_H
    

    C_Sprite_Core.cpp

    // Beschreibung: Konstruktor und Destruktor fuer C_Sprite_Core.h
    //               Die Funktionen und Aufgaben werden im Header (C_Sprite_Core.h) beschrieben
    // Author      : Uriens The Gray
    // Version     : 0.1
    // Datum       : 11.04.2016 (Ersterstellung)
    // Copyright   : GNU Public License v3 (https://www.gnu.org/licenses/gpl.html)
    //               (See also http://copyleft.org/guide/)
    
    // Benoetigte Header-Datei(en)
    // ---------------------------
    #include	"C_Sprite_Core.h"	// KLassendeklaration
    #include	"glad/glad.h"		// OpenGL-Loader
    
    // Konstruktor
    // -----------
    C_Sprite_Core::C_Sprite_Core	()	{
    
    	// Werte setzen
    	SpCore.vertices		= {-1.0f, 1.0f, 1.0f, 1.0f,-1.0f,-1.0f, 1.0f,-1.0f};
    	SpCore.texels		= { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f};
    	SpCore.elements		= {0, 1, 2, 3, 2, 1};
    	SpCore.ProgramID	= 0;
    	SpCore.VAO			= 0;
    	SpCore.VBOvertex	= 0;
    	SpCore.VBOtexel		= 0;
    	SpCore.EBO			= 0;
    	SpCore.model		= 0;
    	SpCore.projection	= 0;
    	SpCore.texture		= 0;
    	SpCore.colors		= 0;
    	SpCore.orthograph	= glm::ortho(0.0f, float(System.GetConfigValue(Config_VSScreenWidth))
    									, float(System.GetConfigValue(Config_VSScreenHeight)), 0.0f);
    }
    
    // Destruktor
    // ----------
    C_Sprite_Core::~C_Sprite_Core	()	{
    
    	glDeleteProgram(SpCore.ProgramID);
    	glDeleteVertexArrays(1, &SpCore.VAO);
    	glDeleteBuffers(1, &SpCore.VBOvertex);
    	glDeleteBuffers(1, &SpCore.VBOtexel);
    }
    

    F_Sprite_Core_Init.cpp

    // Beschreibung: Initialisator fuer 2D-Objekte in OpenGL
    //               Die Funktionen und Aufgaben werden im Header (C_Sprite_Core.h) beschrieben
    // Author      : Uriens The Gray
    // Version     : 0.1
    // Datum       : 11.04.2016 (Ersterstellung)
    // Copyright   : GNU Public License v3 (https://www.gnu.org/licenses/gpl.html)
    //               (See also http://copyleft.org/guide/)
    
    // Benoetigte Header-Datei(en)
    // ---------------------------
    #include	"C_Sprite_Core.h"	// Klassendefinition
    #include	"C_System_Core.h"	// fuer zusaetzliche Funktionen
    #include	"glad/glad.h"		// OpenGL-Loader
    
    /**	@brief	Core: Initialisator
     */
    bool	C_Sprite_Core::Init	()	{
    
    	// Shader-Programm erzeugen
    	if (!System.CreateShaderProgramm("Sprite", SpCore.ProgramID))	{
    		System.SendErrorMessage("Shader-Programm", "Failed", "C_Sprite_Core", "Init");
    		return false;
    	}
    
    	// Positionen im Shaderprogramm einsammlen
    	SpCore.model		= glGetUniformLocation(SpCore.ProgramID, "model");
    	SpCore.texture		= glGetUniformLocation(SpCore.ProgramID, "image");
    	SpCore.projection	= glGetUniformLocation(SpCore.ProgramID, "projection");
    	SpCore.colors		= glGetUniformLocation(SpCore.ProgramID, "SpriteColors");
    
    	// Konstanten uebergeben
    	glUseProgram(SpCore.ProgramID);
    	glUniformMatrix4fv(SpCore.projection, 1, GL_FALSE, glm::value_ptr(SpCore.orthograph));
    	glUseProgram(0);
    
    	// Quadrat auf Graka speichern
    	// Vertex Array Object
    	glGenVertexArrays(1, &SpCore.VAO);
    	glBindVertexArray(SpCore.VAO);
    	// Vertex Buffer Object fuer Vertices
    	glGenBuffers(1, &SpCore.VBOvertex);
    	glBindBuffer(GL_ARRAY_BUFFER, SpCore.VBOvertex);
    	glBufferData(GL_ARRAY_BUFFER, SpCore.vertices.size() * sizeof(float), &SpCore.vertices, GL_STATIC_DRAW);
    	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)nullptr);
    	glEnableVertexAttribArray(0);
    	// Vertex Buffer Object fuer Texels
    	glGenBuffers(1, &SpCore.VBOtexel);
    	glBindBuffer(GL_ARRAY_BUFFER, SpCore.VBOtexel);
    	glBufferData(GL_ARRAY_BUFFER, SpCore.texels.size() * sizeof(float), &SpCore.texels, GL_DYNAMIC_DRAW);
    	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)nullptr);
    	glEnableVertexAttribArray(1);
    	// Element Buffer Objekt
    	glGenBuffers(1, &SpCore.EBO);
    	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SpCore.EBO);
    	glBufferData(GL_ELEMENT_ARRAY_BUFFER, SpCore.elements.size() * sizeof(Uint8), &SpCore.elements, GL_STATIC_DRAW);
    	// Puffer wieder entbinden
    	glBindBuffer(GL_ARRAY_BUFFER, 0);
    	glBindVertexArray(0);
    
    	// Reucksprung
    	return true;
    }
    

    F_Sprite_Core_Draw.cpp

    // Beschreibung: Zeichnet ein Quadrat mit Textur in ein Fenster mit OpenGL-Kontext (C++14)
    //               Die Funktionen und Aufgaben werden im Header (C_Sprite_Core.h) beschrieben
    // Author      : Uriens The Gray
    // Version     : 0.1
    // Datum       : 12.04.2016 (Ersterstellung)
    // Copyright   : GNU Public License v3 (https://www.gnu.org/licenses/gpl.html)
    //               (See also http://copyleft.org/guide/)
    
    // Benoetigte Header-Datei(en)
    // ---------------------------
    #include	"C_Sprite_Core.h"	// Klassendeklaration
    #include	"C_System_Core.h"	// System_Core
    #include	"E_System_Core.h"	// Enumeratoren aus System_Core
    #include	"glad/glad.h"		// OpenGL-Loader
    
    /**	@brief	Sprite: Zeichnet ein Sprite auf den Bildschirm
     */
    bool	C_Sprite_Core::Draw	(const Sprite_Core_Target_s &target)	{
    
    	// Pruefungen
    	if (target.Texture == 0)	{
    		System.SendErrorMessage("No valid Texture", "Failed", "C_Sprite_Core", "Draw");
    		return false;
    	}
    
    	// Neue Texturkoordinaten an Graka schicken
    	glBindBuffer(GL_ARRAY_BUFFER, SpCore.VBOtexel);
    	glBufferSubData(GL_ARRAY_BUFFER, 0, SpCore.texels.size() * sizeof(float), &target.Texels);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    	// Sprite transformieren
    	glm::mat4 model;
    	// Position
    	model = glm::translate(model, glm::vec3(target.Position.x, target.Position.y, target.Position.z));
    	// Rotation
    	model = glm::rotate(model, glm::radians(target.Size.z), glm::vec3(0.0f, 0.0f, 1.0f));
    	// Groesse
    	model = glm::scale(model, glm::vec3(float(target.Size.x / 2), float(target.Size.y / 2), 1.0f));
    
    	// Daten uebertragen
    	// Shader aktivieren
    	glUseProgram(SpCore.ProgramID);
    	// Textur aktivieren
    	glActiveTexture(GL_TEXTURE0);
    	glBindTexture(GL_TEXTURE_2D, target.Texture);
    	glUniform1i(SpCore.texture, 0);
    	// Sprite-Matrix uebertragen
    	glUniformMatrix4fv(SpCore.model, 1, GL_FALSE, glm::value_ptr(model));
    	//  Farbe uebergeben
    	glUniform4f(SpCore.colors, target.Color.x, target.Color.y, target.Color.z, target.Color.w);
    
    	// Sprite zeichnen
    	glBindVertexArray(SpCore.VAO);
    	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
    	glBindVertexArray(0);
    
    	// Aufraeumen und Rueckkehr
    	glBindTexture(GL_TEXTURE_2D, 0);
    	glUseProgram(0);
    	return true;
    }
    

    D_Sprite_Core.h

    /**	@brief		2D-Objekte in OpenGL zeichnen
     *
     *	@details	Definiert die in C_Sprite_Core.h deklarierten Variablen
     *  			Geschrieben in C++14.
     *
     *	@author		Uriens The Gray
     *
     *	@version	0.1
     *
     *	@date		14.04.2016 (Ersterstellung)
     *
     *	@pre		Muss direkt nach C_Sprite_Core.h inkludiert werden !!
     *
     *	@copyright	GNU Public License v3 (https://www.gnu.org/licenses/gpl.html) (See also http://copyleft.org/guide/)
     *
     */
    
    // Praeprozessor (Guard)
    //----------------------
    #ifndef D_SPRITE_CORE_H
    #define D_SPRITE_CORE_H
    
    // Variablendefinition
    C_Sprite_Core::Sprite_Core_s	C_Sprite_Core::SpCore;	// Struktur Sprite_Core_s wird in C_Sprite_Core.h beschrieben
    
    // Praeprozessor (Guard)
    //----------------------
    #endif // D_SPRITE_CORE_H_INCLUDED
    

    E_Sprite_Core.h

    /**	@brief		Struktur fuer das Zeichnen von 2D-Objekten im OpenGL-Kontext
     *
     *	@author		Uriens The Gray
     *
     *	@version	0.1
     *
     *	@date		08.04.2016 (Ersterstellung)
     *
     *	@copyright	GNU Public License v3 (https://www.gnu.org/licenses/gpl.html) (See also http://copyleft.org/guide/)
     *
     */
    
    // Praeprozessor (Guard)
    //----------------------
    #ifndef E_SPRITE_CORE_H
    #define E_SPRITE_CORE_H
    
    // Benoetigte Header-Datei(en)
    // ---------------------------
    #include	<array>			// STL Container-Klasse Array
    #include	"glm/glm.hpp"	// GLM Core
    
    struct	Sprite_Core_Target_s	{
    	/// @brief		Sprite-ID
    	/// @details	Identificationsnummer des Sprites, steht dem Anwender frei zur Verfuegung.
    	Uint32					ID			= 0;
    	/// @brief		Position auf dem Bildschirm
    	/// @details	z wird indirekt fuer die Transparenz verwendet, hat keinen Einfluss auf die Darstellung
    	glm::vec3				Position	= {0.0f, 0.0f, 0.0f};
    	/// @brief		Groesse und Rotationswinkel des Sprites
    	/// @details	x ist die Breite, y ist die Hoehe, z ist der Rotationswinkel
    	glm::vec3				Size		= {0.0f, 0.0f, 0.0f};
    	/// @brief		Textur-ID
    	/// @details	(OpenGL-) Identifikationsnummer der Textur im Graka-Speicher
    	Uint32					Texture		= 0;
    	/// @brief		Textur-Koordinaten
    	/// @details	Bereich der Textur, der auf dem Sprite dargestellt werden soll.
    	std::array<float, 8>	Texels;
    	/// @brief		Sprite-Farbe(n)
    	/// @details	Farbe im RGBA-Format. Wird mit den Texturfarben multipliziert
    	glm::vec4				Color		= {1.0f, 1.0f, 1.0f, 1.0f};
    
    	Sprite_Core_Target_s	()	{this->Texels = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f}; };
    };
    
    // Praeprozessor (Guard)
    //----------------------
    #endif // E_SPRITE_CORE_H
    


  • Die "Klasse" ist startbereit, wenn Sprite.Init() aufgerufen wurde.

    Sprite.Draw kann ein Rechteck an eine bestimmte Position zeichnen, es drehen und zoomen. Wenn man sich SpCore bzw. SpCore.Texels genauer zu Gemuete fuehrt, kriegt man sogar Animationen hin.

    Wie man Texturen auf die Graka laedt, ist, glaube, hinreichend bekannt.

    Wie Shader-Programme kompiliert werden, ist vermutlich auch bekannt.

    Bei Fragen, nicht zoegern und zum Tastenklavier greifen.

    Btw.: Hier sind die Shader:

    sprite.fs

    // Fragment-Shader fuer 2D-Objekte
    // (C) 2016 Uriens The Gray (11.04.2016)
    // Copyright   : GNU Public License v3 (https://www.gnu.org/licenses/gpl.html)
    //               (See also http://copyleft.org/guide/)
    #version 450 core
    
    // Eingaben vom Vertex-Shader
    in vec2 TexCoords;
    in vec4 Colors;
    
    // Eingaben vom Programm
    uniform sampler2D image;
    
    // Ausgaben
    out vec4 color;
    
    // Hauptprogramm
    void	main	()	{
    
    	color = Colors * texture(image, TexCoords);
    
    }
    

    Sprite.vs

    // Vertex-Shader fuer 2D-Objekte
    // (C) 2016 Uriens The Gray (11.04.2016)
    // Copyright   : GNU Public License v3 (https://www.gnu.org/licenses/gpl.html)
    //               (See also http://copyleft.org/guide/)
    #version 450 core
    
    // Eingaben aus Speicher
    layout	(location = 0)	in	vec2	vertex;
    layout	(location = 1)	in	vec2	texel;
    
    // Eingaben vom Programm
    uniform	mat4	model;
    uniform	mat4	projection;
    uniform	vec4	SpriteColors;
    
    // Ausgaben an Fragment-Shader
    out	vec4	Colors;
    out	vec2	TexCoords;
    
    // Hauptprogramm
    void	main	()	{
    
    	gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
    
    	TexCoords = texel;
    
    	Colors = SpriteColors;
    
    }
    

Anmelden zum Antworten