Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Доступ к унифицированным блокам из приложения





Поскольку унифицированные переменные составляют некий мост, ко которому информация разделяется между шейдерами и вашим приложением, вам нужно найти адреса разных унифицированных переменных внутри проименнованных унифицированных блоков в ваших шейдерах. Когда вы узнаете расположение этих переменных, вы можете инициализировать их с данными, как любой другой тип объекта буфера (с помощью вызова glBufferData(), например).

Для начала, давайте предположим, что вы уже знаете наименования унифицированных блоков, используемых вашим шейдером. Первым шагом по инициализации унифицированных переменных в вашем блоке будет получение индекса блока для данной программы. Вызов glGetUniformBlockIndex() выдает важную информацию о создании карты унифицированных переменных для использования в адресном пространстве вашей программы.

GLuint glGetUniformBlockIndex(GLuint program,

const char * uniformBlockName);

Returns the index of the named uniform block specified by

uniformBlockName associated with program. If uniformBlockName is not a

valid uniform block of program, GL_INVALID_INDEX is returned.

 

Для инициализации объекта буфера в ассоциации с вашим унифицированным блоком, вам понадобится привязать объект буфера к GL_UNIFORM_BUFFER используя glBindBuffer() как показано в примере ниже (в Главе 3 будет дано больше деталей).

Когда объект бкфера инициализирован, нам нужно определить наколько большим его сделать для вмещения переменных в проименнованом унифицированном блоке из нашего шейдера. Для этого процедура glGetActiveUniformBlock() запрашивает GL_UNIFORM_BLOCK_DATA_SIZE, которая выдает размер блоков генерированный компилятором (компилятор может удалить унифицированные переменные, не использумые шейдером, в зависимости от того, какой макет блока вы выбрали).

После получения индекса унифицированного блока, нам нужно ассоциировать объект буфера с этим блоком. Самый обычный способ это сделать - вызовом glBindBufferRange() или же, если все хранилища буфера заняты унифицированным блоком, glBindBufferBase().

void glBindBufferRange(GLenum target, GLuint index,

GLuint buffer, GLintptr offset,

GLsizeiptr size);

void glBindBufferBase(GLenum target, GLuint index,

GLuint buffer);

Associates the buffer object buffer with the named uniform block

associated with index. target can either be GL_UNIFORM_BUFFER (for

uniform blocks) or GL_TRANSFORM_FEEDBACK_BUFFER (for use with

transform feedback; Chapter 5). index is the index associated with a

uniform block. offset and size specify the starting index and range of the

buffer that is to be mapped to the uniform buffer.

Calling glBindBufferBase() is identical to calling glBindBufferRange()

with offset equal to zero and size equal to the size of the buffer object.

These calls can generate various OpenGL errors: A GL_INVALID_VALUE

is generated if size is less than zero; if offset + size is greater than the size

of the buffer; if either offset or size is not a multiple of 4; or if index is less

than zero, or greater than or equal to the value returned when querying

GL_MAX_UNIFORM_BUFFER_BINDINGS.

 

Когда ассоциация проименованного унифицированного блока и объекта буфера завершена, вы можете инициализировать или изменить значения в этом блоке при помощи команд, воздействующих на значения буфера.

Возможно, вам также понадобится указать привязку для определенного проименнованного унифицированного блока к объекту буфера, как компановщик может задать привязку блока и после запросить значение привязки. Вы можете воспользоваться тем же методом если у вас есть множество шейдеров, которые используют один унифицированный блок. Это позволяет назначить блоку отдельный индекс для каждой программы. Для прямого управления привязкой унифицированного блока, запросите glUniformBlockBinding() до запроса glLinkProgram()

GLint glUniformBlockBinding(GLuint program,

GLuint uniformBlockIndex,

GLuint uniformBlockBinding);

Explicitly assigns uniformBlockIndex to uniformBlockBinding for

program.

 

Макет унифицированных переменных внутри блока контролируется квалификатором макета определяющимся в момент компиляции и прикрепления блока. Если вы воспользовались спецификацией блока по умолчанию, вам будет необходимо будет указать адрес и размер хранилища данных каждой переменной блока. Для этого вы можете воспользоваться парой запросов: glGetUniformIndeces(), для получения индексов определенных проименованных унифицированных переменных, и glGetActiveUniformsiv(), для получения адреса и размера определенного индекса, как показано в Примере 2.4

