【问题标题】:Light shader moved while resizing window调整窗口大小时移动了灯光着色器
【发布时间】:2017-01-27 18:23:10
【问题描述】:

我一直在努力制作一个小灯光着色器。 它完美地工作,我的意思是,光线会按预期消失,它是围绕我的角色移动的一个圆圈。 仅当不存在该调整大小事件时,它才可能是完美的。

当 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);

}

所以,问题是,我的窗口显示为 1280 x 736(以适应 32x32 纹理),并且我有一个 1920 x 1080 显示器。当我放大窗口以适应 1920 x 1080(包括标题栏)时,整个东西都正确调整大小,一切都很好,但着色器现在是 1920x1080(减去标题栏)。所以着色器需要不同的坐标(应该在 x = 32, y = 0 中,对于着色器来说,在 x = 48 y = 0 中)。

所以我想知道,是否可以用整个窗口放大着色器?我应该使用事件或类似的东西吗?

感谢您的回答^^

编辑:这里有一些图片: 所以这是调整大小之前的光照着色器(它在所有地方都是黑暗的,但在播放器上,就像它应该的那样)。 然后我调整窗口大小,播放器不动,纹理适合整个窗口,但灯光移动了。

所以,正确地解释一下,当我调整窗口大小时,我希望一切都适合窗口,所以它充满了纹理,但是当我这样做时,给我的着色器的坐标是调整大小之前的坐标,如果我移动它就像我没有调整窗口大小一样移动,所以我的播放器再也不会有灯光了。

我不确定它是否更清楚,但我已经尽力了。

EDIT2:这是我调用着色器的代码:

void Graphics::UpdateLight() {
    short radius = 65; // 265 on the pictures

    int x = m_game->GetPlayer()->GetSprite()->getPosition().x + CASE_LEN / 2; // Setting on the middle of the player sprite (CASE_LEN is a const which contains the size of a case (here 32))
    int y = HEIGHT - (m_game->GetPlayer()->GetSprite()->getPosition().y + CASE_LEN / 2); // (the "HEIGHT -" part was set because it seems that y = 0 is on the bottom of the texture for GLSL)

    sf::Vector3f shaderLight;
    shaderLight.x = x;
    shaderLight.y = y;
    shaderLight.z = radius;

    m_lightShader.setParameter("light", shaderLight);
}

【问题讨论】:

  • 我发现您的解释难以理解。但是,很明显它不能很好地缩放,因为您使用的是窗口坐标 (gl_FragCoord) 而不是标准化的设备坐标或其他类型的不依赖于窗口分辨率的坐标。您可以从顶点着色器中获取 NDC 或将 gl_FragCoord 除以窗口分辨率(从统一变量中获取)
  • 你不明白哪一部分?我可以试着澄清一下^^'好吧,我不使用顶点着色器,我只使用片段着色器(我对 glsl 很新,对不起:c)
  • 我不太清楚你要做什么,这是像素艺术吗?你能提供一张图片吗?究竟要如何处理不同的窗口分辨率? 1024x1024 的窗口应该看起来与 512x512 的窗口完全一样吗?还是应该是它的 1/4 部分?
  • 您应该向我们展示更多代码(例如,您在 C++ 中绘制的位置)。这听起来有点像您绘制事物的方式或窗口视图的设置方式存在问题。
  • @dv1729 我编辑了帖子以使其更清晰。马里奥,我的代码只是在屏幕上绘制精灵,没有什么特别的,唯一的问题是我不处理调整大小的事件,所以 SFML 单独完成这项工作,但没有告诉着色器窗口调整大小。跨度>

标签: c++ glsl sfml


【解决方案1】:

您显示的代码 sn-p 实际上只更新了着色器坐标(并且快速浏览它看起来不错)。该错误很可能发生在您实际绘制事物的地方。


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

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

我没有试图用文字解释所有内容,而是编写了一个快速注释示例程序,它将在屏幕上绘制一个窗口并将一些光源移动到背景图像上(我使用了 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();
    }
}

【讨论】:

  • 哇,我还没准备好 xD 看起来很酷,我要试试这个,谢谢!
  • @FeelZoR 以防我不清楚,您可以绘制任何形状的灯光,因此绘制聚光灯或任何其他非圆形光​​源非常简单。
猜你喜欢
  • 2019-03-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-29
  • 1970-01-01
相关资源
最近更新 更多