【问题标题】:GLSL Shader Ported From HLSL Is Not Working从 HLSL 移植的 GLSL 着色器不工作
【发布时间】:2023-04-22 19:37:01
【问题描述】:

我有这个用于模糊的 HLSL 着色器:

   struct VS_INPUT
   {
      float4 Position  : POSITION0;
      float2 TexCoord  : TEXCOORD0;
      float4 Color     : TEXCOORD1;
   };
   struct VS_OUTPUT
   {
      float4 Position  : POSITION0;
      float4 Color     : COLOR0;
      float2 TexCoord  : TEXCOORD0;
   };

   float4x4 al_projview_matrix;

   VS_OUTPUT vs_main(VS_INPUT Input)
   {
      VS_OUTPUT Output;
      Output.Position = mul(Input.Position, al_projview_matrix);
      Output.Color = Input.Color;
      Output.TexCoord = Input.TexCoord;
      return Output;
   }

碎片

texture al_tex;
   sampler2D s = sampler_state {
      texture = <al_tex>;
   };

   int tWidth;
   int tHeight;
   float blurSize = 5.0;
   float4 ps_main(VS_OUTPUT Input) : COLOR0
   {
      float2 pxSz = float2(1.0 / tWidth,1.0 / tHeight);
      float4 outC = 0;
      float outA = 0;
      outA += Input.Color.a * tex2D(s, Input.TexCoord.xy + float2(0,-4.0 * pxSz.y * blurSize)).a * 0.05;
      outA += Input.Color.a * tex2D(s, Input.TexCoord.xy + float2(0,-3.0 * pxSz.y * blurSize)).a * 0.09;
      outA += Input.Color.a * tex2D(s, Input.TexCoord.xy + float2(0,-2.0 * pxSz.y * blurSize)).a * 0.12;
      outA += Input.Color.a * tex2D(s, Input.TexCoord.xy + float2(0,-pxSz.y * blurSize)).a * 0.15;
      outA += Input.Color.a * tex2D(s, Input.TexCoord.xy + float2(0,0)).a * 0.16;
      outA += Input.Color.a * tex2D(s, Input.TexCoord.xy + float2(0,pxSz.y * blurSize)).a * 0.15;
      outA += Input.Color.a * tex2D(s, Input.TexCoord.xy + float2(0,2.0 * pxSz.y * blurSize)).a * 0.12;
      outA += Input.Color.a * tex2D(s, Input.TexCoord.xy + float2(0,3.0 * pxSz.y * blurSize)).a * 0.09;
      outA += Input.Color.a * tex2D(s, Input.TexCoord.xy + float2(0,4.0 * pxSz.y * blurSize)).a * 0.05;

     outC.a = outA;
      return outC;
   }

水平方向也有类似的...

我的想法是,我为纹理和高度提供 tWidth、tHeight,并使用它来获取像素相对于 UV 坐标的“大小”。

然后我使用它通过对邻居进行加权平均来进行正常模糊。

我将此移植到 GLSL:

attribute vec4 al_pos;
attribute vec4 al_color;
attribute vec2 al_texcoord;
uniform mat4 al_projview_matrix;
varying vec4 varying_color;
varying vec2 varying_texcoord;
void main()
{
   varying_color = al_color;
   varying_texcoord = al_texcoord;
   gl_Position = al_projview_matrix * al_pos;
}

片段

uniform sampler2D al_tex;
varying float blurSize;
varying float tWidth;
varying float tHeight;
varying vec2 varying_texcoord;
varying vec4 varying_color;
void main()
{
    vec4 sum = vec4(0.0);
    vec2 pxSz = vec2(1.0 / tWidth,1.0 / tHeight);
    // blur in x
    // take nine samples, with the distance blurSize between them
    sum += texture2D(al_tex, varying_texcoord.xy + vec2(0,-4.0 * pxSz.y * blurSize))* 0.05;
    sum += texture2D(al_tex, varying_texcoord.xy + vec2(0,-3.0 * pxSz.y * blurSize))* 0.09;
    sum += texture2D(al_tex, varying_texcoord.xy + vec2(0,-2.0 * pxSz.y * blurSize))* 0.12;
    sum += texture2D(al_tex, varying_texcoord.xy + vec2(0,-pxSz.y * blurSize))* 0.15;
    sum += texture2D(al_tex, varying_texcoord.xy + vec2(0,0))* 0.16;
    sum += texture2D(al_tex, varying_texcoord.xy + vec2(0,pxSz.y * blurSize))* 0.15;
    sum += texture2D(al_tex, varying_texcoord.xy + vec2(0,2.0 * pxSz.y * blurSize))* 0.12;
    sum += texture2D(al_tex, varying_texcoord.xy + vec2(0,3.0 * pxSz.y * blurSize))* 0.09;
    sum += texture2D(al_tex, varying_texcoord.xy + vec2(0,4.0 * pxSz.y * blurSize))* 0.05;
    gl_FragColor = varying_color * sum;
}

这有点不同,但逻辑相同。我将像素坐标转换为 UV 坐标,并乘以模糊因子,与 hlsl 因子相同。然而, glsl 给了我一个不模糊、稍微透明的原始版本。

这是什么原因造成的?

【问题讨论】:

    标签: opengl glsl hlsl fragment-shader


    【解决方案1】:

    在您的片段着色器中,您有:

    varying vec4 varying_color;
    [...]
         gl_FragColor = varying_color;
    

    所以您所做的所有纹理获取和计算对最终着色器输出没有任何影响(并且可能会被编译器完全删除)。您可能想要输出 sum 或修改它,例如与gl_FragColor = varying_color * sum; 或任何你想达到的效果。

    另一件事:在片段着色器中,您定义了纹理大小的变化,但您不会从顶点着色器传递它们。这些应该是制服(或者,在现代 GLSL 中,还有 textureSize() GLSL 函数,它允许您直接访问这些值而无需显式传递它们)。

    【讨论】:

    • 对不起,我已经像你说的那样了,我不小心发布了一个测试用例。但是,它仍然以这种方式运行。
    • variing_color 是顶点颜色,是纯 rgba 白色。
    • @Milo:另一件事:在碎片着色器中,您定义纹理大小的变化,但您不会从顶点着色器传递它们。 THos 应该是制服(或者,在现代 GLSL 中,还有 textureSize() GLSL 函数,它允许您直接访问这些值而无需显式传递它们)
    • @Milo:你验证你的着色器实际上编译和链接没有错误吗?
    • 是的,我的意思是,它有效,只是比没有数学意义的 hlsl 版本弱得多。也许 hlsl uvs 与 glsl 不同?
    最近更新 更多