void glGetUniformIndices(GLuint program,

GLsizei uniformCount,

const char ** uniformNames,

GLuint * uniformIndices);

Returns the indices associated with the uniformCount uniform variables

specified by name in the array uniformNames in the array uniformIndices

for program. Each name in uniformNames is assumed to be NULL

terminated, and both uniformNames and uniformIndices have

uniformCount elements in each array. If a name listed in uniformNames is

not the name of an active uniform variables, the value

GL_INVALID_INDEX is returned in the corresponding element in

uniformIndices.

 

Пример 2.4 Инициализация унифицированных переменных и проименованных унифицированных блоков

[пример до стр. 69]

 

Блоки буфера

 

Блоки буфера GLSL (для приложения они shader storage buffer objects), работают в целом также как унифицированные блоки. Два критических отличия, которые делают эти блоки более мощными, заключаются в том, что, во-первых, шейдер может писать в них, модифицируя их содержание для запросов другими шейдрами и для приложения; во-вторых, их размер можно установить непосредственно перед визуализацией, а не во время привязки. Например:

buffer BufferObject { // create a read-writeable buffer

int mode; // preamble members

vec4 points []; // last member can be unsized array

};

Если массиву, который мы видим выше не задать размер в шейдере, тогда его размер будет определен приложением перед визуализацией, после компиляции и привязки. Шейдер может использовать метод lenght() для вычисления размера при рендеринге.

Шейдер теперь может и читать и писать компоненты блока буфера. Записи, изменяющие объект хранилища буфера будут видимы для запросов других шейдеров. Это может принести особую пользу на стадии вычислительного шейдера, особенно при работе с неграфическими данными.

Квалификаторы памяти (напр., coherent) и ядерные операции применимы к блокам буфера, и о них читайте в Главе 11, “Паямть”.

Вы устанавливаете объект хранилища шейдера так же, как унифицированный буфер, с той лишь разницей, что glBindBuffer() и glBufferData() направлены на GL_SHADER_STORAGE_BUFFER. Более полный пример приведен в Главе 11, “Память”...

Если вам не нужно писать в буфер, используйте унифицированный блок, поскольку у вашего оборудования может не оказать для блоков буфера достаточного количества памяти.

 

Блоки In/Out

Переменный шейдеров, которые вводятся в него и выводятся на следующую стадию, можно организовать в блоки интерфейса. Эти логические группы могут облегчить визуальную проверку совпадений интерфейса между стадиями, а также сделают привязку разных программ проще.

Например, вершинный шейдер выводит данные:

out Lighting {

vec3 normal;

vec2 bumpCoord;

};

 

Эти данные совпадают с данными ввода фрагментарного шейдера:

in Lighting {

vec3 normal;

vec2 bumpCoord;

};

 

Данные вывода вершинного шейдера, помеченные material и lighting, каждые сгруппированы в свой блок. Интерфейсы, встроенные в OpenGL Shading Language, также представлены в виде блоков, как например, gl_PerVertex, в котором есть встроенная переменная gl_Positions, помимо прочих. Полный список этих блоков находится в Appendix C

 

Компилирование шейдеров

 

Написание шейдеров для OpenGL схоже с использованием языка “С”, основанного на компиляции. Вы задаете компилятору анализировать ваше программу, проверить на ошибки, а потом перевести ее в код объектов. Далее, вы объединяете набор объектов вместе в фазе привязки, для создания выполняемой программы. Использование GLSL шейдеров в вашей программе - схожий процесс, за тем лишь исключением, что компилятор и компоновщик оба являются частью API OpenGL.

Диаграмма 2.1 показывает шаги по созданию объекта шейдера GLSL и привязки его к исполняемой программе шейдера.

[картинка]

 

Для каждой программы, которую вы хотите использовать в вашем приложении, вам понадобится следующая последовательность шагов:

Для каждого объекта:

1. Создать объект шейдера.

2. Компилировать код вашего шейдера в объект.

3. Проверить, успешно ли компилируется ваш шейдер.

