У меня действительно странная проблема, я не могу pin down
в течение нескольких дней. Я делаю простое освещение для каждой вершины, и оно отлично работает на Nvidia
, но не делает ничего затененного светом AMD/ATI
, Я обнаружил, что проблема связана с атрибутами — особенно с атрибутом цвета.
Это мой вершинный шейдер:
#version 140
uniform mat4 modelViewProjectionMatrix;
in vec3 in_Position; // (x,y,z)
in vec4 in_Color; // (r,g,b,a)
in vec2 in_TextureCoord; // (u,v)
out vec2 v_TextureCoord;
out vec4 v_Color;
uniform bool en_ColorEnabled;
uniform bool en_LightingEnabled;
void main()
{
if (en_LightingEnabled == true){
v_Color = vec4(0.0,1.0,0.0,1.0);
}else{
if (en_ColorEnabled == true){
v_Color = in_Color;
}else{
v_Color = vec4(0.0,0.0,1.0,1.0);
}
}
gl_Position = modelViewProjectionMatrix * vec4( in_Position.xyz, 1.0);
v_TextureCoord = in_TextureCoord;
}
Это пиксельный шейдер:
#version 140
uniform sampler2D en_TexSampler;
uniform bool en_TexturingEnabled;
uniform bool en_ColorEnabled;
uniform vec4 en_bound_color;
in vec2 v_TextureCoord;
in vec4 v_Color;
out vec4 out_FragColor;
void main()
{
vec4 TexColor;
if (en_TexturingEnabled == true){
TexColor = texture2D( en_TexSampler, v_TextureCoord.st ) * v_Color;
}else if (en_ColorEnabled == true){
TexColor = v_Color;
}else{
TexColor = en_bound_color;
}
out_FragColor = TexColor;
}
Таким образом, этот шейдер допускает 3 состояния — когда я использую источники света, когда я не использую источники света, но использую цвет для каждой вершины и когда я использую один цвет для всех вершин. Я удалил весь код вычисления light, потому что отследил проблему до атрибута. Это вывод из шейдера:
Как вы можете видеть, все синее (поэтому он отображает все, что не имеет затенения или цвета (en_LightingEnabled == false and en_ColorEnabled == false)
).
Когда я заменяю этот код в вершинном шейдере:
if (en_ColorEnabled == true){
v_Color = in_Color;
}else{
с этим:
if (en_ColorEnabled == true){
v_Color = vec4(1.0,0.0,0.0,1.0);
}else{
Я получаю следующее:
Итак, вы можете видеть, что он рендерит все без затенения по-прежнему синим, но теперь он также рендерит все, что использует свет (en_LightingEnabled == true
) зеленым цветом Так должно быть. Проблема в том, что in_Color
Атрибут не должен мешать источнику света, так как он даже не будет работать, если источники света включены. Вы также можете видеть, что на изображении нет ничего красного, что означает в этой сцене en_ColorEnabled
всегда false
, Так in_Color
здесь абсолютно бесполезно, но оно вызывает ошибки в тех местах, которые по логике не должны. На Nvidia
это работает хорошо, и зеленые области рисуют с или без in_Color
,
Я использую что-то AMD
не поддерживает? Я использую что-то снаружи GLSL
спекуляция? я знаю AMD
строже GL
спецификация чем Nvidia
так что возможно я делаю что-то неопределенное. Я сделал код как можно более простым и все еще имею проблему, поэтому я не вижу его.
Кроме того, я заметил, что он не будет рисовать НИЧЕГО (даже синие области) на экране, если in_Color
атрибут вершины отключен (нет glEnableVertexAttribArray
), но почему? Я даже не использую цвет. Отключенные атрибуты нужно вернуть (0,0,0,1
) по спецификации верно? Я пытался с помощью glVertexAttrib4f
изменить этот цвет, но все равно стал черным. Компилятор и компоновщик не возвращает никаких ошибок или предупреждений. Атрибут in_Color найден просто отлично с glGetAttribLocation
, Но, как я уже сказал, ничего из этого не должно иметь значения, так как эта ветвь никогда не выполняется в моем коде. Есть идеи?
Проверено на Nvidia660Ti
и работает отлично, проверено на ATI
mobility radeon HD 5000
Ноутбук и есть эта ошибка. Моя единственная идея состояла в том, что, может быть, я превосхожу возможности GPU
(слишком много атрибутов и т. д.), но когда я сократил свой код до этого, я перестал в это верить. Я использую только 3 атрибута здесь.
Кроме того, некоторые из моих друзей тестировались на гораздо более новых AMD
карты и получил ту же проблему.
ОБНОВЛЕНИЕ 1
Атрибуты вершины связаны так:
if (useColors){
glUniform1i(uni_colorEnable,1);
glEnableVertexAttribArray(att_color);
glVertexAttribPointer(att_color, 4, GL_UNSIGNED_BYTE, GL_TRUE, STRIDE, OFFSET(offset));
}else{
glUniform1i(uni_colorEnable,0);
}
Кроме того, я нашел, как показать странность еще проще — возьмите этот вершинный шейдер:
void main()
{
v_Color = clamp(vec4(1.,1.,1.,1.) * vec4(0.5,0.5,0.25,1.),0.0,1.0) + in_Color;
gl_Position = modelViewProjectionMatrix * vec4( in_Position.xyz, 1.0);
v_TextureCoord = in_TextureCoord;
}
Так что нет ветвления. И я получаю это:
Если я изменю этот код, удалив in_Color
вот так:
void main()
{
v_Color = clamp(vec4(1.,1.,1.,1.) * vec4(0.5,0.5,0.25,1.),0.0,1.0);
gl_Position = modelViewProjectionMatrix * vec4( in_Position.xyz, 1.0);
v_TextureCoord = in_TextureCoord;
}
Я получаю это:
Последний — то, что я ожидаю, но предыдущий ничего не рисует, хотя я делаю дополнение (+
) вместо всего остального. Так что если attrib
не связан и (0,0,0,0
) или же (0,0,0,1
), то это не должно было ничего делать. И все же это все еще не удается.
Кроме того, все журналы пусты — компиляция, компоновка и проверка. Нет ошибок или предупреждений. Хотя я заметил, что информация отладки шейдера AMD/ATI
дает значительно уступает тому, что Nvidia
дает.
ОБНОВЛЕНИЕ 2
Единственное исправление, которое я нашел, было включить attribarray
во всех случаях (так что в основном отправляет мусор GPU
когда цвет не включен), но поскольку я использую униформу для проверки цвета, то я просто не использую ее. Итак, это так:
if (useColors){
glUniform1i(uni_colorEnable,1);
}else{
glUniform1i(uni_colorEnable,0);
}
glEnableVertexAttribArray(att_color);
glVertexAttribPointer(att_color, 4, GL_UNSIGNED_BYTE, GL_TRUE, STRIDE, OFFSET(offset));
Я понятия не имею, почему это происходит или почему мне нужно это использовать. Мне это не нужно Nvidia
, Итак, я думаю, что это медленнее, и я трачу трафик? Но, по крайней мере, это работает … Справка о том, как сделать это лучше, была бы полезна.
Вероятно, это происходит потому, что вы указываете 3 входных значения для шейдера (in_Position, in_Color и in_TextureCoord), но ваши данные вершин не всегда содержат все 3. Когда атрибуты вершин не соответствуют этому формату точно, вы попадаете в неопределенное поведение территория и каждая реализация может делать то, что хочет.
Похоже, что драйвер Nvidia связывает то, что он имеет, с соответствующими атрибутами вершин и визуализирует с этим.
То есть ваши данные выглядят как расположение ниже для шейдера:
in_Position = Position.xyz
in_Color = ???
in_TextureCoords = TextureCoords.xy
Драйвер AMD, вероятно, пытается интерпретировать данные вершин как все 3 атрибута, даже если цвет не включен. После первой вершины позиция не синхронизирована с позицией в массиве данных, что может привести к тому, что она будет визуализироваться практически везде. Я подозреваю, что причина того, что он работает на AMD при удалении использования атрибута in_Color, заключается в том, что шейдерный компилятор видит, что он не используется, и оптимизирует тот факт, что вы его указали.
in_Position = Position[0].xyz
in_Color = TextureCoords[0].xy,Position[1].xy
in_TextureCoords = Position[1].z,TextureCoords[1].x
Возможные решения — сделать то, что вы уже сделали, и указать данные цвета мусора, когда вам это не нужно, или вы можете разбить ваш вершинный шейдер на 2 отдельных с разными атрибутами вершин и связать соответствующий в зависимости от того, есть ли у вас вершина. данные о цвете.