SFML community forums

Help => Graphics => Topic started by: XCemaXX on March 30, 2019, 07:05:19 am

Title: How to use sf::Shader with multiple textures as a raw shader for OpenGL?
Post by: XCemaXX on March 30, 2019, 07:05:19 am
My shader requires diffuse and normal map textures. How to implement it? I didn't find answer in previous topic (https://en.sfml-dev.org/forums/index.php?topic=24078.0).
Is it possible to use sf::Shader with multiple textures as a raw shader for custom OpenGL geometry?

Now I can only load 1 texture, and if I comment sf::Texture::bind(), I will recive black model.
//staff with vertices
std::vector<GLfloat> vertices(3 * 3 * model->nfaces(), 0);
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
GLuint vertexbuffer = 0;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*vertices.size(), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

//textures
sf::Texture texdif= model->diffusemapT;
sf::Texture::bind(&texdif);
sf::Texture texnormal = model->normalmapT;
glEnable(GL_TEXTURE_2D);
sf::Texture::bind(&texnormal);

//shader
sf::Shader shader;
if (!shader.loadFromFile("Vertex_shader.glsl", "Fragment_shader.glsl")) return 0;
sf::Shader::bind(&shader);

//drawning
shader.setUniform("diffuse", texdif);
shader.setUniform("tangentnm", texnormal);
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
window.display();

Now I use shader only with 1 texture. For code above I get normal map on my model, because it was loaded later. But I want to use this shader:
#version 330 core

out vec3 color;
// Interpolated values from the vertex shaders
in vec3 Normal_cameraspace;
in vec3 LightDirection_cameraspace;
in vec3 tangent_cameraspace;
in vec3 bitangent_cameraspace;
in vec2 UV;

// Textures
uniform sampler2D tangentnm;
uniform sampler2D diffuse;

void main() {
    vec3 n = normalize(Normal_cameraspace);  
    mat3 D = mat3(normalize(tangent_cameraspace), normalize(bitangent_cameraspace), n);
    n = normalize((D*normalize(texture(tangentnm, UV).rgb * 2 - 1)));
    vec3 l = normalize(LightDirection_cameraspace);
    float cosTheta = clamp(dot(n,l), 0, 1);

    color = texture(diffuse, UV).xyz*(0.1 + 1.3*cosTheta);
}

SFML 2.5.1, OpenGL 4.6
Title: Re: How to use sf::Shader with multiple textures as a raw shader for OpenGL?
Post by: Laurent on March 30, 2019, 06:45:49 pm
Do you ever call sf::Shader::bind(&shader)? That's where textures are bound and mapped to sampler2D variables.
Title: Re: How to use sf::Shader with multiple textures as a raw shader for OpenGL?
Post by: XCemaXX on March 31, 2019, 03:59:02 am
Yes, I call.
sf::Shader shader;
if (!shader.loadFromFile("Vertex_shader.glsl", "Fragment_shader.glsl")) return 0;
sf::Shader::bind(&shader);
p.s. I have add it to the first post.
Title: Re: How to use sf::Shader with multiple textures as a raw shader for OpenGL?
Post by: Laurent on March 31, 2019, 03:20:35 pm
You should definitely provide a complete and minimal example that reproduces the problem, so that we don't have to guess ;)
Title: Re: How to use sf::Shader with multiple textures as a raw shader for OpenGL?
Post by: XCemaXX on April 03, 2019, 05:28:17 pm
Thank you for your advice. I found my mistake.
I called sf::Shader::bind(&shader) before shader.setUniform("diffuse", texdif).
I changed code to:
sf::Texture texdif= model->diffusemapT;
sf::Texture texnormal = model->normalmapT;
glEnable(GL_TEXTURE_2D);
sf::Shader shader;
if (!shader.loadFromFile("Vertex_shader.glsl", "Fragment_shader.glsl")) return 0;
shader.setUniform("diffuse", texdif);
shader.setUniform("tangentnm", texnormal);
sf::Shader::bind(&shader);
But it is strange that I can call other "setUniform" rows after sf::Shader::bind, and it works. For example:
sf::Glsl::Mat4 M1(tmp);
shader.setUniform("M", M1);
And vertex shader uses:
uniform mat4 M;
Title: Re: How to use sf::Shader with multiple textures as a raw shader for OpenGL?
Post by: Laurent on April 04, 2019, 06:37:33 am
Uniforms are sent to the shader directly, but textures also need to be bound when the shader runs, which is done in sf::Shader::bind.