Затем, для привязки нескольких объектов шейдера в программу, нужно:

1. Создать программу шейдера.

2. Прикрепить соответствующий объект шейдреа к программе шейдера.

3. Привязать программу шейдера.

4. Убедиться, что стадия привязки прошла успешно.

5. Использовать шейдер для обработки вершин или фрагментов.

 

Зачем создавать несоклько объектов шейдера? Точно так же, как можно повторно использовать функцию и другой программе, можно поступить и с программой GLSL. Общие процедуры, которые вы пишете, могут быть использованы в других шейдерах. Вместо того, чтобы писать несколько тяжелых программ шейдинга, использующих отрывки общего кода, вам понадобится лишь отослать шейдер к соответствующему объекту шейдера.

Для создания объекта шейдера запросите glCreateShader().

GLuint glCreateShader(GLenum type);

Allocates a shader object. type must be one of GL_VERTEX_SHADER,

GL_FRAGMENT_SHADER, GL_TESS_CONTROL_SHADER,

GL_TESS_EVALUATION_SHADER, or GL_GEOMETRY_SHADER. The

return value is either a nonzero integer or zero if an error occurred.

 

Когда вы закончите создание объекта шейдера, вам нужно будет ассоциировать исходный код шейдера с этим объектом, созданным glCreateShader(). Это делается вызовом glSHaderSource().

glShaderSource(GLuint shader, GLsizei count,

const GLchar **string, const GLint *length);

Associates the source of a shader with a shader object shader. string is an

array of count GLchar strings that compose the shader’s source. The

character strings in string may be optionally null-terminated. length can

be one of three values. If length is NULL, then it’s assumed that each

string provided in string is null-terminated. Otherwise, length has count

elements, each of which specifies the length of the corresponding entry

in string. If the value of an element in the array length is a positive

integer, the value represents the number of characters in the

corresponding string element. If the value is negative for particular

elements, then that entry in string is assumed to be null-terminated

 

Для компиляции кода объекта шейдера используйте glCompileshader().

void glCompileShader(GLuint shader);

Compiles the source code for shader. The results of the compilation can

be queried by calling glGetShaderiv() with an argument of

GL_COMPILE_STATUS.

 

По тому же принципу, что и компиляция программы на “С”, вам нужно убедиться, что компиляция пойдет успешно. Запрос к glGetShaderiv() с поправкой GL_COMPILE_STATUS возвращает статус фазы компиляции. Если приходит GL_TRUE, значит компиляция удалась, и объект можно привязать к программе. Если компиляция не удалась, вы можете определить, какая ошибка тому помешала, запросив лог компиляции. glGetSharedInfoLog() выдаст сообщения по использованию с записью ошибок компиляции. Текущий размер лога ошибок может быть запрошен вызовом glGetShaderiv() с поправкой GL_INFO_LOG_LENGTH.

"> void glGetShaderInfoLog(GLuint shader, GLsizei bufSize,

GLsizei *length, char *infoLog);

Returns the log associated with the last compilation of shader. The log is

returned as a null-terminated character string of length characters in the

buffer infoLog. The maximum return size of the log is specified in bufSize.

If length is NULL, infoLog’s length is not returned.

 

Когда вы создали и скомпилировали все необходимые объекты шейдеров, вам нужно будет привязать их для создания выполняемой программы шейдера. Это процесс схожий с созданием самих объектов ешйдера. Сначала вам нужно создать программу шейдера, к которой вы можете прикрепить объекты. Используя glCreateProgramm(), вы получите программу для дальнейшей с ней работы.

GLuint glCreateProgram(void);

Creates an empty shader program. The return value is either a n

integer, or zero if an error occurred.

 

Когда вы получите свою программу шейдера, вам нужно будет заполнить её необходимыми объектами шейдера, для создания исполняемой программы. Это сопровождается прикреплением объектов шейдера к программе посредством вызова glAttachShader()

void glAttachShader(GLuint program, GLuint shader);

Associates the shader object, shader, with the shader program, program. A

shader object can be attached to a shader program at any time, although

its functionality will only be available after a successful link of the shader

program. A shader object can be attached to multiple shader programs

simultaneously

 

