Skip to content

Skija 中的阴影

Skija 提供了两种不同的绘制阴影方式:2D 投影阴影(通过 ImageFilters)和 3D 高程阴影(通过 ShadowUtils)。

1. 2D 投影阴影 (ImageFilter)

这是为特定绘制操作添加阴影的标准方法。阴影跟随所绘制几何形状或图像的轮廓。

java
ImageFilter shadow = ImageFilter.makeDropShadow(
    2.0f, 2.0f,   // 偏移量 (dx, dy)
    3.0f, 3.0f,   // 模糊量 (sigmaX, sigmaY)
    0x80000000    // 阴影颜色 (50% 透明黑色)
);

Paint paint = new Paint().setImageFilter(shadow);
canvas.drawRect(Rect.makeXYWH(50, 50, 100, 100), paint);

仅绘制阴影

如果只想绘制阴影而不绘制原始对象(例如,用于复杂分层),请使用 makeDropShadowOnly


2. 3D 高程阴影 (ShadowUtils)

ShadowUtils 提供了一个更基于物理的阴影模型,类似于 Material Design 的高程概念。它计算特定 3D 位置的光源如何将“遮挡物”(一个 Path)的阴影投射到画布平面上。

基本用法

java
Path path = new Path().addRect(Rect.makeXYWH(50, 50, 100, 100));

// Z 平面:对象的高程。
// 对于平面 UI 元素通常是常量:(0, 0, elevation)
Point3 elevation = new Point3(0, 0, 10.0f); 

// 光源位置:相对于画布的 3D 坐标
Point3 lightPos = new Point3(250, 0, 600); 

float lightRadius = 800.0f;
int ambientColor = 0x10000000;
int spotColor = 0x30000000;

ShadowUtils.drawShadow(
    canvas, 
    path, 
    elevation, 
    lightPos, 
    lightRadius, 
    ambientColor, 
    spotColor, 
    ShadowUtilsFlag.TRANSPARENT_OCCLUDER
);

// 注意:drawShadow 仅绘制阴影。
// 你仍然需要绘制对象本身:
canvas.drawPath(path, new Paint().setColor(0xFFFFFFFF));

环境阴影 vs. 聚光阴影

  • 环境阴影:由间接光引起的柔和、无方向性的阴影。
  • 聚光阴影:由特定光源位置引起的定向阴影。 两者结合可以创造出逼真的深度效果。

阴影标志

  • TRANSPARENT_OCCLUDER:如果你的对象是半透明的,请使用此标志,这样阴影就不会被裁剪到对象下方。
  • GEOMETRIC_ONLY:如果不需要高质量模糊,可以使用此优化标志。
  • DIRECTIONAL_LIGHT:将光源视为无限远(如阳光)。

对比

特性投影阴影 (ImageFilter)高程阴影 (ShadowUtils)
模型2D 高斯模糊3D 透视投影
性能快速(由 Skia 缓存)更复杂,但高度优化
用法Paint 上设置直接调用 ShadowUtils
最适合文本、简单的 UI 发光效果、图标Material Design 按钮、卡片、深度效果

视觉示例

要查看这些阴影的实际效果,请运行 Scenes 示例应用并选择 ShadowUtils 场景。

源代码: examples/scenes/src/ShadowUtilsScene.java

图:各种 ShadowUtils 标志和光源位置的对比。