Hello! I'm doing a lighting system and I've been trying to apply shaders to a vertex array by doing the following. I generate the vertex array of the tilemap, generate the vertex array of the lightmap and draw it to a rendertexture and finally apply a shader to the tilemap which does a hard light blend of the tiles and the lights... but it doesn't work and I can't figure out where the problem is...
Minimal code:
#include "SFML/Graphics.hpp"
int main() {
sf::Texture tileMapTex;
tileMapTex.loadFromFile("tile.png");
sf::Shader lightShader;
lightShader.loadFromFile("shader.frag", sf::Shader::Fragment);
sf::RenderWindow window(sf::VideoMode(200, 100), "Shader problem", sf::Style::Close);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if(event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color(255, 127, 0));
sf::VertexArray lightvertex(sf::PrimitiveType::Quads,10 * 10 * 4),
tileVA(sf::PrimitiveType::Quads,10 * 10 * 4);
sf::RenderTexture lightMapTex;
unsigned int tileN = 0, lightN = 0;
for (unsigned int x = 0; x < 10; ++x) {
for (unsigned int y = 0; y < 10; ++y) {
tileVA[tileN].position = sf::Vector2f(x * 8, y * 8);
tileVA[tileN].texCoords = sf::Vector2f(0, 0);
tileVA[tileN + 1].position = sf::Vector2f(x * 8 + 8, y * 8);
tileVA[tileN + 1].texCoords = sf::Vector2f(7, 0);
tileVA[tileN + 2].position = sf::Vector2f(x * 8 + 8, y * 8 + 8);
tileVA[tileN + 2].texCoords = sf::Vector2f(7, 7);
tileVA[tileN + 3].position = sf::Vector2f(x * 8, y * 8 + 8);
tileVA[tileN + 3].texCoords = sf::Vector2f(0, 7);
tileN += 4;
lightvertex[lightN].position = sf::Vector2f(x * 8, y * 8);
lightvertex[lightN].color = sf::Color(127, 127, 127);
lightvertex[lightN + 1].position = sf::Vector2f(x * 8 + 8, y * 8);
lightvertex[lightN + 1].color = sf::Color(127, 127, 127);
lightvertex[lightN + 2].position = sf::Vector2f(x * 8 + 8, y * 8 + 8);
lightvertex[lightN + 2].color = sf::Color(127, 127, 127);
lightvertex[lightN + 3].position = sf::Vector2f(x * 8, y * 8 + 8);
lightvertex[lightN + 3].color = sf::Color(127, 127, 127);
lightN+=4;
}
}
tileVA.resize(tileN);
lightvertex.resize(lightN);
lightMapTex.draw(lightvertex);
lightShader.setParameter("tex", sf::Shader::CurrentTexture);
lightShader.setParameter("map", lightMapTex.getTexture());
sf::RenderStates states(&lightShader);
states.texture = &tileMapTex;
window.draw(tileVA, states);
window.display();
}
}
Fragment shader:
uniform sampler2D map;
uniform sampler2D tex;
void main(void)
{
vec4 mapPix = texture2D(map, gl_TexCoord[0].xy);
vec4 drawPix = texture2D(tex, gl_TexCoord[0].xy);
vec4 finalPix;
if(mapPix.r < 0.5) {
finalPix.r = 2.0 * mapPix.r * gl_Color.r * drawPix.r;
}
else {
finalPix.r = 1.0 - 2.0 * (1.0 - mapPix.r) * (1.0 - (gl_Color.r * drawPix.r));
}
if(mapPix.g < 0.5) {
finalPix.g = 2.0 * mapPix.g * gl_Color.g * drawPix.g;
}
else {
finalPix.g = 1.0 - 2.0 * (1.0 - mapPix.g) * (1.0 - (gl_Color.g * drawPix.g));
}
if(mapPix.b < 0.5) {
finalPix.b = 2.0 * mapPix.b * gl_Color.b * drawPix.b;
}
else {
finalPix.b = 1.0 - 2.0 * (1.0 - mapPix.b) * (1.0 - (gl_Color.b * drawPix.b));
}
finalPix.a = 1.0;
gl_FragColor = finalPix;
}
Note: All tiles are a 8x8 red square, all lights are white and the tile map is 10x10 for this test. Orange is where nothing is rendered (clear color). The result should be only red squares but it outputs black squares. If I replace finalPix with gl_Color * drawPix in the fragment shader for disabling the lights it works fine, so the problem is with the lights.