一、PS图层样式投影效果
1、创建材质函数
MF_PS_Style_Shadow
公开到库(可选)
定义 function input。
Shadow代码:
/**
PS图层样式投影效果
@param {UVs} texture coordinate
@param {TextureObject} texture object
@param {TextureSize} 纹理大小
@param {ShadowRGBA} 投影颜色与不透明度
@param {ShadowRotate} 投影角度
@param {ShadowLength} 投影距离
@param {ShadowSize} 投影大小
@param {OpacityThreshold} 纹理透明度阈值
@param {BorderThreshold} 边界透明度阈值
*/
float4 Shadow(float2 UVs, Texture2D TextureObject, float2 TextureSize, float4 ShadowRGBA, float ShadowRotate, half ShadowLength, half ShadowSize, float OpacityThreshold = 0, float BorderThreshold = 0.0001) {
const float PI = acos(-1);
// 单位像素
float2 TexturePixel = 1 / TextureSize;
// 角度
float Angle = 360 * ShadowRotate;
// 弧度
float Degrees = Angle / 180 * PI;
// 阴影反向方位(单位向量)
float2 Direction = TexturePixel * float2(cos(Degrees), sin(Degrees));
class Function {
Texture2D TextureObject;
SamplerState TextureObjectSampler;
float4 ShadowRGBA;
float2 Position;
float OpacityThreshold;
float BorderThresholdLeftAndTop;
float BorderThresholdRightAndBottom;
float PI;
float2 TexturePixel;
float4 GetShadowRGBA(float2 UVs, out half ShadowStep) {
ShadowStep = 0;
float4 TextureRGBA = Texture2DSampleLevel(this.TextureObject, this.TextureObjectSampler, UVs, 0).xyzw;
if (TextureRGBA.w > this.OpacityThreshold) {
return TextureRGBA;
}
ShadowStep = 1;
// 阴影反向方位 UVs
float2 PositionUVs = UVs + this.Position;
// 阴影反向方位 UVs 超出了 0 - 1 的范围则不计算
if (PositionUVs.x < this.BorderThresholdLeftAndTop || PositionUVs.x > this.BorderThresholdRightAndBottom || PositionUVs.y < this.BorderThresholdLeftAndTop || PositionUVs.y > this.BorderThresholdRightAndBottom) {
return TextureRGBA;
}
ShadowStep = 2;
// 阴影反向方位像素点不透明度
float PositionOpacity = Texture2DSampleLevel(this.TextureObject, this.TextureObjectSampler, PositionUVs, 0).w;
if (PositionOpacity < this.OpacityThreshold) {
return TextureRGBA;
}
ShadowStep = 3;
// 返回阴影RGBA
return this.ShadowRGBA;
}
float4 CalculateGetShadowSizeRGBA(float2 UVs) {
float4 ShadowSizeRGBA = Texture2DSampleLevel(this.TextureObject, this.TextureObjectSampler, UVs, 0).xyzw;
return ShadowSizeRGBA.w < this.OpacityThreshold ? ShadowSizeRGBA : this.ShadowRGBA;
}
float Calculate1DGaussian(float x) {
return exp(-0.5 * pow(this.PI * x, 2));
}
float4 GetShadowSizeRGBA(float2 UVs, half ShadowSize) {
// 投影大小范围内像素颜色累加
float4 RGBASum = float4(0, 0, 0, 0);
// 投影大小范围内像素的权重
float WeightSum = 0;
for (half x = -ShadowSize; x <= ShadowSize; x++) {
for (half y = -ShadowSize; y <= ShadowSize; y++) {
float Weight = this.Calculate1DGaussian(x / ShadowSize) * this.Calculate1DGaussian(y / ShadowSize);
WeightSum += Weight;
float2 OffsetUVs = UVs + float2(x, y) * this.TexturePixel + this.Position;
if (OffsetUVs.x < this.BorderThresholdLeftAndTop || OffsetUVs.x > this.BorderThresholdRightAndBottom || OffsetUVs.y < this.BorderThresholdLeftAndTop || OffsetUVs.y > this.BorderThresholdRightAndBottom) {
continue;
}
float4 RGBA = this.CalculateGetShadowSizeRGBA(OffsetUVs);
RGBASum += RGBA * Weight;
}
}
return RGBASum / WeightSum;
}
}; // 注意要加分号
// func.TextureObject = TextureObject;
// func.TextureObjectSampler = TextureObjectSampler;
// func.ShadowRGBA = ShadowRGBA;
// func.Position = ShadowLength * Direction;
// func.OpacityThreshold = OpacityThreshold;
// func.BorderThresholdLeftAndTop = BorderThreshold;
// func.BorderThresholdRightAndBottom = 1 - BorderThreshold;
// func.PI = PI;
// func.TexturePixel = TexturePixel;
Function func = { TextureObject, TextureObjectSampler, ShadowRGBA, ShadowLength * Direction, OpacityThreshold, BorderThreshold, 1 - BorderThreshold, PI, TexturePixel };
half ShadowStep;
// 结果色
float4 RGBA = func.GetShadowRGBA(UVs, ShadowStep);
// 如果不是投影区域,则返回当前结果色
if (ShadowStep <= 1 || ShadowSize < 1) {
return RGBA;
}
// 返回计算阴影大小后的结果色
return func.GetShadowSizeRGBA(UVs, ShadowSize);
}
2、创建材质
M_PS_Style_Shadow
修改参数。
如果之前没有公开到库,则使用 material function call 调用
3、效果预览
一、渲染人物角色
1、创建渲染目标
命名为 RT_Equipment。
用于 UI 贴图,修改参数,这里大小使用1024。
2、创建 Actor
命名 BP_Equipment。
添加 场景捕获组件2D。
根据需要设置参数。
添加 骨骼网络体组件。
指定模型与动画。
调整好位置。
3、放入场景。
将 BP_Equipment 放入 Level,也可以在运行时动态生成。
4、修改材质
由于 A 通道需要反向,所以之前的 Shadow 代码做如下改动:
改动一:
float4 TextureRGBA = Texture2DSampleLevel(this.TextureObject, this.TextureObjectSampler, UVs, 0).xyzw;
TextureRGBA = float4(TextureRGBA.rgb, 1 - TextureRGBA.a);
if (TextureRGBA.w > this.OpacityThreshold) {
return TextureRGBA;
}
改动二:
float PositionOpacity = Texture2DSampleLevel(this.TextureObject, this.TextureObjectSampler, PositionUVs, 0).w;
if (1 - PositionOpacity < this.OpacityThreshold) {
return TextureRGBA;
}
改动三:
float4 ShadowSizeRGBA = Texture2DSampleLevel(this.TextureObject, this.TextureObjectSampler, UVs, 0).xyzw;
ShadowSizeRGBA = float4(ShadowSizeRGBA.rgb, 1 - ShadowSizeRGBA.a);
return ShadowSizeRGBA.w < this.OpacityThreshold ? ShadowSizeRGBA : this.ShadowRGBA;