Я и мой друг разрабатываем редактор (подобный CAD) для использования в нашей будущей игре.
Мы используем фреймворк Qt и OpenGL.
Проблема, с которой мы сталкиваемся, заключается в том, что на его ноутбуке со встроенной картой nVidia затенение работает, как и ожидалось, и хорошо воспроизводится. На моем ноутбуке с интегрированной картой ATI, а также на моем настольном компьютере с Radeon HD5850 подсветка фонга ведет себя немного иначе. Есть более яркие пятна и темные пятна, и изображение выглядит не очень хорошо. Кроме того, мы используем Toon Shader, чтобы нарисовать силуэт по краям и ограничить количество оттенков, которые может иметь цвет.
В шейдере Toon используется двухпроходный рендеринг — первый проход визуализирует объект в черном цвете, немного больше оригинала (слегка смещая каждую вершину в направлении нормали), чтобы создать силуэт, а затем второй проход визуализирует объект в обычном режиме (только ограничивая спектр оттенка). так выглядит более комично).
Изображения одинаковы на наших двух компьютерах. Первое отличие, которое я упомянул выше, второе: силуэт растягивается, как и должно быть на компьютере моих друзей, поэтому он создает ровный силуэт вокруг объекта, но слегка перемещается на моем компьютере, делая толстую линию на сверху и без линии снизу.
Другая вещь — освещение фонга, освещающее куб, в котором редактируется объект. Опять же, хорошо рендеринг на компьютере моих друзей, но почти полностью черный или белый на моем.
Я понимаю, что код длинный и, возможно, проблема кроется в некоторых настройках Qt, а не в шейдерах, но если вы видите что-то, что кажется вам плохой практикой, пожалуйста, ответьте.
Код для затенения фонга следует
#version 400
in vec4 aVertex;
in vec4 aNormal;
in vec2 aTexCoord;
uniform mat4 uPVM;
uniform mat4 uViewModel;
uniform mat4 uNormal;
uniform int uLightsOn;
out vec2 vTexCoord;
out vec3 vNormal;
flat out vec3 mEye;
flat out vec3 mLightDirection;
flat out vec4 mAxisColor;
void main(void)
{
if(uLightsOn == 1) {
mEye = (uViewModel * aVertex).xyz;
mLightDirection = vec4(2.0,-2.0,1.0,0.0).xyz;
vNormal = (uNormal * aNormal).xyz;
}
gl_Position = uPVM * aVertex;
vTexCoord = aTexCoord;
mAxisColor = aNormal;
}
Фрагмент фонетного шейдера:
#version 400
uniform sampler2D uTexture0;
uniform int uLightsOn;
uniform vec3 uHighlightColor;
uniform int uTextured;
uniform int uAxisRender;
in vec2 vTexCoord;
in vec3 vNormal;
flat in vec3 mEye;
flat in vec3 mLightDirection;
out vec4 fragColor;
flat in vec4 mAxisColor;
struct TMaterial {
vec4 diffuse;
vec4 ambient;
vec4 specular;
float shininess;
};
TMaterial material;
void setup() {
// setupMaterials
material.ambient = vec4(0.4);
material.diffuse = vec4(0.9);
material.specular = vec4(0.0);
material.shininess = 0.3;
}
void main(void)
{
setup();
vec3 finalHighlightColor = uHighlightColor;
if(finalHighlightColor.x <= 0.0) finalHighlightColor.x = 0.1;
if(finalHighlightColor.y <= 0.0) finalHighlightColor.y = 0.1;
if(finalHighlightColor.z <= 0.0) finalHighlightColor.z = 0.1;
if(uLightsOn == 0) {
if(uAxisRender == 1) fragColor = mAxisColor;
else fragColor = vec4(finalHighlightColor,1.0);
return;
}
vec4 diffuse;
vec4 spec = vec4(0.0);
vec4 ambient;
vec3 L = normalize(mLightDirection - mEye);
vec3 E = normalize(-mEye);
vec3 R = normalize(reflect(-L,vNormal));
ambient = material.ambient;
float intens = max(dot(vNormal,L), 0.0);
diffuse = clamp( material.diffuse * intens , 0.0, 1.0 );
if(intens > 0.0) spec = clamp ( material.specular * pow(max(dot(R,E),0.0),material.shininess) , 0.0, 1.0 );
if(uTextured == 1) fragColor = (ambient + diffuse + spec) * texture(uTexture0,vTexCoord);
else fragColor = (ambient + diffuse + spec) * vec4(finalHighlightColor,1.0);
}
И шейдеры Toon:
#version 400
in vec4 aVertex;
in vec4 aNormal;
in vec2 aTexCoord;
uniform mat4 uPV;
uniform mat4 uM;
uniform mat4 uN;
uniform vec3 uLightPosition;
uniform vec3 uCameraPosition;
uniform int uSilhouetteMode;
uniform float uOffset;
// if this uniform is passed, all the toon rendering is going off and only simple axis are rendered
// last data in aNormal are colors of those axis if everything was ser properly.
uniform int uAxisRendering;
flat out vec4 fAxisColor;
out vec4 vNormal;
out vec2 vTexCoord;
out vec3 vDirectionToCamera;
out vec3 vDirectionToLight;void silhouetteMode() {
gl_Position = uPV * uM * vec4(aVertex.xyz + aNormal.xyz * uOffset,1.0f);
}
void toonMode() {
vec4 worldPosition = uM * aVertex;
vDirectionToCamera = uCameraPosition - worldPosition.xyz;
vDirectionToLight = uLightPosition - worldPosition.xyz;
vNormal = uN * aNormal;
gl_Position = uPV * worldPosition;
}
void axisMode() {
fAxisColor = aNormal;
gl_Position = uPV * uM * aVertex;
}
void main(void)
{
vTexCoord = aTexCoord;
if(uSilhouetteMode == 1) {
silhouetteMode();
} else {
if(uAxisRendering == 1) axisMode();
else toonMode();
}
}
и фрагмент шейдера
#version 400
uniform sampler2D uTexture;
uniform vec3 uBaseColor;
uniform float uNumShades;
uniform int uSilhouetteMode;
uniform int uAxisRendering;
flat in vec4 fAxisColor;
in vec4 vNormal;
in vec2 vTexCoord;
in vec3 vDirectionToCamera;
in vec3 vDirectionToLight;
out vec4 outFragColor;
void main(void)
{
if(uSilhouetteMode == 1) {
outFragColor = vec4(uBaseColor,1.0);
return;
}
if(uAxisRendering == 1) {
outFragColor = fAxisColor;
return;
}
float l_ambient = 0.1;
float l_diffuse = clamp(dot(vDirectionToLight,vNormal.xyz),0.0,1.0);
float l_specular;
vec3 halfVector = normalize(vDirectionToCamera + vDirectionToLight);
if(dot(vDirectionToLight,vNormal.xyz) > 0.0) {
l_specular = pow(clamp(dot(halfVector,vNormal.xyz),0.0,1.0),64.0);
} else {
l_specular = 0.0;
}
float intensity = l_ambient + l_diffuse + l_specular;
float shadeIntesity = ceil(intensity * uNumShades)/ uNumShades;
outFragColor = vec4(texture(uTexture,vTexCoord).xyz * shadeIntesity * uBaseColor,1.0);
}
И, наконец, наша инициализация OpenGLWindow (в Qt)
OpenGLWindow::OpenGLWindow(QWindow *parent) :
QWindow(parent),m_animating(false), m_initialized(false), m_animationTimer(NULL)
{
setSurfaceType(QWindow::OpenGLSurface);
QSurfaceFormat format;
format.setDepthBufferSize( 24 );
format.setMajorVersion( 4 );
format.setMinorVersion( 0 );
format.setSamples( 4 );
format.setProfile( QSurfaceFormat::CoreProfile );
setFormat( format );
create();
if(!m_context) {
m_context = new QOpenGLContext(this);
m_context->setFormat(requestedFormat());
m_context->create();
m_context->makeCurrent(this);
initializeOpenGLFunctions();
}
m_animationTimer = new QTimer(this);
connect(m_animationTimer, SIGNAL(timeout()), this, SLOT(renderer()));
m_animationTimer->setInterval(16);
}
На мой взгляд, изображение nVidia, похоже, использует альфу, а AMD — нет. Я тоже не вижу
format.setAlpha(true);
в вашей настройке Qt так может быть.