shader - 我想像在 Photoshop 中一样创建内部阴影着色器

标签 shader shadow

我想重新创建名为“内阴影”的 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;
}

最佳答案

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

Jump Flooding

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

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

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

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

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

Inner shadow

        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;                          
        }

关于shader - 我想像在 Photoshop 中一样创建内部阴影着色器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55347665/

相关文章:

c++ - OpenGL 和 GLFW - 我需要着色器来绘制点吗?

java - 法线发生了变化,但光照仍然很奇怪?

unity3d - 'Master' : implicit truncation of vector type 中的着色器警告

c++ - OpenGL:关于使用多个纹理或纹理单元的一些说明

c++ - 未声明的标识符 'gl_Position'

css - 如何在元素的一侧添加框阴影?

ios - 为什么阴影反射(reflect)在 subview 上

css - CSS Blur 出现奇怪的阴影效果

ios - UITableViewCell Layer Shadow Overlap Cell 上面