【问题标题】:I want to create inner shadow shader like in photoshop我想像在 Photoshop 中一样创建内部阴影着色器
【发布时间】:2019-08-16 06:38:19
【问题描述】:

我想重新创建名为“内阴影”的 Photoshop 效果作为纹理着色器。作为起点,我以“大纲”为例,但我不知道下一步该做什么,或者如何创建它。请问有人可以分享一些代码示例或者可以帮助修改这个着色器以获得内部阴影效果吗?

varying vec2 v_texCoord;
varying vec4 v_fragmentColor;
uniform vec3 u_outlineColor;
uniform float u_threshold;
uniform float u_radius;

void main()
{
    float radius = u_radius;
    vec4 accum = vec4(0.0);
    vec4 normal = vec4(0.0);

    normal = texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y));

    accum += texture2D(CC_Texture0, vec2(v_texCoord.x - radius, v_texCoord.y - radius));
    accum += texture2D(CC_Texture0, vec2(v_texCoord.x + radius, v_texCoord.y - radius));
    accum += texture2D(CC_Texture0, vec2(v_texCoord.x + radius, v_texCoord.y + radius));
    accum += texture2D(CC_Texture0, vec2(v_texCoord.x - radius, v_texCoord.y + radius));

    accum *= u_threshold;
    accum.rgb =  u_outlineColor * accum.a;
    accum.a = 0.0;

    normal = ( accum * (1.0 - normal.a)) + (normal * normal.a);

    gl_FragColor = v_fragmentColor * normal;
}

【问题讨论】:

  • 欢迎来到 Stackoverflow.com!请收看the tour 看看如何ask a good question 来更好地了解这里的主题。到目前为止,您的帖子中根本没有任何问题,因此无法回答。
  • 对不起,你能帮我提供一些代码示例来创建内部阴影着色器吗?

标签: shader shadow


【解决方案1】:

首先,您需要计算图像的distance transform。最好的方法是使用jump flooding算法。

1) 指定重要像素,例如使用阶跃函数。

        fixed4 frag (v2f i) : SV_Target
        {
            return step( _Threshold, tex2D( _MainTex, i.uv ).a );
        }

2) 渲染跳跃泛洪算法的种子图像。在种子图像中,有效像素编码 (0,0) 和不重要像素的实际 UV 位置(在上图中,RG 编码 U,BA 编码 V,精度为 16 位)。

        fixed4 frag (v2f i) : SV_Target
        {
            return lerp(
                fixed4( 0.0, 0.0, 0.0, 0.0 ),
                fixed4( EncodeFloatRG( i.uv.x ), EncodeFloatRG( i.uv.y ) ),                 
                1.0 - step( 0.01, tex2D( _MainTex, i.uv ).r )
            );        
        }

3-10) 跳跃泛滥步骤。在每一步中,您必须遍历“相邻”像素并找到哪个包含编码的 UV 位置,最接近当前像素的 UV 位置。跳洪必须从最远的“邻居”开始,然后逐渐缩小搜索距离。

        void JumpFlooding(half2 uv, half2 duv, inout half2 nearestPos, inout half nearestDist)
        {
            fixed4 seed = tex2D( _MainTex, uv + duv * _MainTex_TexelSize.xy );
            half2 pos = half2( DecodeFloatRG( seed.xy ), DecodeFloatRG( seed.zw ) );
            if( length(pos) > 0.0 )
            {
                half dist = distance( uv, pos );
                if( dist < nearestDist )
                {
                    nearestDist = dist;
                    nearestPos = pos;
                }
            }
        }

        fixed4 frag (v2f i) : SV_Target
        {
            half2 nearestPos = half2( 0, 0 );
            half nearestDist = 2.0;

            JumpFlooding( i.uv, half2( -_Offset, -_Offset ), nearestPos, nearestDist );
            JumpFlooding( i.uv, half2( -_Offset, 0 ), nearestPos, nearestDist );
            JumpFlooding( i.uv, half2( -_Offset, _Offset ), nearestPos, nearestDist );
            JumpFlooding( i.uv, half2( 0, _Offset ), nearestPos, nearestDist );
            JumpFlooding( i.uv, half2( _Offset, _Offset ), nearestPos, nearestDist );
            JumpFlooding( i.uv, half2( _Offset, 0 ), nearestPos, nearestDist );
            JumpFlooding( i.uv, half2( _Offset, -_Offset ), nearestPos, nearestDist );
            JumpFlooding( i.uv, half2( 0, -_Offset ), nearestPos, nearestDist );
            JumpFlooding( i.uv, half2( 0, 0 ), nearestPos, nearestDist );

            return fixed4( EncodeFloatRG( nearestPos.x ), EncodeFloatRG( nearestPos.y ) );
        }

11) 最后是跳洪算法编码到距离场的最后结果。

        fixed4 frag (v2f i) : SV_Target
        {
            fixed4 seed = tex2D( _MainTex, i.uv );
            half2 pos = half2( DecodeFloatRG( seed.xy ), DecodeFloatRG( seed.zw ) );
            float dist = distance( i.uv, pos );                 
            return EncodeFloatRGBA( dist );
        }

现在你可以使用距离场来绘制内阴影了。

        fixed4 frag (v2f i) : SV_Target
        {
            half4 color = _ShadowColor;

            half dist = DecodeFloatRGBA( tex2D(_DistTex, i.uv) );

            color.a *= ( 1.0 - smoothstep( _ShadowMinRange, _ShadowMaxRange, dist ) );

            return color;                          
        }

【讨论】:

  • 我不确定我是否理解这个例子。这是统一着色器吗?我在这里看到 11 步,我可以将它们应用到一个着色器脚本中吗?或者我需要将它顺序存储到一些临时文件中?你有工作样本来看看它的真实性吗?
  • 是的,基本上,这是多步骤技术。但是,它的多步性是因为距离变换。不过,您可以通过其他方式执行距离变换,例如使用 Photoshop 或其他图像编辑器。
  • 我真的很抱歉,但我无法统一重现它(步骤 3-11)。你能帮我举个例子吗?
猜你喜欢
  • 2014-04-23
  • 2015-06-09
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
相关资源
最近更新 更多