ximen: переводы
OpenGL SuperBible (6th Edition) / OpenGL Супер Книга (6-ое издание)
→Click here to view code image
GLuint compile_shaders(void)
{
GLuint vertex_shader;
GLuint fragment_shader;
GLuint program;
// Source code for vertex shader
static const GLchar * vertex_shader_source[] =
{
"#version 430 core \n"
" \n"
"void main(void) \n"
"{ \n"
" gl_Position = vec4(0.0, 0.0, 0.5, 1.0); \n"
"} \n"
};
// Source code for fragment shader
static const GLchar * fragment_shader_source[] =
{
"#version 430 core \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(0.0, 0.8, 1.0, 1.0); \n"
"} \n"
};
// Create and compile vertex shader
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
glCompileShader(vertex_shader);
// Create and compile fragment shader
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
glCompileShader(fragment_shader);
// Create program, attach shaders to it, and link it
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
// Delete the shaders as the program has them now
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return program;
}
Listing 2.5: Compiling a simple shader
GLuint compile_shaders(void)
{
GLuint vertex_shader;
GLuint fragment_shader;
GLuint program;
// Source code for vertex shader
static const GLchar * vertex_shader_source[] =
{
"#version 430 core \n"
" \n"
"void main(void) \n"
"{ \n"
" gl_Position = vec4(0.0, 0.0, 0.5, 1.0); \n"
"} \n"
};
// Source code for fragment shader
static const GLchar * fragment_shader_source[] =
{
"#version 430 core \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(0.0, 0.8, 1.0, 1.0); \n"
"} \n"
};
// Create and compile vertex shader
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
glCompileShader(vertex_shader);
// Create and compile fragment shader
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
glCompileShader(fragment_shader);
// Create program, attach shaders to it, and link it
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
// Delete the shaders as the program has them now
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return program;
}
Listing 2.5: Compiling a simple shader
0 GLuint compile_shaders(void)
{
GLuint vertex_shader;
GLuint fragment_shader;
GLuint program;
// Исходный код вершинного шейдера
static const GLchar * vertex_shader_source[] =
{
"#version 430 core \n"
" \n"
"void main(void) \n"
"{ \n"
" gl_Position = vec4(0.0, 0.0, 0.5, 1.0); \n"
"} \n"
};
// Исходный код фрагментного шейдера
static const GLchar * fragment_shader_source[] =
{
"#version 430 core \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(0.0, 0.8, 1.0, 1.0); \n"
"} \n"
};
// Создание и компиляция вершинного шейдера
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
glCompileShader(vertex_shader);
// Создание и компиляция фрагментого шейдера
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
glCompileShader(fragment_shader);
// Создание программы, прикрепление шейдеров и их связываение.
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
// Удаляем шейдеры т.к. они есть в программе
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return program;
}
Листинг 2.5: Компиляция простого шейдера
{
GLuint vertex_shader;
GLuint fragment_shader;
GLuint program;
// Исходный код вершинного шейдера
static const GLchar * vertex_shader_source[] =
{
"#version 430 core \n"
" \n"
"void main(void) \n"
"{ \n"
" gl_Position = vec4(0.0, 0.0, 0.5, 1.0); \n"
"} \n"
};
// Исходный код фрагментного шейдера
static const GLchar * fragment_shader_source[] =
{
"#version 430 core \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(0.0, 0.8, 1.0, 1.0); \n"
"} \n"
};
// Создание и компиляция вершинного шейдера
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
glCompileShader(vertex_shader);
// Создание и компиляция фрагментого шейдера
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
glCompileShader(fragment_shader);
// Создание программы, прикрепление шейдеров и их связываение.
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
// Удаляем шейдеры т.к. они есть в программе
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return program;
}
Листинг 2.5: Компиляция простого шейдера
→Now that we have both a vertex and a fragment shader, it’s time to compile them and link them together into a program that can be run by OpenGL. This is similar to the way that programs written in C++ or other similar languages are compiled and linked to produce executables. The code to link our shaders together into a program object is shown in Listing 2.5.
0 Теперь, когда у нас есть и вершинный и фрагментный шейдеры, пришло время их скомпилировать и связать в программу, которая может быть выполнена OpenGL. Это аналогично тому, как программы, написанные на C++ или подобном языке компилируются и связываются для получения исполняемого файла. Код для связи наших шейдеров в программный объект показан в Листинге 2.5.
→Click here to view code image
#version 430 core
out vec4 color;
void main(void)
{
color = vec4(0.0, 0.8, 1.0, 1.0);
}
Listing 2.4: Our first fragment shader
#version 430 core
out vec4 color;
void main(void)
{
color = vec4(0.0, 0.8, 1.0, 1.0);
}
Listing 2.4: Our first fragment shader
0 #version 430 core
out vec4 color;
void main(void)
{
color = vec4(0.0, 0.8, 1.0, 1.0);
}
Листинг 2.4: Наш первый фрагментный шейдер
out vec4 color;
void main(void)
{
color = vec4(0.0, 0.8, 1.0, 1.0);
}
Листинг 2.4: Наш первый фрагментный шейдер
→Next, our fragment shader is given in Listing 2.4. Again, this is extremely simple. It too starts with a #version 430 core declaration. Next, it declares color as an output variable using the out keyword. In fragment shaders, the value of output variables will be sent to the window or screen. In the main function, it assigns a constant to this output. By default, that value goes directly onto the screen and is a vector of four floating-point values, one each for red, green, blue, and alpha, just like in the parameter to glClearBufferfv(). In this shader, the value we’ve used is vec4(0.0, 0.8, 1.0, 1.0), which is a cyan color.
0 Наш вершинный шейдер представлен на Листинге 2.4. И снова, он крайне прост. Он также начинается с объявления #version 430 core. Далее color объявляется выходной переменной с помощью ключевого слова out. Значение выходных переменных фрагментного шейдера будет отправлено на экран или в окно. В функции main этой переменной присваивается постоянное значение. По умолчанию, это значение сразу отображается на экране и представляет собой вектор из четырёх значений с плавающей точкой, по одному на красную, зелёную, синюю и альфа компоненты, в точности как параметр glClearBufferfv(). В этом шейдере мы использовали значение vec4(0.0, 0.8, 1.0, 1.0), что соответствует сине-зелёному цвету.
→Click here to view code image
#version 430 core
void main(void)
{
gl_Position = vec4(0.0, 0.0, 0.5, 1.0);
}
Listing 2.3: Our first vertex shader
#version 430 core
void main(void)
{
gl_Position = vec4(0.0, 0.0, 0.5, 1.0);
}
Listing 2.3: Our first vertex shader
0 #version 430 core
void main(void)
{
gl_Position = vec4(0.0, 0.0, 0.5, 1.0);
}
Листинг 2.3: Наш первый вершинный шейдер
void main(void)
{
gl_Position = vec4(0.0, 0.0, 0.5, 1.0);
}
Листинг 2.3: Наш первый вершинный шейдер
→Using Shaders
As we mentioned in the introduction to the graphics pipeline in Chapter 1, “Introduction,” OpenGL works by connecting a number of mini-programs called shaders together with fixed-function glue. When you draw, the graphics processor executes your shaders and pipes their inputs and outputs along the pipeline until pixels3 come out the end. In order to draw anything at all, you’ll need to write at least a couple of shaders.
----------------------------
3. Actually, there are a number of use cases of OpenGL that create no pixels at all. We will cover those in a while. For now, let’s just draw some pictures.
----------------------------
OpenGL shaders are written in a language called the OpenGL Shading Language, or GLSL. This is a language that has its origins in C, but has been modified over time to make it better suited to running on graphics processors. If you are familiar with C, then it shouldn’t be hard to pick up GLSL. The compiler for this language is built into OpenGL. The source code for your shader is placed into a shader object and compiled, and then multiple shader objects can be linked together to form a program object. Each program object can contain shaders for one or more shader stages. The shader stages of OpenGL are vertex shaders, tessellation control and evaluation shaders, geometry shaders, fragment shaders, and compute shaders. The minimal useful pipeline configuration consists only of a vertex shader4 (or just a compute shader), but if you wish to see any pixels on the screen, you will also need a fragment shader.
-----------------------------
4. If you try to draw anything when your pipeline does not contain a vertex shader, the results will be undefined and almost certainly not what you were hoping for.
----------------------------
Our first couple of shaders are extremely simple. Listing 2.3 shows our first vertex shader. This is about as simple as it gets. In the first line, we have the #version 430 core declaration, which tells the shader compiler that we intend to use version 4.3 of the shading language. Notice that we include the keyword core to indicate that we only intend to use features from the core profile of OpenGL.
Next, we have the declaration of our main function, which is where the shader starts executing. This is exactly the same as in a normal C program, except that the main function of a GLSL shader has no parameters. Inside our main function, we assign a value to gl_Position, which is part of the plumbing that connects the shader to the rest of OpenGL. All variables that start with gl_ are part of OpenGL and connect shaders to each other or to the various parts of fixed functionality in OpenGL. In the vertex shader, gl_Position represents the output position of the vertex. The value we assign (vec4(0.0, 0.0, 0.5, 1.0)) places the vertex right in the middle of OpenGL’s clip space, which is the coordinate system expected by the next stage of the OpenGL pipeline.
As we mentioned in the introduction to the graphics pipeline in Chapter 1, “Introduction,” OpenGL works by connecting a number of mini-programs called shaders together with fixed-function glue. When you draw, the graphics processor executes your shaders and pipes their inputs and outputs along the pipeline until pixels3 come out the end. In order to draw anything at all, you’ll need to write at least a couple of shaders.
----------------------------
3. Actually, there are a number of use cases of OpenGL that create no pixels at all. We will cover those in a while. For now, let’s just draw some pictures.
----------------------------
OpenGL shaders are written in a language called the OpenGL Shading Language, or GLSL. This is a language that has its origins in C, but has been modified over time to make it better suited to running on graphics processors. If you are familiar with C, then it shouldn’t be hard to pick up GLSL. The compiler for this language is built into OpenGL. The source code for your shader is placed into a shader object and compiled, and then multiple shader objects can be linked together to form a program object. Each program object can contain shaders for one or more shader stages. The shader stages of OpenGL are vertex shaders, tessellation control and evaluation shaders, geometry shaders, fragment shaders, and compute shaders. The minimal useful pipeline configuration consists only of a vertex shader4 (or just a compute shader), but if you wish to see any pixels on the screen, you will also need a fragment shader.
-----------------------------
4. If you try to draw anything when your pipeline does not contain a vertex shader, the results will be undefined and almost certainly not what you were hoping for.
----------------------------
Our first couple of shaders are extremely simple. Listing 2.3 shows our first vertex shader. This is about as simple as it gets. In the first line, we have the #version 430 core declaration, which tells the shader compiler that we intend to use version 4.3 of the shading language. Notice that we include the keyword core to indicate that we only intend to use features from the core profile of OpenGL.
Next, we have the declaration of our main function, which is where the shader starts executing. This is exactly the same as in a normal C program, except that the main function of a GLSL shader has no parameters. Inside our main function, we assign a value to gl_Position, which is part of the plumbing that connects the shader to the rest of OpenGL. All variables that start with gl_ are part of OpenGL and connect shaders to each other or to the various parts of fixed functionality in OpenGL. In the vertex shader, gl_Position represents the output position of the vertex. The value we assign (vec4(0.0, 0.0, 0.5, 1.0)) places the vertex right in the middle of OpenGL’s clip space, which is the coordinate system expected by the next stage of the OpenGL pipeline.
0 Использование шейдеров
Как мы уже упоминали в Главе 1, OpenGL работает путём соединения в единое целое нескольких мини-программ, называемых шейдеры. Когда вы рисуете, графический процессор исполняет ваши шейдеры и соединяет их входы и выходы в конвейер пока в конце не получатся пиксели3. Что нарисовать хоть что-то, вам потребуется как минимум пара шейдеров.
----------------------------
3. Вообще-то, существуют случаи, когда OpenGL вообще не создаёт пиксели. Об этом мы поговорим позже, а сейчас давайте просто нарисуем несколько картинок.
----------------------------
Шейдеры OpenGL пишутся на языке OpenGL Shading Language или GLSL. Этот язык происходит от C, но со временем был изменён, чтобы лучше выполняться на графических процессорах. Если вы знакомы с C, то разобраться с GLSL должно быть не сложно. Компилятор для этого языка встроен в OpenGL. Исходный код вашего шейдера помещается в шейдерный объект и компилируется, а затем множество шейдерных объектов могут быть связаны вместе для создания программного объекта. Каждый программный объект может содержать шейдеры различных стадий. В OpenGL существуют следующие стадии шейдеров: вершинные шейдеры, шейдеры управления тесселяцией, геометрические шейдеры, фрагментные шейдеры и вычислительные шейдеры. Минимальная полезная конфигурация конвейера содержит только вершинный4 (или только вычислительный) шейдер, но если вы хотите увидеть какие-нибудь пикселы на экране, вам также потребуется фрагментный шейдер.
----------------------------
4. Если вы попытаетесь нарисовать что-нибудь, когда в вашем конвейере нет вершинного шейдера, результат получится непредсказуемый и почти обязательно не тот, на который вы рассчитывали.
----------------------------
Наша первая пара шейдеров крайне проста. Листинг 2.3 показывает наш первый вершинный шейдер. Первая строка содержит объявление #version 430 core, которое говорит компилятору шейдера, что мы намерены использовать шейдерный язык версии 4.3. Заметьте, что мы использовали ключевое слово core для указания того, что мы будем пользоваться возможностями только базового профиля (core profile) OpenGL.
Далее идёт объявление функции main, с которой начинает выполняться шейдер, в точности, как и обычная программа на языке C. Разница заключается в том, что функция main в GLSL не имеет параметров. Внутри функции main мы присваиваем значение переменной gl_Position, которая является частью того, что связывает шейдер с остальным OpenGL. Все переменные, имя которых начинается с "gl_", являются частью OpenGL и соединяют шейдеры друг с другом или с частями фиксированной функциональности OpenGL. В вершинном шейдере gl_Position представляет выходное положение вершины. Значение, которое мы присваиваем (vec4(0.0, 0.0, 0.5, 1.0)), располагает вершину точно в середине однородной системы координат (clip-space), которая требуется для следующей стадии конвейера OpenGL.
Как мы уже упоминали в Главе 1, OpenGL работает путём соединения в единое целое нескольких мини-программ, называемых шейдеры. Когда вы рисуете, графический процессор исполняет ваши шейдеры и соединяет их входы и выходы в конвейер пока в конце не получатся пиксели3. Что нарисовать хоть что-то, вам потребуется как минимум пара шейдеров.
----------------------------
3. Вообще-то, существуют случаи, когда OpenGL вообще не создаёт пиксели. Об этом мы поговорим позже, а сейчас давайте просто нарисуем несколько картинок.
----------------------------
Шейдеры OpenGL пишутся на языке OpenGL Shading Language или GLSL. Этот язык происходит от C, но со временем был изменён, чтобы лучше выполняться на графических процессорах. Если вы знакомы с C, то разобраться с GLSL должно быть не сложно. Компилятор для этого языка встроен в OpenGL. Исходный код вашего шейдера помещается в шейдерный объект и компилируется, а затем множество шейдерных объектов могут быть связаны вместе для создания программного объекта. Каждый программный объект может содержать шейдеры различных стадий. В OpenGL существуют следующие стадии шейдеров: вершинные шейдеры, шейдеры управления тесселяцией, геометрические шейдеры, фрагментные шейдеры и вычислительные шейдеры. Минимальная полезная конфигурация конвейера содержит только вершинный4 (или только вычислительный) шейдер, но если вы хотите увидеть какие-нибудь пикселы на экране, вам также потребуется фрагментный шейдер.
----------------------------
4. Если вы попытаетесь нарисовать что-нибудь, когда в вашем конвейере нет вершинного шейдера, результат получится непредсказуемый и почти обязательно не тот, на который вы рассчитывали.
----------------------------
Наша первая пара шейдеров крайне проста. Листинг 2.3 показывает наш первый вершинный шейдер. Первая строка содержит объявление #version 430 core, которое говорит компилятору шейдера, что мы намерены использовать шейдерный язык версии 4.3. Заметьте, что мы использовали ключевое слово core для указания того, что мы будем пользоваться возможностями только базового профиля (core profile) OpenGL.
Далее идёт объявление функции main, с которой начинает выполняться шейдер, в точности, как и обычная программа на языке C. Разница заключается в том, что функция main в GLSL не имеет параметров. Внутри функции main мы присваиваем значение переменной gl_Position, которая является частью того, что связывает шейдер с остальным OpenGL. Все переменные, имя которых начинается с "gl_", являются частью OpenGL и соединяют шейдеры друг с другом или с частями фиксированной функциональности OpenGL. В вершинном шейдере gl_Position представляет выходное положение вершины. Значение, которое мы присваиваем (vec4(0.0, 0.0, 0.5, 1.0)), располагает вершину точно в середине однородной системы координат (clip-space), которая требуется для следующей стадии конвейера OpenGL.
→Now our window fades from red through yellow, orange, green, and back to red again. Still not that exciting, but at least it does something.
0 Теперь наше окно изменяет цвет с красного через жёлтый, оранжевый, зелёный и чёрный снова на красный. Всё ещё не особо захватывающе, но хотя бы уже что-то делает.
→Click here to view code image
// Our rendering function
void render(double currentTime)
{
const GLfloat color[] = { (float)sin(currentTime) * 0.5f + 0.5f,
(float)cos(currentTime) * 0.5f + 0.5f,
0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, color);
}
Listing 2.2: Animating color over time
// Our rendering function
void render(double currentTime)
{
const GLfloat color[] = { (float)sin(currentTime) * 0.5f + 0.5f,
(float)cos(currentTime) * 0.5f + 0.5f,
0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, color);
}
Listing 2.2: Animating color over time
0 // Наша функция рендера
void render(double currentTime)
{
const GLfloat color[] = { (float)sin(currentTime) * 0.5f + 0.5f,
(float)cos(currentTime) * 0.5f + 0.5f,
0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, color);
}
Листинг 2.2: Анимация цвета с течением времени
void render(double currentTime)
{
const GLfloat color[] = { (float)sin(currentTime) * 0.5f + 0.5f,
(float)cos(currentTime) * 0.5f + 0.5f,
0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, color);
}
Листинг 2.2: Анимация цвета с течением времени
→All OpenGL functions start with gl and follow a number of naming conventions such as encoding some of their parameter types as suffixes on the end of the function names. This allows a limited form of overloading even in languages that don’t directly support this. In this case, the suffix fv means that the function consumes a vector (v) of floating-point (f) values, where arrays (generally referenced by pointers in languages like C) and vectors are used interchangeably by OpenGL.
The glClearBufferfv() function tells OpenGL to clear the buffer specified by the first parameter (in this case GL_COLOR) to the value specified in its third parameter. The second parameter, drawBuffer, is used when there are multiple output buffers that could be cleared. Because we’re only using one here and drawBuffer is a zero-based index, we’ll just set it to zero in this example. Here, that color is stored in the array red, which contains four floating-point values — one each for red, green, blue, and alpha, in that order. The red, green, and blue terms should be self-explanatory. Alpha is a fourth component that is associated with a color and is often used to encode the opacity of a fragment. When used this way, setting alpha to zero will make the fragment completely transparent, and setting it to one will make it completely opaque. The alpha value can also be stored in the output image and used in some parts of OpenGL’s calculations, even though you can’t see it. You can see that we set both the red and alpha values to one and the others to zero. This specifies an opaque red color. The result of running this application is shown in Figure 2.1.
This initial application isn’t particularly interesting1 as all it does is fill the window with a solid red color. You will notice that our render() function takes a single parameter — currentTime. This contains the number of seconds since the application was started, and we can use it to create a simple animation. In this case, we can use it to change the color that we use to clear the window. Our modified render() function2 is shown in Listing 2.2.
1. This sample is especially uninteresting if you are reading this book in black and white!
2. If you’re copying this code into your own example, you’ll need to include <math.h> in order to get the declarations of sin() and cos().
The glClearBufferfv() function tells OpenGL to clear the buffer specified by the first parameter (in this case GL_COLOR) to the value specified in its third parameter. The second parameter, drawBuffer, is used when there are multiple output buffers that could be cleared. Because we’re only using one here and drawBuffer is a zero-based index, we’ll just set it to zero in this example. Here, that color is stored in the array red, which contains four floating-point values — one each for red, green, blue, and alpha, in that order. The red, green, and blue terms should be self-explanatory. Alpha is a fourth component that is associated with a color and is often used to encode the opacity of a fragment. When used this way, setting alpha to zero will make the fragment completely transparent, and setting it to one will make it completely opaque. The alpha value can also be stored in the output image and used in some parts of OpenGL’s calculations, even though you can’t see it. You can see that we set both the red and alpha values to one and the others to zero. This specifies an opaque red color. The result of running this application is shown in Figure 2.1.
This initial application isn’t particularly interesting1 as all it does is fill the window with a solid red color. You will notice that our render() function takes a single parameter — currentTime. This contains the number of seconds since the application was started, and we can use it to create a simple animation. In this case, we can use it to change the color that we use to clear the window. Our modified render() function2 is shown in Listing 2.2.
1. This sample is especially uninteresting if you are reading this book in black and white!
2. If you’re copying this code into your own example, you’ll need to include <math.h> in order to get the declarations of sin() and cos().
0 Названия всех функций OpenGL начинаются с "gl" и следуют определённым правилам построения, таким как указание типов параметров в конце имени. Это позволяет реализовать ограниченную форму перегрузки даже если язык программирования прямо этого не поддерживает. В таком случае, суффикс "fv" означает, что на вход функции подаётся вектор (v) значений с плавающей точкой (f). Векторы и массивы (как правило, представляющие собой указатели в языках, подобных C ) в OpenGL взаимозаменяемы.
Функция glClearBufferfv() говорит OpenGL очистить буфер, указываемый первым параметром (в данном случае GL_COLOR), значением, указанным в третьем параметре. Второй параметр, drawBuffer, используется в случае, если есть несколько буферов, которые могут быть очищены. Поскольку мы используем всего один буфер, а drawBuffer это индекс с нулевым основанием, в этом примере мы просто передаём 0. Цвет хранится в массиве red, состоящем из четырёх значений с плавающей точкой -- по одному на каждую компоненту: красный, зеленый, синий, альфа (и именно в таком порядке). Значение компонент "красный", "зелёный" и "синий" должно быть понятно из их названия. Альфа -- четвёртый компонент, связанный с цветом, и обычно используется для указания непрозрачности фрагмента. В таком случае, установка альфа в ноль делает фрагмент полностью прозрачным, а установка в единицу -- непрозрачным. Значение альфа сохраняется в выходном изображении и используется некоторыми частями OpenGL даже если вы этого не видите. Вы видите, что мы установили компоненты красный и альфа в единицу, а остальные в ноль. Это означает непрозрачный красный цвет. Результат работы этого приложения показан на Рисунке 2.1.
Это начальное приложение не особо интересно1, т.к. всё, что оно делает, это заполнение окна сплошным красным цветом. Заметьте, что наша функция render() принимает единственный параметр -- currentTime. Он содержит время, прошедшее с момента запуска приложения, и мы можем использовать его для создания простой анимации. Например, мы можем использовать его для изменения цвета, которым мы закрашиваем окно. Изменённая функция render()2 представлена в Листинге 2.2.
1. Этот пример особенно не интересен, если вы читаете черно-белый вариант этой книги.
2. Если вы решите скопировать этот код в ваш собственный пример, вам потребуется подключить <math.h> для объявления функций sin() и cos().
Функция glClearBufferfv() говорит OpenGL очистить буфер, указываемый первым параметром (в данном случае GL_COLOR), значением, указанным в третьем параметре. Второй параметр, drawBuffer, используется в случае, если есть несколько буферов, которые могут быть очищены. Поскольку мы используем всего один буфер, а drawBuffer это индекс с нулевым основанием, в этом примере мы просто передаём 0. Цвет хранится в массиве red, состоящем из четырёх значений с плавающей точкой -- по одному на каждую компоненту: красный, зеленый, синий, альфа (и именно в таком порядке). Значение компонент "красный", "зелёный" и "синий" должно быть понятно из их названия. Альфа -- четвёртый компонент, связанный с цветом, и обычно используется для указания непрозрачности фрагмента. В таком случае, установка альфа в ноль делает фрагмент полностью прозрачным, а установка в единицу -- непрозрачным. Значение альфа сохраняется в выходном изображении и используется некоторыми частями OpenGL даже если вы этого не видите. Вы видите, что мы установили компоненты красный и альфа в единицу, а остальные в ноль. Это означает непрозрачный красный цвет. Результат работы этого приложения показан на Рисунке 2.1.
Это начальное приложение не особо интересно1, т.к. всё, что оно делает, это заполнение окна сплошным красным цветом. Заметьте, что наша функция render() принимает единственный параметр -- currentTime. Он содержит время, прошедшее с момента запуска приложения, и мы можем использовать его для создания простой анимации. Например, мы можем использовать его для изменения цвета, которым мы закрашиваем окно. Изменённая функция render()2 представлена в Листинге 2.2.
1. Этот пример особенно не интересен, если вы читаете черно-белый вариант этой книги.
2. Если вы решите скопировать этот код в ваш собственный пример, вам потребуется подключить <math.h> для объявления функций sin() и cos().
→Click here to view code image
// Include the "sb6.h" header file
#include "sb6.h"
// Derive my_application from sb6::application
class my_application : public sb6::application
{
public:
// Our rendering function
void render(double currentTime)
{
// Simply clear the window with red
static const GLfloat red[] = { 1.0f, 0.0f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, red);
}
};
// Our one and only instance of DECLARE_MAIN
DECLARE_MAIN(my_application);
Listing 2.1: Our first OpenGL application
// Include the "sb6.h" header file
#include "sb6.h"
// Derive my_application from sb6::application
class my_application : public sb6::application
{
public:
// Our rendering function
void render(double currentTime)
{
// Simply clear the window with red
static const GLfloat red[] = { 1.0f, 0.0f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, red);
}
};
// Our one and only instance of DECLARE_MAIN
DECLARE_MAIN(my_application);
Listing 2.1: Our first OpenGL application
0 Click here to view code image
// Подключение заголовочного файла sb6.h
#include "sb6.h"
// Наследуем my_application от sb6::application
class my_application : public sb6::application
{
public:
// Наша функция рендера
void render(double currentTime)
{
// Простая очистка окна красным цветом
static const GLfloat red[] = { 1.0f, 0.0f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, red);
}
};
// Наш единственный экземпляр DECLARE_MAIN
DECLARE_MAIN(my_application);
Листинг 2.1: Наше первое OpenGL приложение
// Подключение заголовочного файла sb6.h
#include "sb6.h"
// Наследуем my_application от sb6::application
class my_application : public sb6::application
{
public:
// Наша функция рендера
void render(double currentTime)
{
// Простая очистка окна красным цветом
static const GLfloat red[] = { 1.0f, 0.0f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, red);
}
};
// Наш единственный экземпляр DECLARE_MAIN
DECLARE_MAIN(my_application);
Листинг 2.1: Наше первое OpenGL приложение
Резюме
- Пол:
- мужчина
- Родной язык:
- русский
- С нами:
- с 18 октября 2010 г. (5845 дней) по приглашению notabenoid
- Деятельность:
-
272 версии перевода
с общим рейтингом 21
3 комментария
Карма: 4 (оценок: 4)