Для контроля четности, вам нужно убрать объект шейдера из программы для модификации операций шейдера, отсоедините объект вызовом glDetachShader() с идетификатором объекта шейдра.

void glDetachShader(GLuint program, GLuint shader);

Removes the association of a shader object, shader, from the shader

program, program. If shader is detached from program and had been

previously marked for deletion (by calling glDeleteShader()), it is deleted

at that time.

 

После того, как все необходимые объекты шейдера были прикреплены к программе, вам привязать их к исполняемой программе. Это делается вызовом glLinkProgram().

void glLinkProgram(GLuint program);

Processes all shader objects attached to program to generate a completed

shader program. The result of the linking operation can be queried by

calling glGetProgramiv() with GL_LINK_STATUS. GL_TRUE is returned

for a successful link; GL_FALSE is returned otherwise.

 

Также как с объектами шейдеров, есть вероятность, что эта фаза не пройдет успешно из-за ошибок в привязанных объектах. Вы можете запросить результат операции привязки вызовом glGetProgramiv() с поправкой GET_LINK_STATUS. Если ответ будет в форме GL_TRUE, то операция прошла успешно, и вы можете определить шейдер для обработки вершин и фрагментов. Если привзяка не была успешной, придет ответ GL_FALSE. Вы можете определить причину ошибки запросом glGetProgramInfoLog()

void glGetProgramInfoLog(GLuint program, GLsizei bufSize,

GLsizei *length, char *infoLog);

Returns the log associated with the last compilation of program. The log

is returned as a null-terminated character string of length characters in

the buffer infoLog. The maximum return size of the log is specified in

bufSize. If length is NULL, infoLog ’s length is not returned.

 

После успешной привязки программы, вы можете запустить вершинный или фрагментарный шейдер вызовом glUseProgram() с дескриптором программы.

void glUseProgram(GLuint program);

Use the linked shader program program. If program is zero, any shaders

currently in use are unbound. OpenGL’s operation is undefined if no

shader is bound, but no error is generated.

While a program is in use, it can have new shader objects attached to it,

or detach previously attached objects. It may also be relinked. If the link

phase is successful, the newly linked shader program replaces the

previously active program. If the link fails, the currently bound shader

program remains active and is not replaced until either a new program is

specified with glUseProgram() or the program is successfully relinked.

 

Когда вы закончите работу с объектом шейдера,вы можете удалить его командой glDeleteShader(), даже если он прикреплен к активной программе. Также как с привязкой программы в “С”, когда у вас готово исполняемое приложение, вам больше не нужны объекты до тех пор, пока вы не повторите компиляцию.

void glDeleteShader(GLuint shader);

Deletes shader. If shader is currently linked to one or more active shader

programs, the object is tagged for deletion and deleted once the shader

program is no longer being used by any shader program.

 

Также, когда вы закончите с программой шейдера, вы можете её удалить через glDeleteProgram()

void glDeleteProgram(GLuint program);

Deletes program immediately if not currently in use in any context, or

schedules program for deletion when the program is no longer in use by

any contexts.

 

Наконец, для полного завершения вы также можете запросить, использыется ли имя файла каким-нибудь объектом шейдера, запросив glIsShader(), или для программы шейдера glIsProgram():

GLboolean glIsShader(GLuint shader);

Returns GL_TRUE if shader is the name of a shader object that was

previously generated with glCreateShader(), but has not been

subsequently deleted. Returns GL_FALSE if shader is zero or a nonzero

value that is not the name of a shader object.

 

GLboolean glIsProgram(GLuint program);

Returns GL_TRUE if program is the name of a program object that was

previously generated with glCreateProgram(), but has not been

subsequently deleted. Returns GL_FALSE if program is zero or a nonzero

value that is not the name of a program object.

 

Наша функция LoadShaders()

Для того, чтобы облегчить использования шейдров вашим приложением, мы создали LoadShaders() в помощь с загрузкой и созданием программ шейдеров. Мы используем её в нашей программе в Главе 1, чтобы загрузить простой набор шейдеров.

 

Подпрограммы шейдеров

Продвинутый уровень

