【问题标题】:Drawing a perfect horizontal line at a specific position with a fragment shader使用片段着色器在特定位置绘制完美水平线
【发布时间】:2019-09-05 00:13:26
【问题描述】:

是否可以在垂直轴上的任何选定位置绘制一条具有单个像素高度的完美水平线,并将片段着色器应用于屏幕对齐的四边形?

我找到了许多具有平滑步骤或更复杂功能的解决方案,但我正在寻找一种优雅而快速的方法。

我提出的一个解决方案是使用指数函数并使其更陡峭,但它有许多我不想要的缺点(由于指数函数,这条线实际上不是一个像素高度,而且很难得到一个正确的),这是GLSL代码:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;

    // a centered horizontal line
    float v = pow(uv.y - 0.5, 2.);

    // make it steeper
    v *= 100000.;

    // make it white on a black background
    v = clamp(1. - v, 0., 1.);

    fragColor = vec4(v);
}

这是执行此操作的 shadertoy 代码:https://www.shadertoy.com/view/Ms2cWh

我想要什么:

  • 以像素为单位或标准化绘制到特定 Y 位置的完美水平线
  • 其强度限制在 [0, 1] 范围内,无需钳位
  • 一种快速的方法

【问题讨论】:

    标签: opengl-es glsl webgl shader


    【解决方案1】:

    如果你只是想:

    在任何选定的位置绘制一个像素高度的完美水平线 将片段着色器应用于垂直轴上的位置 屏幕对齐四边形

    ,那么也许:

    void mainImage( out vec4 fragColor, in vec2 fragCoord )
    {
        int iPosition = 250; // the y coord in pixels
        int iThickness = 10; // the thickness in pixels
    
        vec2 uv = fragCoord.xy / iResolution.xy;
    
        float v = float( iPosition ) / iResolution.y;
        float vHalfHeight = ( float( iThickness ) / ( iResolution.y ) ) / 2.;
    
        if ( uv.y > v - vHalfHeight && uv.y < v + vHalfHeight )
            fragColor = vec4(1.,1.,1.,1.); // or whatever color
    }
    

    【讨论】:

    • 谢谢你,这个解决方案除了性能之外是完美的,我知道这个解决方案,但分支有点不行,我想有一种方法可以通过删除条件来优化它。
    • 所以,我不知道step 函数的计算成本,但我通过v = step(uv.y, v + vHalfHeight) - step(uv.y, v - vHalfHeight); 删除了分支
    • 干得好!你知道任何用于测量着色器执行时间的简单工具吗?可能可以在高分辨率时钟滴答之间循环数千次! :)
    • 不,但我也很想知道它是如何实现的 :)
    • iq 和 abje on ShaderToy 发布了一个非常优雅的解决方案(带有分支)fragColor = vec4(fragCoord.y+0.5 == iPosition) 我想知道这是不是最快的?
    【解决方案2】:

    Here 是一个没有分支的简洁解决方案。我不知道它是否真的比使用分支更快。

    void mainImage( out vec4 fragColor, in vec2 fragCoord )
    {
        vec2 uv = fragCoord.xy / iResolution.xy;
    
        float py = iMouse.y/iResolution.y;
    
        float hh = 1./iResolution.y;
    
        // can also be replace with step(0., hh-abs(uv.y-py))
        float v = sign(hh-abs(uv.y-py));
    
        fragColor = vec4(v);
    }
    

    【讨论】:

    • ShaderToy 上的 Zabidon 用v = step(abs(fragCoord.y - py), 1.); 发布了一个更好的解决方案,感谢他!
    【解决方案3】:

    我知道这个问题在我之前得到了正确的回答,但是如果有人正在寻找一种以像素完美的方式渲染纹理线条的方法,我写了一个 article 并附有一些示例。

    一般来说,它是关于像素完美的 UI,但将它用于线条只是钳制/重复纹理采样的问题。我也在使用 Unity,但没有理由该方法是它独有的。

    【讨论】:

      猜你喜欢
      • 2019-10-23
      • 2018-07-15
      • 2012-10-30
      • 2018-12-25
      • 2022-06-14
      • 2019-11-27
      • 1970-01-01
      • 1970-01-01
      • 2017-05-16
      相关资源
      最近更新 更多