C++ 灯光着色器在调整窗口大小时移动

C++ 灯光着色器在调整窗口大小时移动,c++,glsl,sfml,C++,Glsl,Sfml,我一直在做一个小的灯光着色器。 它工作得很完美,我的意思是,光线会像预期的那样消失,它是一个围绕着我的角色的圆圈,随着它移动。 只有当调整大小的事件不存在时,它才可能是完美的 当SFML调整窗口大小时,它会以一种奇怪的方式放大所有内容。它放大了所有内容,但却放大了着色器。 我试图调整我的窗口大小(我喜欢调整像素图游戏的大小,我觉得它最漂亮。所以我不想阻止调整大小事件) 这是我的着色器: uniform vec3 light; void main(void) { float di

我一直在做一个小的灯光着色器。 它工作得很完美,我的意思是,光线会像预期的那样消失,它是一个围绕着我的角色的圆圈,随着它移动。 只有当调整大小的事件不存在时,它才可能是完美的

当SFML调整窗口大小时,它会以一种奇怪的方式放大所有内容。它放大了所有内容,但却放大了着色器。 我试图调整我的窗口大小(我喜欢调整像素图游戏的大小,我觉得它最漂亮。所以我不想阻止调整大小事件)

这是我的着色器:

    uniform vec3 light;

void main(void) {
    float distance = sqrt(pow(gl_FragCoord.x - light.x, 2) + pow(gl_FragCoord.y - light.y, 2));
    float alpha = 1.;

    if (distance <= light.z) {
        alpha = (1.0 / light.z) * distance;
    }
    gl_FragColor = vec4(0., 0., 0., alpha);

}
您正在显示的代码片段实际上只更新着色器坐标(从快速浏览中,它看起来很好)。这个bug最有可能发生在你实际绘制东西的地方


我会使用完全不同的方法,因为一旦渲染多个对象、其他光源等,着色器方法可能会变得相当乏味

因此,我建议您将灯光贴图渲染到渲染纹理(本质上类似于“黑色=无灯光,颜色=该颜色的灯光”)

我没有试图用文本解释所有内容,而是编写了一个快速注释的示例程序,该程序将在屏幕上绘制一个窗口,并在背景图像上移动一些光源(我使用了SFML着色器示例附带的一个):

除了在启动路径中有一个名为“background.jpg”的文件外,没有其他要求

请随意复制此代码或将其用于灵感。请记住,这不是优化的,实际上只是一个快速编辑,以显示总体思路

#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>

const float PI = 3.1415f;

struct Light
{
    sf::Vector2f position;
    sf::Color color;
    float radius;
};

int main()
{
    // Let's setup a window
    sf::RenderWindow window(sf::VideoMode(640, 480), "SFML Lights");
    window.setVerticalSyncEnabled(false);
    window.setFramerateLimit(60);

    // Create something simple to draw
    sf::Texture texture;
    texture.loadFromFile("background.jpg");
    sf::Sprite background(texture);

    // Setup everything for the lightmap
    sf::RenderTexture lightmapTex;
    // We're using a 512x512 render texture for max. compatibility
    // On modern hardware it could match the window resolution of course
    lightmapTex.create(512, 512);
    sf::Sprite lightmap(lightmapTex.getTexture());
    // Scale the sprite to fill the window
    lightmap.setScale(640 / 512.f, 480 / 512.f);
    // Set the lightmap's view to the same as the window
    lightmapTex.setView(window.getDefaultView());

    // Drawable helper to draw lights
    // We'll just have to adjust the first vertex's color to tint it
    sf::VertexArray light(sf::PrimitiveType::TriangleFan);
    light.append({sf::Vector2f(0, 0), sf::Color::White});
    // This is inaccurate, but for demo purposes…
    // This could be more elaborate to allow better graduation etc.
    for (float i = 0; i  <= 2 * PI; i += PI * .125f)
        light.append({sf::Vector2f(std::sin(i), std::cos(i)), sf::Color::Transparent});

    // Setup some lights
    std::vector<Light> lights;
    lights.push_back({sf::Vector2f(50.f, 50.f), sf::Color::White, 100.f });
    lights.push_back({sf::Vector2f(350.f, 150.f), sf::Color::Red, 150.f });
    lights.push_back({sf::Vector2f(150.f, 250.f), sf::Color::Yellow, 200.f });
    lights.push_back({sf::Vector2f(250.f, 450.f), sf::Color::Cyan, 100.f });

    // RenderStates helper to transform and draw lights
    sf::RenderStates rs(sf::BlendAdd);

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            switch (event.type) {
                case sf::Event::Closed:
                    window.close();
                    break;
            }
        }

        bool flip = false; // simple toggle to animate differently

        // Draw the light map
        lightmapTex.clear(sf::Color::Black);
        for(Light &l : lights)
        {
            // Apply all light attributes and render it

            // Reset the transformation
            rs.transform = sf::Transform::Identity;

            // Move the light
            rs.transform.translate(l.position);

            // And scale it (this could be animated to create flicker)
            rs.transform.scale(l.radius, l.radius);

            // Adjust the light color (first vertex)
            light[0].color = l.color;

            // Draw the light
            lightmapTex.draw(light, rs);

            // To make things a bit more interesting
            // We're moving the lights
            l.position.x += flip ? 2 : -2;
            flip = !flip;
            if (l.position.x > 640)
                l.position.x -= 640;
            else if (l.position.x < 0)
                l.position.x += 640;
        }
        lightmapTex.display();

        window.clear(sf::Color::White);
        // Draw the background / game
        window.draw(background);
        // Draw the lightmap
        window.draw(lightmap, sf::BlendMultiply);
        window.display();
    }
}
#包括
#包括
#包括
常数浮点PI=3.1415f;
结构光
{
sf::矢量2f位置;
颜色;
浮动半径;
};
int main()
{
//让我们设置一个窗口
sf::RenderWindow窗口(sf::VideoMode(640480),“SFML灯光”);
window.setVerticalSyncEnabled(false);
设置帧率限制(60);
//创造一些简单的画
sf::纹理;
loadFromFile(“background.jpg”);
雪碧背景(纹理);
//为光照贴图设置所有内容
sf::RenderTexture lightmapTex;
//我们使用512x512渲染纹理以实现最大兼容性
//在现代硬件上,它当然可以匹配窗口分辨率
创建(512512);
sf::Sprite lightmap(lightmapTex.getTexture());
//缩放精灵以填充窗口
光照贴图设置比例(640/512.f,480/512.f);
//将光照贴图的视图设置为与窗口相同
lightmapTex.setView(window.getDefaultView());
//绘制灯光的可绘制辅助对象
//我们只需调整第一个顶点的颜色即可对其着色
sf::VertexArray灯光(sf::PrimitiveType::TriangleFan);
append({sf::Vector2f(0,0),sf::Color::White});
//这是不准确的,但出于演示目的…
//这可以更详细,以便更好地毕业等。

对于(float i=0;我发现您的解释很难理解。但是,很明显,它不能很好地缩放,因为您使用的是窗口坐标(gl_FragCoord)代替标准化设备坐标或其他不依赖于窗口分辨率的坐标。您可以从顶点着色器获取NDC,或将gl_FragCoord除以窗口分辨率(从统一变量获取)你不明白哪一部分?我可以试着澄清一下^^嗯,我不使用顶点着色器,我只使用frag着色器(我对glsl非常陌生,抱歉:c)我不清楚你想做什么,这是像素艺术吗?你能提供一张图片吗?你想如何准确地处理不同的窗口分辨率?1024x1024窗口应该看起来像512x512窗口?或者它应该是它的1/4部分?你应该给我们更多的代码(例如,你在C++中绘制的地方)。这听起来有点像你如何绘制东西或窗口视图的设置有问题。@dv1729我编辑了这篇文章以使其更清晰。马里奥,我的代码只是在屏幕上绘制精灵,没有什么特别之处,唯一的问题是我不处理大小调整事件,所以SFML单独完成任务,但不告诉用户着色器窗口已调整大小。哇,我还没有准备好xD看起来很酷,我要试试这个,谢谢!@FeelZoR如果我不清楚,你可以绘制任何形状的灯光,所以绘制聚光灯或任何其他非圆形光源非常简单。
#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>

const float PI = 3.1415f;

struct Light
{
    sf::Vector2f position;
    sf::Color color;
    float radius;
};

int main()
{
    // Let's setup a window
    sf::RenderWindow window(sf::VideoMode(640, 480), "SFML Lights");
    window.setVerticalSyncEnabled(false);
    window.setFramerateLimit(60);

    // Create something simple to draw
    sf::Texture texture;
    texture.loadFromFile("background.jpg");
    sf::Sprite background(texture);

    // Setup everything for the lightmap
    sf::RenderTexture lightmapTex;
    // We're using a 512x512 render texture for max. compatibility
    // On modern hardware it could match the window resolution of course
    lightmapTex.create(512, 512);
    sf::Sprite lightmap(lightmapTex.getTexture());
    // Scale the sprite to fill the window
    lightmap.setScale(640 / 512.f, 480 / 512.f);
    // Set the lightmap's view to the same as the window
    lightmapTex.setView(window.getDefaultView());

    // Drawable helper to draw lights
    // We'll just have to adjust the first vertex's color to tint it
    sf::VertexArray light(sf::PrimitiveType::TriangleFan);
    light.append({sf::Vector2f(0, 0), sf::Color::White});
    // This is inaccurate, but for demo purposes…
    // This could be more elaborate to allow better graduation etc.
    for (float i = 0; i  <= 2 * PI; i += PI * .125f)
        light.append({sf::Vector2f(std::sin(i), std::cos(i)), sf::Color::Transparent});

    // Setup some lights
    std::vector<Light> lights;
    lights.push_back({sf::Vector2f(50.f, 50.f), sf::Color::White, 100.f });
    lights.push_back({sf::Vector2f(350.f, 150.f), sf::Color::Red, 150.f });
    lights.push_back({sf::Vector2f(150.f, 250.f), sf::Color::Yellow, 200.f });
    lights.push_back({sf::Vector2f(250.f, 450.f), sf::Color::Cyan, 100.f });

    // RenderStates helper to transform and draw lights
    sf::RenderStates rs(sf::BlendAdd);

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            switch (event.type) {
                case sf::Event::Closed:
                    window.close();
                    break;
            }
        }

        bool flip = false; // simple toggle to animate differently

        // Draw the light map
        lightmapTex.clear(sf::Color::Black);
        for(Light &l : lights)
        {
            // Apply all light attributes and render it

            // Reset the transformation
            rs.transform = sf::Transform::Identity;

            // Move the light
            rs.transform.translate(l.position);

            // And scale it (this could be animated to create flicker)
            rs.transform.scale(l.radius, l.radius);

            // Adjust the light color (first vertex)
            light[0].color = l.color;

            // Draw the light
            lightmapTex.draw(light, rs);

            // To make things a bit more interesting
            // We're moving the lights
            l.position.x += flip ? 2 : -2;
            flip = !flip;
            if (l.position.x > 640)
                l.position.x -= 640;
            else if (l.position.x < 0)
                l.position.x += 640;
        }
        lightmapTex.display();

        window.clear(sf::Color::White);
        // Draw the background / game
        window.draw(background);
        // Draw the lightmap
        window.draw(lightmap, sf::BlendMultiply);
        window.display();
    }
}