Bonjour,
Pour les besoins de mon jeu (un raycaster à la wolf3d) je dois passer un tableau de textures à mon fragment shader qui s'occupe du rendu (chose qui n'est pas possible de base avec sf::Shader)
Je passe donc par OpenGL pour ça, sauf que ca marche pas
Au niveau du shader je n'ai qu'un sampler2DArray vide (0 couches)
si j'envoie n'importe quel autre type au shader via glUniformxx ca marche sans pb...
Le code :
ShaderRenderSurface::ShaderRenderSurface(const sf::Vector2f &t_size)
{
if (!sf::Shader::isAvailable())
{
throw_shader_error("Shaders are not supported on this machine !");
}
m_drawTexture.create(t_size.x, t_size.y);
if (!m_renderShader.loadFromFile(c_glRenderShader, sf::Shader::Fragment))
{
throw_shader_error("Error loading shader '" + std::string(c_glRenderShader) + "' !");
}
m_drawSurface.setTexture(m_drawTexture);
glCheck(glGenTextures(1, &m_texArray));
sf::Shader::bind(&m_renderShader);
glCheck(glUniform1i(glGetUniformLocation(m_renderShader.getNativeHandle(), "u_textures"), 0)); // Texture unit 0
}
void ShaderRenderSurface::update(const sf::Time &)
{
updateUniforms();
}
void ShaderRenderSurface::setSize(const sf::Vector2f &t_size)
{
m_drawTexture.create(t_size.x, t_size.y);
}
void ShaderRenderSurface::loadTextureArray(const std::vector<sf::Image> &t_textures)
{
sf::Shader::bind(&m_renderShader);
Utility::createTextureArray(m_texArray, t_textures);
}
void ShaderRenderSurface::draw(sf::RenderTarget &t_target, sf::RenderStates t_states) const
{
t_states.shader = &m_renderShader;
t_target.draw(m_drawSurface, t_states);
}
void ShaderRenderSurface::updateUniforms()
{
m_renderShader.setUniform("u_resolution", sf::Vector2f(m_drawTexture.getSize()));
m_renderShader.setUniform("u_pos", info.pos);
m_renderShader.setUniform("u_dir", info.dir);
}
void createTextureArray(GLuint t_tex, const std::vector<sf::Image> &t_textures)
{
assert(!t_textures.empty());
auto size_x = std::max_element(t_textures.cbegin(), t_textures.cend(),
[](const sf::Image& a, const sf::Image& b)
{
return a.getSize().x < b.getSize().x;
})->getSize().x;
auto size_y = std::max_element(t_textures.cbegin(), t_textures.cend(),
[](const sf::Image& a, const sf::Image& b)
{
return a.getSize().y < b.getSize().y;
})->getSize().y;
glCheck(glActiveTexture(GL_TEXTURE0 + 0));
glCheck(glBindTexture(GL_TEXTURE_2D_ARRAY, t_tex));
glCheck(glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, size_x, size_y, t_textures.size()));
for (size_t i { 0 }; i < t_textures.size(); ++i)
{
glCheck(glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, t_textures[i].getSize().x, t_textures[i].getSize().y,
1, GL_RGBA, GL_UNSIGNED_BYTE, t_textures[i].getPixelsPtr()));
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glCheck(glTexParameterf(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_LINEAR));
glCheck(glTexParameterf(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_LINEAR));
glCheck(glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE));
glCheck(glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE));
glCheck(glBindTexture(GL_TEXTURE_2D_ARRAY, 0));
}
Le shader de test :
#version 330
uniform vec2 u_resolution;
uniform vec2 u_pos = vec2(7.5, 7.5);
uniform vec2 u_dir = vec2(0, 1);
uniform sampler2DArray u_textures;
void main()
{
gl_FragColor = texture(u_textures, vec3(gl_FragCoord.xy / u_resolution.xy, 1));
}
Du noir à chaque fois (et j'ai testé aussi la taille de la texture, 1x1 et 0 couches)
Le github du projet au besoin :
https://github.com/Stellaris-code/Rayfun