"तत्काल मोड" क्या है? एक कोड उदाहरण दें।
मुझे रिटेन किए गए मोड के बजाय तत्काल मोड का उपयोग कब करना है? प्रत्येक विधि का उपयोग करने के पेशेवरों और विपक्ष क्या हैं?
जवाबों:
"तत्काल मोड" का एक उदाहरण उपयोग कर रहा है glBegin
और glEnd
साथ glVertex
उन दोनों के बीच में। "तत्काल मोड" का एक और उदाहरण का उपयोग करने के लिए है glDrawArrays
एक ग्राहक शिखर सरणी (यानी के साथ नहीं एक शीर्ष बफर वस्तु)।
आप आमतौर पर तत्काल मोड (शायद अपने पहले "हैलो वर्ल्ड" प्रोग्राम को छोड़कर) का उपयोग नहीं करना चाहेंगे, क्योंकि यह पदावनत कार्यक्षमता है और इष्टतम प्रदर्शन की पेशकश नहीं करता है।
तत्काल मोड इष्टतम नहीं होने का कारण यह है कि ग्राफिक कार्ड सीधे आपके प्रोग्राम के प्रवाह के साथ जुड़ा हुआ है। ड्राइवर GPU को पहले रेंडर करना शुरू करने के लिए नहीं कह सकता है glEnd
, क्योंकि यह नहीं पता है कि आपको डेटा सबमिट करना कब समाप्त होगा, और इसे उस डेटा को भी ट्रांसफर करने की आवश्यकता है (जो कि यह केवल उसके बाद कर सकता है glEnd
)।
इसी तरह, क्लाइंट वर्टेक्स ऐरे के साथ, ड्राइवर केवल आपके एरे की एक कॉपी खींच सकता है जिसे आप कॉल करते हैं glDrawArrays
, और उसे आपके एप्लिकेशन को ब्लॉक करना चाहिए। कारण यह है कि अन्यथा आप ड्राइवर को कैप्चर करने से पहले सरणी की मेमोरी को संशोधित (या मुफ्त) कर सकते हैं। यह उस ऑपरेशन को पहले या बाद में शेड्यूल नहीं कर सकता है, क्योंकि यह केवल यह जानता है कि डेटा एक समय में बिल्कुल मान्य है।
इसके विपरीत, यदि आप उदाहरण के लिए एक वर्टेक्स बफर ऑब्जेक्ट का उपयोग करते हैं, तो आप डेटा के साथ एक बफर भरते हैं और इसे ओपनजीएल को सौंप देते हैं। आपकी प्रक्रिया अब इस डेटा का स्वामी नहीं है और इसलिए अब इसे संशोधित नहीं किया जा सकता है। ड्राइवर इस तथ्य पर भरोसा कर सकता है और जब भी बस खाली होती है, तब भी डेटा अपलोड कर सकता है।
आपका कोई भी बाद glDrawArrays
या glDrawElements
कॉल बस एक काम कतार में जाएगा और तुरंत (वास्तव में खत्म होने से पहले!) वापस आ जाएगा, इसलिए आपका कार्यक्रम एक ही समय में कमांड जमा करता रहता है जबकि ड्राइवर एक-एक करके काम करता है। उन्होंने यह भी कहा कि डेटा के आने की प्रतीक्षा करने की आवश्यकता नहीं होगी, क्योंकि ड्राइवर पहले से ही ऐसा कर सकता है।
इस प्रकार, थ्रेड और जीपीयू को अतुल्यकालिक रूप से चलाएं, हर घटक हर समय व्यस्त रहता है, जो बेहतर प्रदर्शन देता है।
तत्काल मोड का उपयोग करने के लिए मृत सरल होने का फायदा होता है, लेकिन फिर एक गैर-पदावनत तरीके से ओपनजीएल का सही तरीके से उपयोग करना ठीक से रॉकेट साइंस भी नहीं है - यह केवल बहुत कम अतिरिक्त काम करता है।
यहाँ तत्काल मोड में विशिष्ट OpenGL "हैलो वर्ल्ड" कोड है:
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;
}
ओपन जीआईजीएल से अनुकूलित , मेरा गिटहब अपस्ट्रीम ।
संकलन और Ubuntu 20.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
इससे हम देखते हैं कि:
शेड का उपयोग करते समय:
सीपीयू पर चलने वाले नियमित सी प्रोग्राम के अंदर जीएलएसएल भाषा ( vertexShaderSource
और fragmentShaderSource
) युक्त सी-स्टाइल स्ट्रिंग्स के रूप में वर्टेक्स और टुकड़ा shader कार्यक्रमों का प्रतिनिधित्व किया जा रहा है
यह C प्रोग्राम OpenGL कॉल करता है जो उन तारों को GPU कोड में संकलित करता है, जैसे:
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shader उनके अपेक्षित इनपुट को परिभाषित करता है, और C प्रोग्राम उन्हें GPU कोड को मेमोरी में पॉइंटर के माध्यम से प्रदान करता है। उदाहरण के लिए, टुकड़ा shader शीर्ष पदों और रंगों की एक सरणी के रूप में अपने अपेक्षित इनपुट को परिभाषित करता है:
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec3 color;\n"
"out vec3 ourColor;\n"
और इसके एक आउटपुट 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);
हालांकि, तत्काल नॉन-शेडर उदाहरण पर, हम देखते हैं कि मैजिक एपीआई कॉल किए जाते हैं जो स्पष्ट रूप से स्थिति और रंग देते हैं:
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);
इसलिए हम समझते हैं कि यह एक बहुत अधिक प्रतिबंधित मॉडल का प्रतिनिधित्व करता है, क्योंकि स्थिति और रंग अब स्मृति में उपयोगकर्ता-परिभाषित सरणियों नहीं हैं, बल्कि केवल एक फोंग जैसे मॉडल के लिए इनपुट करते हैं।
दोनों मामलों में, प्रदान किया गया आउटपुट सामान्य रूप से सीपीयू के माध्यम से वापस जाने के बिना, सीधे वीडियो में चला जाता है, हालांकि सीपीयू को पढ़ना संभव है, जैसे यदि आप उन्हें एक फ़ाइल में सहेजना चाहते हैं: रेंडर करने के लिए GLUT / OpenGL का उपयोग कैसे करें एक पंक्ति?
अधिकांश "आधुनिक" ओपनजीएल ट्यूटोरियल सामान्य रूप से बनाए रखा गया मोड और GLFW, आपको कई उदाहरण मिलेंगे
ERROR::SHADER::VERTEX::COMPILATION_FAILED
तो आप इसे ठीक कर सकते हैं glfwWindowHint
जैसा कि दिखाया गया है: stackoverflow.com/questions/52592309/… फिर भी मैं पुन: पेश नहीं कर सकता।
export MESA_GL_VERSION_OVERRIDE=3.3
main.out (डेबियन 8) चलाने से पहले कमांड को चलाकर समस्या का हल किया क्योंकि एक उत्तर उसी पोस्ट पर इंगित करता है जिसे आपने साझा किया था।