「イミディエイトモード」とは?コード例を挙げてください。
保持モードの代わりに即時モードを使用する必要があるのはいつですか?それぞれの方法を使用することの長所と短所は何ですか?
回答:
「即時モード」の一例は、使用しているglBegin
とglEnd
してglVertex
それらの間インチ 「イミディエイトモード」の別の例はglDrawArrays
、クライアント頂点配列で使用することです(つまり、、頂点バッファオブジェクトで)で使用することです。
即時モードは非推奨の機能であり、最適なパフォーマンスを提供しないため、通常は(おそらく最初の「helloworld」プログラムを除いて)即時モードを使用することはありません。
イミディエイトモードが最適でない理由は、グラフィックカードがプログラムのフローに直接リンクされているためです。ドライバーはglEnd
、データの送信がいつ終了するかわからないため、GPUにレンダリングを開始するように指示できません。また、そのデータも転送する必要があります(これは後でのみ実行できますglEnd
)。
同様に、クライアント頂点配列の場合、ドライバーは呼び出した瞬間にのみ配列のコピーをプルできglDrawArrays
、その間、アプリケーションをブロックする必要があります。その理由は、そうでなければ、ドライバがアレイをキャプチャする前に、アレイのメモリを変更(または解放)する可能性があるためです。データが正確にある時点で有効であることがわかっているだけなので、その操作を以前または後でスケジュールすることはできません。
それとは対照的に、たとえば頂点バッファオブジェクトを使用する場合は、バッファにデータを入力してOpenGLに渡します。プロセスはこのデータを所有しなくなったため、データを変更できなくなりました。ドライバーはこの事実に頼ることができ、バスが空いているときはいつでも(投機的にさえ)データをアップロードすることができます。
それglDrawArrays
以降のglDrawElements
呼び出しまたは呼び出しは、ワークキューに入り、すぐに(実際に終了する前に!)戻るため、プログラムはコマンドを送信し続け、同時にドライバーは1つずつ動作します。また、ドライバーはすでにはるかに早い段階でデータが到着する可能性があるため、データが到着するのを待つ必要はないでしょう。
したがって、レンダリングスレッドとGPUは非同期で実行され、すべてのコンポーネントが常にビジー状態になり、パフォーマンスが向上します。
イミディエイトモードには、非常に簡単に使用できるという利点がありますが、OpenGLを非推奨ではない方法で適切に使用することも、厳密にはロケット科学ではありません。余分な作業はほとんど必要ありません。
即時モードでの典型的なOpenGL「HelloWorld」コードは次のとおりです。
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();
編集:
一般的なリクエストにより、保持モードでの同じことは次のようになります。
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);
実行可能な保持例
デイモンは重要な部分を提供しましたが、私のような初心者は完全に実行可能な例を探しています。
main.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 = 512, HEIGHT = 512;
/* 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(int argc, char **argv) {
int immediate = (argc > 1) && argv[1][0] == '1';
/* Used in !immediate only. */
GLuint vao, vbo;
GLint shaderProgram;
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);
if (immediate) {
float ratio;
int width, height;
glfwGetFramebufferSize(window, &width, &height);
ratio = width / (float) height;
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBegin(GL_TRIANGLES);
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f(-0.5f, -0.5f, 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();
} else {
/* 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 */
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);
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);
glUseProgram(shaderProgram);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
}
glfwSwapBuffers(window);
/* Main loop. */
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
if (!immediate) {
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteProgram(shaderProgram);
}
glfwTerminate();
return EXIT_SUCCESS;
}
Learn OpenGL、私のGitHubアップストリームから適応。
Ubuntu20.04でコンパイルして実行します。
sudo apt install libglew-dev libglfw3-dev
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c -lGL -lGLEW -lglfw
# Shader
./main.out
# Immediate
./main.out 1
それから、次のことがわかります。
シェーダーを使用する場合:
頂点シェーダープログラムとフラグメントシェーダープログラムは、CPU上で実行される通常のCプログラム内でGLSL言語(vertexShaderSource
およびfragmentShaderSource
)を含むCスタイルの文字列として表されます。
このCプログラムは、これらの文字列をGPUコードにコンパイルするOpenGL呼び出しを行います。例:
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
シェーダーは期待される入力を定義し、CプログラムはGPUコードへのメモリへのポインターを介してそれらを提供します。たとえば、フラグメントシェーダーは、期待される入力を頂点の位置と色の配列として定義します。
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec3 color;\n"
"out vec3 ourColor;\n"
また、出力の1つをourColor
色の配列として定義し、それがフラグメントシェーダーへの入力になります。
static const GLchar* fragmentShaderSource =
"#version 330 core\n"
"in vec3 ourColor;\n"
次に、Cプログラムは、CPUからGPUへの頂点の位置と色を含む配列を提供します。
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
ただし、シェーダー以外の直接の例では、位置と色を明示的に指定するマジックAPI呼び出しが行われていることがわかります。
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);
したがって、位置と色はメモリ内の任意のユーザー定義配列ではなく、Phongのようなモデルへの入力にすぎないため、これははるかに制限されたモデルを表すことを理解しています。
どちらの場合も、レンダリングされた出力は通常、CPUを経由せずにビデオに直接送られますが、CPUに読み取ることは可能です。たとえば、ファイルに保存する場合などです。GLUT/ OpenGLを使用してレンダリングする方法ファイル?
ほとんどの「最新の」OpenGLチュートリアルは、通常、モードとGLFWを保持しています。多くの例は、次の場所にあります。
ERROR::SHADER::VERTEX::COMPILATION_FAILED
修正できる可能性があるという報告があります。ただし、再現できません。glfwWindowHint