Was ist "Sofortmodus"? Geben Sie ein Codebeispiel.
Wann muss ich den Sofortmodus anstelle des beibehaltenen Modus verwenden? Was sind die Vor- und Nachteile jeder Methode?
Ein Beispiel für den "Sofortmodus" ist die Verwendung von glBegin
und glEnd
mit glVertex
dazwischen. Ein weiteres Beispiel für den "Sofortmodus" ist die Verwendung glDrawArrays
mit einem Client-Vertex-Array (dh nicht mit einem Vertex-Pufferobjekt).
Normalerweise möchten Sie den Sofortmodus nie verwenden (außer vielleicht für Ihr erstes "Hallo Welt" -Programm), da es sich um eine veraltete Funktionalität handelt und keine optimale Leistung bietet.
Der Grund, warum der Sofortmodus nicht optimal ist, besteht darin, dass die Grafikkarte direkt mit dem Programmfluss verknüpft ist. Der Treiber kann die GPU nicht anweisen, vorher mit dem Rendern zu beginnen glEnd
, da er nicht weiß, wann Sie mit dem Senden der Daten fertig sind, und diese Daten ebenfalls übertragen muss (was erst danach möglich ist glEnd
).
In ähnlicher Weise kann der Treiber bei einem Client-Vertex-Array nur in dem Moment, in dem Sie aufrufen glDrawArrays
, eine Kopie Ihres Arrays abrufen und muss dabei Ihre Anwendung blockieren. Der Grund ist, dass Sie andernfalls den Speicher des Arrays ändern (oder freigeben) könnten, bevor der Treiber ihn erfasst hat. Dieser Vorgang kann nicht früher oder später geplant werden, da nur bekannt ist, dass die Daten genau zu einem bestimmten Zeitpunkt gültig sind.
Wenn Sie beispielsweise ein Scheitelpunktpufferobjekt verwenden, füllen Sie einen Puffer mit Daten und übergeben ihn OpenGL. Ihr Prozess besitzt diese Daten nicht mehr und kann sie daher nicht mehr ändern. Der Fahrer kann sich auf diese Tatsache verlassen und die Daten (auch spekulativ) hochladen, wenn der Bus frei ist.
Jeder Ihrer späteren glDrawArrays
oder glDrawElements
Aufrufe wird einfach in eine Arbeitswarteschlange gestellt und sofort (vor dem eigentlichen Abschluss!) Zurückgegeben, sodass Ihr Programm weiterhin Befehle sendet, während der Treiber gleichzeitig nacheinander arbeitet. Sie müssen wahrscheinlich auch nicht auf das Eintreffen der Daten warten, da der Fahrer dies bereits viel früher tun könnte.
Wenn Render-Thread und GPU asynchron ausgeführt werden, ist jede Komponente jederzeit ausgelastet, was zu einer besseren Leistung führt.
Der Sofortmodus hat den Vorteil, dass er kinderleicht zu bedienen ist, aber die ordnungsgemäße und nicht veraltete Verwendung von OpenGL ist auch keine Raketenwissenschaft - es erfordert nur sehr wenig zusätzliche Arbeit.
Hier ist der typische OpenGL-Code "Hello World" im Sofortmodus:
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(0.0f, 1.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.87f, -0.5f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(-0.87f, -0.5f);
glEnd();
Bearbeiten:
Auf allgemeine Anfrage würde dasselbe im beibehaltenen Modus ungefähr so aussehen:
float verts = {...};
float colors = {...};
static_assert(sizeof(verts) == sizeof(colors), "");
// not really needed for this example, but mandatory in core profile after GL 3.2
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint buf[2];
glGenBuffers(2, buf);
// assuming a layout(location = 0) for position and
// layout(location = 1) for color in the vertex shader
// vertex positions
glBindBuffer(GL_ARRAY_BUFFER, buf[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// copy/paste for color... same code as above. A real, non-trivial program would
// normally use a single buffer for both -- usually with stride (5th param) to
// glVertexAttribPointer -- that presumes interleaving the verts and colors arrays.
// It's somewhat uglier but has better cache performance (ugly does however not
// matter for a real program, since data is loaded from a modelling-tool generated
// binary file anyway).
glBindBuffer(GL_ARRAY_BUFFER, buf[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
Ausführbares Beispiel
Damon hat die Schlüsselteile geliefert , aber Neulinge wie ich werden nach einem voll funktionsfähigen Beispiel suchen.
Haupt c
#include <stdio.h> #include <stdlib.h> #define GLEW_STATIC #include <GL/glew.h> #include <GLFW/glfw3.h> #define INFOLOG_LEN 512 static const GLuint WIDTH = 800, HEIGHT = 600; /* vertex data is passed as input to this shader * ourColor is passed as input to the to the fragment shader. */ static const GLchar* vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 position;\n" "layout (location = 1) in vec3 color;\n" "out vec3 ourColor;\n" "void main() {\n" " gl_Position = vec4(position, 1.0f);\n" " ourColor = color;\n" "}\n"; static const GLchar* fragmentShaderSource = "#version 330 core\n" "in vec3 ourColor;\n" "out vec4 color;\n" "void main() {\n" " color = vec4(ourColor, 1.0f);\n" "}\n"; GLfloat vertices[] = { /* Positions Colors */ 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f }; int main(void) { glfwInit(); GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL); glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; glewInit(); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glViewport(0, 0, WIDTH, HEIGHT); /* Build and compile shader program. */ /* Vertex shader */ GLint vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); GLint success; GLchar infoLog[INFOLOG_LEN]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertexShader, INFOLOG_LEN, NULL, infoLog); printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog); } /* Fragment shader */ GLint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragmentShader, INFOLOG_LEN, NULL, infoLog); printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog); } /* Link shaders */ GLint shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram, INFOLOG_LEN, NULL, infoLog); printf("ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog); } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); GLuint vbo, vao; glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); /* Position attribute */ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); /* Color attribute */ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); glBindVertexArray(0); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(shaderProgram); glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); glfwSwapBuffers(window); } glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo); glfwTerminate(); return EXIT_SUCCESS; }
Unter Ubuntu 18.10:
Sofortiges "Äquivalent":
glBegin(GL_TRIANGLES); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(0.5f, -0.5.0f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(0.0f, 0.5f, 0.0f); glEnd();
Dieses Beispiel wird von hier aus angepasst .
Die meisten "modernen" OpenGL-Tutorials behalten normalerweise den Modus und GLFW bei. Viele Beispiele finden Sie unter:
quelle
ERROR::SHADER::VERTEX::COMPILATION_FAILED
beheben können , wenn Sie ihnglfwWindowHint
wie folgt beheben : stackoverflow.com/questions/52592309/… Ich kann ihn jedoch nicht reproduzieren.