Хотя GLSL позволяет определять функции шейдеров, поток запросов этих функций всегда статичен. Чтобы динамически выбирать между несколькими функциями, вы или создаете 2 разных шейдера, или используете if для выбора в настоящем времени, как показано в примере 2.5

Пример 2.5 Статичный поток контроля шейдера

#version 330 core

void func_1() {... }

void func_2() {... }

uniform int func;

Void

main()

{

if (func == 1)

func_1();

Else

func_2();

}

 

Подпрограммы шейдра схожи по понятию с указателями функций в “С” для введения динамического подпрограммного выбора. В вашем шейдере вы указываете тип подпрограмм и используете этот тип для заявления набора подпрограмм, действительных для динамического применения. Потом вы выбираете какую процедуру из набора исполнить шейдеру посредством установки унифицированной переменной подпрограмм.

 

Установка подпрограмм GLSL

 

Когда вы хотите воспользоваться выбором подпрограмм в шейдере, нужно проделать три операции для установки динамической области подпрограмм:

1. Определить тип подпрограмм использовав ключевое слово
subroutine returnType subroutineType(type param,...);
где returnType представляет любой допустимы тип данных, которые мжет выдать функция, а subroutineType - любое допустимое имя. также как с прототипами функций, необходимы только типы параметров, их имена - нет. (Подсказка: Представьте себе это в виде typedef языка “С”, где subroutineType будет новым представленным типом).

2. Использовав subroutineType, который вы назначили, определить набор подпрограмм, которые вы бы хотели динамически выбрать при помощи ключевого слова. Прототип подпрограммной функции выглядит так:
subroutine (subroutineType) returnType functionName(...);

3. И наконец, указать переменную подпрограммы, в которой будет содержаться “указатель функции” для подпрограммы, которую вы выбрали в своём приложении:
subroutine uniform subroutineType variableName;

 

Продемонстрируем эти операции вместе. В следующем примере мы бы хотели выбрать между внешним светом и рассеянным.

Пример 2.6 Объявление набора подпрограмм

subroutine vec4 LightFunc(vec3); // Step 1

subroutine (LightFunc) vec4 ambient(vec3 n) // Step 2

{

return Materials.ambient;

}

subroutine (LightFunc) vec4 diffuse(vec3 n) // Step 2 (again)

{

return Materials.diffuse *

max(dot(normalize(n), LightVec.xyz), 0.0);

}

subroutine uniform LightFunc materialShader; // Step 3

 

Подпрограммы не обязательно работают с одним типом (напр., LightFunc из Примера 2.6), вы можете запускать подпрограммы разных типов, добавив любой тип подпрограмм в список определения подпрограмм, как в примере,

subroutine void Type_1();

subroutine void Type_2();

subroutine void Type_3();

subroutine (Type_1, Type_2) Func_1();

subroutine (Type_1, Type_3) Func_2();

subroutine uniform Type_1 func_1;

subroutine uniform Type_2 func_2;

subroutine uniform Type_3 func_3;

 

В примере выше, func_1 может использовать или Func_1 или Func_2, потому что они все относится к Type_1. Однако, func_2, например, ограничена в использовании только с Func_1, и также func_3 - только с Func_2.

 

Выбор подпрограмм шейдеров

 

Когда вы определили ваши подпрограммы и функции в вашем шейдере, вам остаётся только запросить несколько значений из привязанной программы шейдера, чтобы в дальнейшем использовать эти значения для выбора соответствующей функции.

GLint glGetSubroutineUniformLocation(GLuint program,

GLenum shadertype,

const char* name);

Returns the location of the subroutine uniform named name in program

for the shading stage specified by shadertype. name is a null-terminated

character string, and shadertype must be one of GL_VERTEX_SHADER,

GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER,

GL_GEOMETRY_SHADER, or GL_FRAGMENT_SHADER.

If name is not an active subroutine uniform, minus one ( 1) is returned.

If program is not a successfully linked shader program, a

GL_INVALID_OPERATION error will be generated.

 

В операции 3 на стр. __ мы объявили унифицированное значение подпрограммы, и теперь нам нужно получить его адрес, чтобы мы могли видеть его. Схоже с униформами шейдера, униформы подпрограм используют glGetSubroutineUniformLocation() для выдачи положения.

