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; }