• UE5实现PS图层样式投影效果


    一、图片投影

    1、创建材质函数

    MF_PS_Style_Shadow

     定义 function input。

     公开到库(可选) 

     Shadow代码:

    1. /**
    2. PS图层样式投影效果
    3. @param {UVs} texture coordinate
    4. @param {Texture} texture object
    5. @param {TextureSize} 纹理大小(x, y)
    6. @param {ShadowRGBA} 投影颜色与不透明度
    7. @param {ShadowRotate} 投影角度
    8. @param {ShadowLength} 投影距离
    9. @param {ShadowSize} 投影大小
    10. @param {BorderThreshold} 边界UVs阈值(左, 上, 右, 下)
    11. */
    12. float4 Shadow(float2 UVs, Texture2D Texture, float2 TextureSize, float4 ShadowRGBA, float ShadowRotate, half ShadowLength, half ShadowSize, float4 BorderThreshold=0.001) {
    13. const float PI = acos(-1);
    14. // 单位像素
    15. float2 TexturePixel = 1 / TextureSize;
    16. // 角度
    17. float Angle = 360 * ShadowRotate;
    18. // 弧度
    19. float Degrees = Angle / 180 * PI;
    20. // 阴影反向方位(单位向量)
    21. float2 Direction = TexturePixel * float2(cos(Degrees), sin(Degrees));
    22. class Function {
    23. Texture2D Texture;
    24. SamplerState TextureSampler;
    25. float4 ShadowRGBA;
    26. float2 Position;
    27. float BorderThresholdLeft;
    28. float BorderThresholdTop;
    29. float BorderThresholdRight;
    30. float BorderThresholdBottom;
    31. float PI;
    32. float2 TexturePixel;
    33. // 阴影颜色
    34. float3 ShadowColor(float3 Color) {
    35. // 如果需要与颜色混合,在此修改返回值,如下式 正片叠底。
    36. // return this.ShadowRGBA.rgb * Color;
    37. return this.ShadowRGBA.rgb;
    38. }
    39. // 混合
    40. float3 Blend(float3 base, float3 blend, float alpha) {
    41. // 如果使用了混合模式,把 blend 按混合公式计算一次,如下式 正片叠底。
    42. // blend = base * blend;
    43. return lerp(base, blend, alpha);
    44. }
    45. // 纹理采样
    46. float4 TextureSample(float2 UVs) {
    47. // 如果需要 alpha 通道反向,在此修改。
    48. return Texture2DSampleLevel(this.Texture, this.TextureSampler, UVs, 0).xyzw;
    49. }
    50. float4 GetShadowRGBA(float2 UVs) {
    51. // 当前像素点 RGBA
    52. float4 TextureRGBA = this.TextureSample(UVs);
    53. // 阴影反向方位 UVs
    54. float2 PositionUVs = UVs + this.Position;
    55. // 阴影反向方位 UVs 超出了 0 - 1 的范围则不计算
    56. if (PositionUVs.x < this.BorderThresholdLeft || PositionUVs.x > this.BorderThresholdRight || PositionUVs.y < this.BorderThresholdTop || PositionUVs.y > this.BorderThresholdBottom) {
    57. return TextureRGBA;
    58. }
    59. // 阴影反向方位像素点RGBA
    60. float4 PositionRGBA = this.TextureSample(PositionUVs);
    61. // 阴影透明度
    62. float ShadowOpacity = PositionRGBA.a * this.ShadowRGBA.a;
    63. if (ShadowOpacity <= 0) {
    64. return TextureRGBA;
    65. }
    66. // 当前像素点混合后的结果色
    67. // this.ShadowRGBA.rgb 为 base 固有色
    68. // TextureRGBA.rgb 为 blend 固有色
    69. // TextureRGBA.a 为 alpha
    70. float3 ShadowBlendColor = this.Blend(this.ShadowColor(PositionRGBA.rgb) * ShadowOpacity, TextureRGBA.rgb, TextureRGBA.a);
    71. // 当前像素点混合后的透明度
    72. float ShadowBlendOpacity = ShadowOpacity + TextureRGBA.a - ShadowOpacity * TextureRGBA.a;
    73. // 当前像素点混合后的RGBA
    74. return float4(ShadowBlendColor / ShadowBlendOpacity, ShadowBlendOpacity);
    75. }
    76. float Calculate1DGaussian(float x) {
    77. return exp(-0.5 * pow(this.PI * x, 2));
    78. }
    79. float4 GetShadowSizeRGBA(float2 UVs, half ShadowSize) {
    80. // 当前像素点 RGBA
    81. float4 TextureRGBA = this.TextureSample(UVs);
    82. // 投影大小范围内像素颜色累加
    83. float4 RGBASum = float4(0, 0, 0, 0);
    84. // 投影大小范围内像素的权重
    85. float WeightSum = 0;
    86. for (half x = -ShadowSize; x <= ShadowSize; x++) {
    87. for (half y = -ShadowSize; y <= ShadowSize; y++) {
    88. float Weight = this.Calculate1DGaussian(x / ShadowSize) * this.Calculate1DGaussian(y / ShadowSize);
    89. WeightSum += Weight;
    90. // 阴影偏移 UVs
    91. float2 OffsetUVs = UVs + float2(x, y) * this.TexturePixel + this.Position;
    92. if (OffsetUVs.x < this.BorderThresholdLeft || OffsetUVs.x > this.BorderThresholdRight || OffsetUVs.y < this.BorderThresholdTop || OffsetUVs.y > this.BorderThresholdBottom) {
    93. continue;
    94. }
    95. // 阴影偏移像素点 RGBA
    96. float4 OffsetRGBA = this.TextureSample(OffsetUVs);
    97. // 阴影透明度
    98. float Opacity = this.ShadowRGBA.a * OffsetRGBA.a;
    99. if (Opacity <= 0) {
    100. continue;
    101. }
    102. // 阴影结果色
    103. float4 RGBA = float4(this.ShadowColor(OffsetRGBA.rgb), Opacity);
    104. RGBASum += RGBA * Weight;
    105. }
    106. }
    107. // 模糊后的 RGBA
    108. float4 BlurRGBA = RGBASum / WeightSum;
    109. // 当前像素点混合后的结果色
    110. float3 Color = this.Blend(BlurRGBA.rgb * BlurRGBA.a, TextureRGBA.rgb, TextureRGBA.a);
    111. // 当前像素点混合后的透明度
    112. float Opacity = BlurRGBA.a + TextureRGBA.a - BlurRGBA.a * TextureRGBA.a;
    113. // 当前像素点混合后的RGBA
    114. return float4(Color / Opacity, Opacity);
    115. }
    116. }; // 注意要加分号
    117. // Function func;
    118. // func.Texture = Texture;
    119. // func.TextureSampler = TextureSampler;
    120. // func.ShadowRGBA = ShadowRGBA;
    121. // func.Position = ShadowLength * Direction;
    122. // func.BorderThresholdLeft = BorderThreshold.x;
    123. // func.BorderThresholdTop = BorderThreshold.y;
    124. // func.BorderThresholdRight = 1 - BorderThreshold.z;
    125. // func.BorderThresholdBottom = 1 - BorderThreshold.w;
    126. // func.PI = PI;
    127. // func.TexturePixel = TexturePixel;
    128. Function func = { Texture, TextureSampler, ShadowRGBA, ShadowLength * Direction, BorderThreshold.x, BorderThreshold.y, 1 - BorderThreshold.z, 1 - BorderThreshold.w, PI, TexturePixel };
    129. if (ShadowSize < 1) {
    130. return func.GetShadowRGBA(UVs);
    131. }
    132. return func.GetShadowSizeRGBA(UVs, round(ShadowSize));
    133. }

    2、创建材质

    M_PS_Style_Shadow

    修改 材质域 和 混合模式。

     

     调用之前创建的材质函数。

    材质函数调用方式。

     如果之前没有公开到库,则使用 material function call 调用

     

     3、效果预览

    二、文字投影

    1、添加 Retainer Box

    设置尺寸,并指定效果材质。

    2、添加 TextBlock

    3、设置材质实例参数

    由于字体所在画布大小为 300 * 100,这里要设置同步。

     

    4、效果预览(需要运行游戏才能看到效果)

    ShadowSize 为 0。

     ShadowSize 为 10。

     ShadowSize 为 20。

    需要改颜色就修改 ShadowRGBA。 

    三、人物角色投影

    1、创建渲染目标

     命名 RT_Equipment。

    用于 UI 贴图,修改参数,这里大小使用1024。

    2、创建 Actor 

    命名 BP_Equipment

     

    添加 场景捕获组件2D。

     根据需要设置参数。

    添加 骨骼网络体组件。

    指定模型与动画。

     

    调整好位置。

    3、放入场景。

     将 BP_Equipment 放入 Level,也可以在运行时动态生成。

    4、修改材质

     由于 A 通道需要反向,所以之前的 Shadow 代码做如下改动:

    1. // 纹理采样
    2. float4 TextureSample(float2 UVs) {
    3. // 如果需要 alpha 通道反向,在此修改。
    4. float4 PixelRGBA = Texture2DSampleLevel(this.Texture, this.TextureSampler, UVs, 0).xyzw;
    5. return float4(PixelRGBA.rgb, 1 - PixelRGBA.a);
    6. }

    5、效果预览

    四、使用混合模式

    假定使用 正片叠底,代码做如下改动。

    1. // 阴影颜色
    2. float3 ShadowColor(float3 Color) {
    3. // 如果需要与颜色混合,在此修改返回值,如下式 正片叠底。
    4. return this.ShadowRGBA.rgb * Color;
    5. }

    也可以换成其他的混合模式,具体算法可以参考文章 《HLSL实现PS混合模式》

    效果预览 

  • 相关阅读:
    思维模型 秩序
    5G NR学习入门
    抽丝剥茧C语言(高阶)指针进阶练习
    【TypeScirpt学习记录】二
    网络通信编程基础,BIO,NIO
    FragmentManager is already executing transactions异常
    王树森Transformer学习笔记
    Spring中还有一招集合注入的写法
    IDEA中的MySQL数据库所需驱动包的下载和导入方法
    C/C++计算(a+b)c的值 2019年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析
  • 原文地址:https://blog.csdn.net/qq_42486920/article/details/127905969