GLuint glGetSubroutineIndex(GLuint program,

GLenum shadertype,

const char* name);

Returns the index of the shader function associated with name from

program for the shading stage specified by shadertype. name is a

null-terminated character string, and shadertype must be one of

GL_VERTEX_SHADER, GL_TESS_CONTROL_SHADER,

GL_TESS_EVALUATION_SHADER, GL_GEOMETRY_SHADER, or

GL_FRAGMENT_SHADER.

If name is not an active subroutine for the shader for shadertype,

GL_INVALID_INDEX is returned.

 

Когда вы получите доступные индексы подпрограм и их унифицированные значения, воспользуйтесь glUniformSubroutinesuiv() для назначения, какие подпрограммы должен использовать шейдер. Все активные подпрограммы для стадии шейдера должны быть инициализированы.

GLuint glUniformSubroutinesuiv(GLenum shadertype,

GLsizei count,

const GLuint * indices);

Sets count shader subroutine uniforms using the values in indices, for the

shader stage shadertype. shadertype must be one of GL_VERTEX_SHADER,

GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER,

GL_GEOMETRY_SHADER, or GL_FRAGMENT_SHADER. The ith

subroutine uniform will be assigned the value indices[i].

If count is not equal to the value of

GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the shader stage

shadertype for the currently bound program, a GL_INVALID_VALUE error

is generated. All values in indices must be less than

GL_ACTIVE_SUBROUTINES, or a GL_INVALID_VALUE error is generated.

 

Объединив все эти операции, мы получим следующий отрывок кода, который демонстрирует процесс работы вершинного шейдера, представленного в Примере 2.6:

GLint materialShaderLoc;

GLuint ambientIndex;

GLuint diffuseIndex;

glUseProgram(program);

materialShaderLoc = glGetSubroutineUniformLocation(

program, GL_VERTEX_SHADER, "materialShader");

if (materialShaderLoc < 0) {

// Error: materialShader is not an active subroutine

// uniform in the shader.

}

ambientIndex = glGetSubroutineIndex(program,

GL_VERTEX_SHADER,

"ambient");

diffuseIndex = glGetSubroutineIndex(program,

GL_VERTEX_SHADER,

"diffuse");

if (ambientIndex == GL_INVALID_INDEX ||

diffuseIndex == GL_INVALID_INDEX) {

// Error: the specified subroutines are not active in

// the currently bound program for the GL_VERTEX_SHADER

// stage.

}

else {

GLsizei n;

glGetIntegerv(GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, &n);

GLuint *indices = new GLuint[n];

indices[materialShaderLoc] = ambientIndex;

glUniformSubroutinesuiv(GL_VERTEX_SHADER, n, indices);

delete [] indices;

}

Примечание: вызов glUseProgram() сбросит все унифицированные переменные подпрограмм в порядок в зависимости от реализации.

 

Раздельные объекты шейдеров

Продвинутый уровень

До версии OpenGL 4.1 (без учета дополнений) только одна программа шейдера могла быть привязана в один момент времени к исполняемой программе. Это было неудобно, особенно если вам нужно было работать с несколькими фрагментарными шейдерами для обработки набора геометрии, которая трансформировалась посредством одного вершинного шейдера. Из-за этого приходилось использовать несколько одинаковых программ одного и того же вершинного шейдера, растрачивая впустую ресурсы и копируя код.

Раздельные объекты шейдеров позволяют разным стадиям шейдеров (напр., вершинному шейдеру) из разных программ собираться в один программный конвейер.

Первым делом нужно создать программу, которую можно использовать в конвейере. Это делается с помощью вызова glProgramParameteri() с параметром GL_PROGRAM_SEPARABLE до привязки в программе шейдера. Это помечает программу шейдера как применимую в конвейере. Для облегчения этой задачи, новая команда, glCreateShaderProgramv(), была добавлена. Эта команда включает в себя процесс компиляции шейдера, вместе с определение программы, как доступной для других программ (как упоминалось выше), и привязывает эту программу для создания конечного объекта.

