【问题标题】:Is Photoshop "Motion Blur" possible with GLSL?使用 GLSL 可以实现 Photoshop“运动模糊”吗?
【发布时间】:2017-10-15 10:02:16
【问题描述】:

我正在使用 制作带有精灵的 2D 游戏并尝试获得这种效果:

我在示例中使用了 Photoshop 的“运动模糊”。可以看到,效果是有方向性的。

我的游戏使用纸娃娃精灵,因此将其作为后期效果会更容易,而不是模糊每个精灵上的每个设备组合。

是否可以使用着色器获得这种效果?一个例子将不胜感激。

【问题讨论】:

  • 对不起,如果我的问题不清楚:我不希望将传统的运动模糊添加到 MOVING 精灵。我想将此效果应用于静止精灵。这就是为什么我指定我想应用方向模糊,它在 Photoshop 中恰好被命名为“运动模糊”。这只是它的名字。 @LJᛃ
  • 这就是为什么标题是“”是 PHOTOSHOP “MOTION BLUR”可能使用 glsl 吗?”而不是“是否可以使用 glsl 进行动态模糊?”。@LJᛃ
  • "photoshop 运动模糊" is 运动模糊仅使用用户定义的方向/运动矢量,但如果在 GLSL 中可能,请回答您的问题:是的。
  • 任何不依赖于对象移动的实现示例都将受到高度赞赏。

标签: sfml glsl shader sfml blur


【解决方案1】:

在这里,我发布了我可以在一晚内完成的最佳结果。我按照你的要求用着色器做到了。我没有实现这些角度,但这并不太难。

这是cpp文件的一部分:

...
if (!shader.loadFromFile("dMotionBlur_v05.frag", sf::Shader::Fragment)){
...

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

// Passing parameters to shader.
shader.setUniform("dir", dir); //direction of blur
shader.setUniform("nSamplesF", (float)std::atoi(argv[3])); // number of samples
shader.setUniform("radius", (float)std::atof(argv[4]) ); //radius of blur

window.draw(sprite, &shader);
window.display();
...

这是片段着色器:

uniform sampler2D u_texture;
uniform float nSamplesF;
uniform float radius;
uniform vec2 dir;

void main(){
    vec2 tc = gl_TexCoord[0].xy;
    float blur = radius;
    float hstep = dir.x;
    float vstep = dir.y;
    float total = 0.0;
    int nSamplesI = int(nSamplesF);

    vec4 sum = vec4(0.0);

    for (int i=1; i<=nSamplesI; i++){
        float floatI = float(i);
        float counter = nSamplesF-floatI+1.0;

        float p = floatI/nSamplesF;
        float tO = (p * 0.1783783784) + 0.0162162162;
        total += tO;

        sum += texture2D(u_texture, vec2(tc.x - counter*blur*hstep, tc.y - counter*blur*vstep)) * tO;
    }

    sum += texture2D(u_texture, vec2(tc.x, tc.y)) * 0.2270270270;

    for (int i=nSamplesI; i>=1; i--){
        float floatI = float(i);
        float counter = nSamplesF-floatI+1.0;

        float p = floatI/nSamplesF;
        float tO = (p * 0.1783783784) + 0.0162162162;
        total += tO;

        sum += texture2D(u_texture, vec2(tc.x + counter*blur*hstep, tc.y + counter*blur*vstep)) * tO;
    }

    gl_FragColor =  gl_Color * (sum/total);
}

我将entire code 上传到我的存储库,以便您下载并试用。 您可以设置 x/Y 方向、采样和模糊半径。 X/Y 方向为 0-1。 您可以使用样本数量。 模糊半径非常敏感,可以从 0.01 开始尝试

我的例子是:

$ ./sfml-app [x(0-1)] [Y(0-1] [number of sample] [ radius blur]

一些图片:

【讨论】:

    【解决方案2】:

    在线生成点

    在手动方面有点,但我可以建议一种方法。
    让我们想象一个,与确定的角度上的线相交。在那条线上,我们随机放置一些

    类似这样的:


    半径 100角度 45º(PI / 4 弧度)和 100 个随机点的圆

    然后,无论每个点在哪里,我们都将绘制我们的纹理精灵,并带有一些 alpha(透明度)。结果将如下所示:

    改变圆的半径,点数,结果可能会有所不同


    进一步说明

    在我的示例中,我使用了一个类,它代表BlurredSprite。它将保存这些点,以及要绘制的sf::Texture

    class BlurredSprite : public sf::Drawable, sf::Transformable {
        public:
            BlurredSprite(const sf::Texture &t, float radius, float angle, unsigned int points = 30) :
                m_texture(t)
            {
                auto getPointOverLine = [=]{
                    auto angleOverX = angle - std::_Pi*0.5;  // Angle 0 is a vertical line, so I rotate it 45 degrees clockwise (substract)
                    if (rand() % 2){
                        angleOverX += std::_Pi;   // Half of the points will be on the "first quadrant", the other half over the "third", if you consider (0,0) the center of the circle
                    }
                    auto l = radius * ((rand() * 1.f) / RAND_MAX);
                    auto x = cos(angleOverX) * (l);
                    auto y = sin(angleOverX) * (l);
    
                    return sf::Vector2f(x, y);
                };
    
                while (m_points.size() < points){
                    m_points.push_back(getPointOverLine());
                }
    
            }
        private:
            std::vector<sf::Vector2f> m_points;
            sf::Texture m_texture;
    };
    

    使用getPointOverLine lambda,我在线上创建了一个随机点,但可以使用其他选项来执行此操作。事实上,这些点的分布方式会影响最终结果

    我需要重写draw 方法,以使这个类在窗口上可绘制。我还覆盖了setPosition 方法(来自sf::Transformable),因为如果你移动它,你应该移动它的所有点。

    public:
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const{
            auto it = m_points.begin();
            while (it != m_points.end()){    
                sf::Sprite sp(m_texture);
                auto col = sp.getColor();
                auto rect = sp.getTextureRect();
                auto orig = sp.getOrigin() + sf::Vector2f(rect.width, rect.height)*0.5f;
                col.a = 25;
    
                sp.setColor(col);
                sp.setOrigin(orig);
                sp.setPosition(*it);
                target.draw(sp);
    
                it++;
            }
        }
    
        virtual void setPosition(sf::Vector2f pos){
            sf::Transformable::setPosition(pos);
            for (int i = 0; i < m_points.size(); ++i){
                m_points[i] = pos + m_points[i];
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多