使着色器将vertexArray作为画布而不是窗口

时间:2017-12-07 19:47:50

标签: c++ opengl glsl shader sfml

目前正在开发一个基于开源GUI的SFML库,但与着色器有点挣扎。到目前为止,我设法渲染着色器没有问题,但是它不是在当前对象上应用着色器,而是将其应用于整个窗口,但仅在对象范围内可见。

这是我的简单代码:

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>

#include <iostream>

const char *glsl = R"(
    #version 330 core
    uniform vec2 u_resolution;

    void main() {
        vec2 pos = gl_FragCoord.xy / u_resolution;
        float radius = 0.4;
        float d = distance(pos, vec2(0.5));

        gl_FragColor = d <= radius ? vec4(pos.y,pos.y/2.,pos.y, 1.0) : vec4(d*0.8, d*0.8, d*0.8, 1.0);


        //gl_FragColor = vec4(0.0, 0.5, 1.0, 1.0);
    }
)";

const char *pos = R"(
    // some default shader I've found
    // adding #version 330 core will complain for outdated gl_Position variable..

    void main() {
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

        gl_FrontColor = gl_Color;
    }
)";

int main() {
    sf::RenderWindow window(sf::VideoMode(800, 600), "GLSL", sf::Style::Default);

    // create a quad
    sf::VertexArray quad(sf::Quads, 4);
    // define it as a rectangle, located at (10, 10) and with size 100x100
    quad[0].position = sf::Vector2f(100, 100);
    quad[1].position = sf::Vector2f(410, 100);
    quad[2].position = sf::Vector2f(410, 410);
    quad[3].position = sf::Vector2f(100, 410);


    sf::Shader shader;
    // the following line is the same as shader.loadFromMemory(pos, glsl);
    shader.loadFromMemory(glsl, sf::Shader::Fragment);
    shader.setUniform("u_resolution", sf::Vector2f(800, 600));

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear(sf::Color(244,244,244));

        window.draw(quad, &shader);

        window.display();
    }

    return 0;
}

不确定现在要做什么,但我想pos着色器会影响渲染的完成方式。谢谢!

1 个答案:

答案 0 :(得分:3)

只需要进行一些小的改动。我不确定在任何更现代的着色器版本中完成它的最佳方法是什么,但如果省略任何版本标记(即使用遗留代码),则可以快速更改:

首先,您的各个顶点(或更具体的渲染片段)不知道它们相对于正在绘制的四边形的位置。幸运的是,您可以滥用纹理坐标。例如,将左上角定义为(0, 0),将右下角定义为(1, 1)。这样,它们的值将根据片段的位置从0到1。这基本上是您现有的着色器代码计算为pos

让我们首先添加纹理坐标:

quad[0].position = sf::Vector2f(100, 100);
quad[0].texCoords = sf::Vector2f(0, 0);
quad[1].position = sf::Vector2f(410, 100);
quad[1].texCoords = sf::Vector2f(1, 0);
quad[2].position = sf::Vector2f(410, 410);
quad[2].texCoords = sf::Vector2f(1, 1);
quad[3].position = sf::Vector2f(100, 410);
quad[3].texCoords = sf::Vector2f(0, 1);

现在我们要做的就是将纹理坐标指定给pos(或者更好地删除pos completely)。为简化起见,我将完成任务:

vec2 pos = gl_TexCoord[0].xy;

但是,这会导致着色器编译器抱怨,因为gl_TexCoord已被删除。所以对于测试我刚刚删除了预编译器行,结果看起来就像你想到的那样:

Screenshot