Когда наборы программ шейдеров будут объединены, вам понадобится использовать конструкторы нового конвейера шейдреров, для объединения стадий шейдеров разных программ в конвейер программ, доступный для использования. Как и со всем объектами в OpenGL, вы используете набор запросов gen-bind-delete. Конвейер шейдеров создается командой glGenProgramPipelines(), которая создаст новый идентификатор программного конвейера, который вы передаёте в glBindProgramPipelines(), делая программу доступной для поправок (напр., добавления или замены стадий шейдинга), а затем и использования. Также как и с другими генерированными объектами, программные конвейеры удаляются запросом glDeleteProgramPipelines().

Когда вы связали программный конвейер, вы можете добавить в него программы, которые были помечены как сепарабельные, к вашему конвейеру вызовом glUseProgramStages(), для этого требуется описание в битовом поле, какие стадии из подключенной программы нужно использовать, когда данный конвейер обрабатывает данные геометрии и делает шейдинг объектов. Более старый glUseProgram() при запросе заменит нынешнюю привязку программного конвейера.

Интерфейсы для разных стадий шейдеров (in и out переменные) должны соответствовать порядку работы конвейера. В отличие от использования шейдера с нераздельными объектами, конвейер шейдеров с раздельными программными объектами нужно проверять на наличие проблем на стадии отрисовки(???). Если инрефейсы не совпадают, все изменяемые переменные (переменные вывода out) будут неопределены.

Встроенный блок gl_PerVertex должен быть переопределен для прямого указания, что будет использоваться подмножество интерфейса закрепленного конвейера. Это необходимо при использовании множества программ в вашем конвейере.

Наример,

out gl_PerVertex {

vec4 gl_Position; // makes gl_Position is part of interface

float gl_PointSize; // makes gl_PointSize is part of interface

}; // no more members of gl_PerVertex are used

 

Эта команда устанавливает интерфейс шейдера, который должен использовать конвейер на следующей стадии. Это должно быть подмножеством встроенных членов gl_PerVertex. Если встроенные блок используется несколькими программами конвейера, все одни должны заявлять этот блок одинаковым образом.

Поскольку отделяемые объекты могут каждый содержать свой набор униформ программ, существует два метода для назначения значений унифицированных переменных. Сначала вы выбираете активную программу шейдера при помощи glActiveShaderProgram(), тем самым назначив значения унифицированным переменным данной программы шейдера через glUniform*() и glUniformMatrix*(). Или же, что даже лучше, вызываете glProgramUniform*() и glProgramUniformMatrix*(), которые берут определенный объект программы в дополнение к другим использованным для индентификации униформ программы параметрам.

void glProgramUniform{1234}{fdi ui}(GLuint program,

GLint location,

TYPE value);

void glProgramUniform{1234}{fdi ui}v(GLuint program,

GLint location,

GLsizei count,

const TYPE * values);

void glProgramUniformMatrix{234}{fd}v(GLuint program,

GLint location,

GLsizei count,

GLboolean transpose,

const GLfloat * values);

void glProgramUniformMatrix{2x3,2x4,3x2,3x4,4x2,4x3}{fd}v(

GLuint program, GLint location,

GLsizei count,

GLboolean transpose,

const GLfloat * values);

glProgramUniform*() and glProgramUniformMatrix*() routines

operate exactly as glUniform*() and glUniformMatrix*(), except that

program specifies the shader program to update the uniform variable for.

The advantage of these routines is that program need not be the currently

bound program (i.e., the last specified shader program to

glUseProgram()).

 







ЧТО ТАКОЕ УВЕРЕННОЕ ПОВЕДЕНИЕ В МЕЖЛИЧНОСТНЫХ ОТНОШЕНИЯХ? Исторически существует три основных модели различий, существующих между...

ЧТО ПРОИСХОДИТ ВО ВЗРОСЛОЙ ЖИЗНИ? Если вы все еще «неправильно» связаны с матерью, вы избегаете отделения и независимого взрослого существования...

Что вызывает тренды на фондовых и товарных рынках Объяснение теории грузового поезда Первые 17 лет моих рыночных исследований сводились к попыткам вычис­лить, когда этот...

Система охраняемых территорий в США Изучение особо охраняемых природных территорий(ООПТ) США представляет особый интерес по многим причинам...





Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2024 zdamsam.ru Размещенные материалы защищены законодательством РФ.