deux joueurs rencontrent un problème avec mon jeu où l'écran se déchire quand il utilise un fragment shader mais il semble que cela ne soit le cas que pour les joueurs avec un GPU R9 380. Voici à quoi cela ressemble dans le jeu:
Après avoir travaillé avec l'un des joueurs, je l'ai limité à l'utilisation du shader, mais cela pourrait ne pas être fait correctement dans le code d'appel. Voici à quoi ressemble le shader (notez que j'apprends toujours le GLSL).
uniform sampler2D lightTexture;
uniform sampler2D targetTexture;
uniform sampler2D backgroundTexture;
uniform vec2 tileSize;
vec3 SaturationBrightness(vec3 color, float brt, float sat)
{
// Increase or decrease theese values to adjust r, g and b color channels seperately
const float AvgLumR = 0.5;
const float AvgLumG = 0.5;
const float AvgLumB = 0.5;
const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
vec3 brtColor = color * brt;
vec3 intensity = vec3(dot(brtColor, LumCoeff));
vec3 satColor = mix(intensity, brtColor, sat);
return satColor;
}
void main(void)
{
vec2 position;
position.s = gl_TexCoord[0].s;
position.t = gl_TexCoord[0].t;
vec4 lightColor = texture2D(lightTexture, position);
//Return the lighting if the light is pure dark since the tile behind it was not rendered
if (lightColor.r == 0.0 && lightColor.g == 0.0 && lightColor.b == 0.0) {
gl_FragColor = lightColor;
return;
}
//Get the average of the the nearby light
position.t -= tileSize.t;
vec4 lightColorUp = texture2D(lightTexture, position);
position.t += tileSize.t*2.0;
vec4 lightColorDown = texture2D(lightTexture, position);
position -= tileSize;
vec4 lightColorLeft = texture2D(lightTexture, position);
position.s += tileSize.s*2.0;
vec4 lightColorRight = texture2D(lightTexture, position);
position.s += tileSize.s;
vec4 lightColorFarRight = texture2D(lightTexture, position);
position.s -= tileSize.s*4.0;
vec4 lightColorFarLeft = texture2D(lightTexture, position);
position.s += tileSize.s*2.0;
position.t -= tileSize.t*2.0;
vec4 lightColorFarUp = texture2D(lightTexture, position);
position.t += tileSize.t*4.0;
vec4 lightColorFarDown = texture2D(lightTexture, position);
lightColor = lightColorRight + lightColorUp + lightColorDown + lightColorLeft + lightColorFarRight + lightColorFarUp + lightColorFarDown + lightColorFarLeft;
lightColor.r /= 8.0;
lightColor.g /= 8.0;
lightColor.b /= 8.0;
lightColor.a /= 8.0;
//Get the target (foreground) that we apply the light to
vec4 targetColor = texture2D(targetTexture, gl_TexCoord[0].st);
if (targetColor.a == 0.0) {
//Foreground is transparent meaning that we never rendered to it so instead render the background without light
gl_FragColor = texture2D(backgroundTexture, gl_TexCoord[0].st);
} else {
//Apply averaged light to target
gl_FragColor = vec4(SaturationBrightness(lightColor.rgb, 1.15, 1.1), lightColor.a) * targetColor;
}
}
Voici le code backend (c ++) utilisant SFML.
SpecialRenderTexturePtr targetTexture = boost::static_pointer_cast<SpecialRenderTexture>(target);
targetTexture->display();
m_texture->setView(m_view);
m_texture->clear(Color(0, 0, 0, 255));
m_texture->draw(m_vertices);
m_texture->display();
m_shader.setParameter("lightTexture", m_texture->getTexture());
m_shader.setParameter("targetTexture", targetTexture->getTexture());
m_shader.setParameter("backgroundTexture", m_render->getBackgroundTexture()->getTexture());
Vector tileSize(Sizes::SUBTILE / 2.0 / m_texture->getSize().x, Sizes::SUBTILE / 2.0 / m_texture->getSize().y);
m_shader.setParameter("tileSize", tileSize.toSfml());
sf::Sprite lightSprite(m_texture->getTexture());
Vector viewPosition = m_view.getCenter();
const Vector& viewSize = m_view.getSize();
viewPosition.x = ceil(viewPosition.x - (viewSize.x / 2.0f));
viewPosition.y = ceil(viewPosition.y - (viewSize.y / 2.0f));
lightSprite.setPosition(viewPosition.toSfml());
target->draw(lightSprite, &m_shader);
Y a-t-il quelque chose d'évident ici que je manque que je ne devrais pas faire. Quelqu'un connaît-il des problèmes avec les pilotes R9 380? En regardant le déchirement de ce que je suppose, c'est que nous échantillonnons incorrectement à partir de la texture cible, mais je ne vois pas comment ni pourquoi.
Réponses:
J'y suis revenu aujourd'hui et après quelques investigations et essais et erreurs, j'ai découvert que le coupable était targetTexture. Avec un peu plus d'investigation, j'ai appris que lire et écrire sur la même texture dans un shader est une mauvaise pratique (sans surprise) et provoquera un comportement indéfini sur les GPU.
La solution consistait à copier la texture cible dans une nouvelle texture, puis à lire à partir de la copie tout en écrivant sur la texture cible d'origine.
la source