关于Vector Graphics
Vector Graphics package提供了一个SVG导入器以及通用的矢量图形API。
该包被认为是实验性的,不建议在生产中使用。因此,必须使用Unity Package Manager manualUnity Package Manager manual中描述的com.unity.vectorgraphics名称来添加包。
要求
Vector Graphics package版本1.0.0与以下版本的Unity编辑器兼容: 2018.1及更高版本。
已知限制
Vector Graphics package中的SVG导入器实现了SVG 1.1规范的一个子集,但有一些限制:
- 文本元素还不受支持(SVG 1.1第10节)
- 不支持逐像素遮罩(SVG 1.1第14.4节)
- 不支持过滤器效果(SVG 1.1第15节)
- 不支持任何交互性特性(SVG 1.1第16节)
- 不支持动画(SVG 1.1第19节)
请注意,当使用-no-graphics命令行参数启动Unity时,程序包可能无法正确导入资产。该包在以纹理格式导入资产时需要图形,因为它将需要将向量内容呈现到纹理资产中。
使用Vector Graphics
SVG导入器
这个包提供了一个SVG导入器,可以读取和解释SVG文档,并生成在Unity中使用的2D精灵。
像其他资产一样将SVG文件导入Unity编辑器。
将它们直接放到“项目”窗口的“资产”文件夹中,或者从菜单栏中选择“Assets > Import New Asset”。导入后,您可以在层次结构视图或场景视图中实例化结果资产。
属性 | 功能 |
---|---|
Pixels Per Unit | 对应于1个场景单元的SVG单元数。 |
Tessellation Step Distance | 当创建路径时,Unity生成三角形的距离。 较小的步长将导致更光滑的曲线,但代价是更多的三角形。 |
Gradient Resolution | 用于存储渐变的纹理大小。 |
Pivot | 所生成的精灵的轴心的位置。这遵循与常规精灵相同的约定,并有一个额外的SVG Origin值。当使用SVG Origin时,轴心是(0,0)。 |
基础设置
当Setting使用Basic参数时,只需要提供目标分辨率(Target Resolution)和缩放因子(Zoom Factor)。当Setting使用Advanced参数时,可确保您的SVG文档渲染在足够高的分辨率。
高级设置
如果要全面控制SVG文档的导入,则可以指定以下高级设置:
属性 | 功能 |
---|---|
Step Distance | 导入器沿着路径生成顶点时所处的距离。较低的值会导致更密集的网格。 |
Sampling Steps | 导入器根据路径进行计算的样本数。更多的样本可能会得到更精确的曲线,特别是当曲线有尖角时。 |
Max Cord Deviation | 最大直线偏差,较小的值产生更多的网格。 |
Max Tangent Angle | 导入器生成网格的最大切线角度(单位是度)。 |
只要不满足每个已启用的约束,导入器就会对曲线进行细分。
精灵编辑器也可用,其工作方式与常规的精灵资源完全相同。
Vector Graphics API
所提供的类和方法使您能够直接在代码中处理向量数据。
SVG导入器在内部使用这些api来生成和细分生成的精灵。
向量图形API是一组简单的类和结构,它将向量数据保存在一起。
这是伴随着静态的方法来操作和转换这些数据。
向量图形包的核心是场景类(Scene),它存储了一个向量对象的图形。
它的根属性(Root)是场景节点(SceneNode)的一个实例,它包含可绘制项列表、子节点列表、转换和剪切器(请参见后面的剪切部分内容)。
public class SceneNode
{
public List<SceneNode> Children { get; set; }
public List<IDrawable> Drawables { get; set; }
public Matrix2D Transform { get; set; }
public SceneNode Clipper { get; set; }
}
主要有两种可绘制的实例:路径(Paths)和形状(Shapes)。
Paths
路径是由BezierContour线定义的可绘制路径。BezierContour包含BezierPathSegment数组和指示轮廓是否关闭的标志。
public class Path : IDrawable
{
public BezierContour Contour { get; set; }
public PathProperties PathProps { get; set; }
}
public struct BezierContour
{
public BezierPathSegment[] Segments { get; set; }
public bool Closed { get; set; }
}
public struct BezierPathSegment
{
public Vector2 P0;
public Vector2 P1;
public Vector2 P2;
}
BezierPathSegment数组定义了一个三次Bézier曲线链。上面的线段只指定第一个点P0和两个控制点P1和P2。路径类(Path)使用数组中下一个段的P0值来完成曲线。因此,您总是需要至少两个段来定义一个有效的BezierContour。使用这种方法允许链接多个线段,并保证曲线的连续性。例如,考虑此路径:
你可以这样构建这个路径:
var segments = new BezierPathSegment[] {
new BezierPathSegment() { P0 = a, P1 = b, P2 = c },
new BezierPathSegment() { P0 = d, P1 = e, P2 = f },
new BezierPathSegment() { P0 = g }
};
var path = new Path() {
contour = new BezierContour() {
Segments = segments,
Closed = false
},
pathProps = new PathProperties() {
Stroke = new Stroke() { Color = Color.red, HalfThickness = 1.0f }
}
};
当定义具有Closed = true的BezierContour时,轮廓的最后一个路径段将被连接到第一个路径段,并且最后一个路径段的P1和P2值将被用作控制点。
Shapes
就像路径一样,形状也是由BezierContour定义的,但它们也提供了一种填充方法:
public class Shape : Filled
{
public BezierContour[] Contours { get; set; }
}
public abstract class Filled : IDrawable
{
public IFill Fill { get; set; }
public Matrix2D FillTransform { get; set; }
public PathProperties PathProps { get; set; }
}
有几个类实现了IFill接口:
SolidFill
一个简单的彩色填充TextureFill
纹理填充GradientFill
线性或径向渐变填充
Gradients
public class GradientFill : IFill
{
public GradientFillType Type { get; set; }
public GradientStop[] Stops { get; set; }
public FillMode Mode { get; set; }
public AddressMode Addressing { get; set; }
public Vector2 RadialFocus { get; set; }
}
public struct GradientStop
{
public Color Color { get; set; }
public float StopPercentage { get; set; }
}
请考虑以下线性填充,以及要生成它的GradientFill实例:
var fill = new GradientFill() {
Type = GradientFillType.Linear,
Stops = new GradientFillStop[] {
new GradientFillStop() { Color = Color.blue, StopPercentage = 0.0f },
new GradientFillStop() { Color = Color.red, StopPercentage = 0.5f },
new GradientFillStop() { Color = Color.yellow, StopPercentage = 1.0f }
}
};
梯度寻址模式定义了当梯度坐标超出范围时,Unity如何显示颜色,如下图所示:
Fill Mode
填充类还提供了一个填充模式,它决定了如何定义形状内部的孔。
FillMode.NonZero通过将轮廓段与水平线相交来确定哪些点在一个形状内。轮廓的方向确定点是在形状内部还是外部:
FillMode.OddEven还可以通过将分段与一条水平线相交来工作。形状内的点是偶数段交叉时的点,奇数段交叉时,形状外的点:
Clipping
在上面的例子中,重复的正方形形状被一个椭圆剪切。在代码中,这可以这样做:
var ellipse = new SceneNode() {
Drawables = new List<IDrawable> { VectorUtils.MakeEllipse(ellipse, Vector2.zero, 50, 100) }
};
var squaresPattern = ...;
var squaresClipped = new SceneNode() {
Children = new List<SceneNode> { squaresPattern },
Clipper = ellipse
};
请注意,只有形状可以作为剪裁器(剪裁过程会忽略在剪裁器中定义的任何笔划)。被剪辑的内容可以是任何形状和/或笔画。
警告:剪切过程可能是一个昂贵的操作。使用简单剪切简单形状可能执行合理,但任何复杂形状和/或剪裁都可能导致帧率显著下降。
渲染矢量图形
要在屏幕上渲染矢量图形元素,首先获取场景的镶嵌(三角)版本。当设置了矢量场景实例时,可以使用以下VectorUtils方法对其进行细分:
public static List<Geometry> TessellateScene(Scene scene, TesselationOptions options);
TesselationOptions类似于高级导入器设置:
public struct TesselationOptions
{
public float StepDistance { get; set; }
public float MaxCordDeviation { get; set; }
public float MaxTanAngleDeviation { get; set; }
public float SamplingStepSize { get; set; }
}
请注意,最大的角度偏差(maxTanAngleDeviation)是用弧度表示的。
若要禁用最大测线偏差约束(maxCordDeviation),请将其设置为float.MaxValue。
要禁用最大的偏差约束(maxTanAngleDeviation),请将其设置为Mathf.PI/2.0f。
禁用约束将使镶嵌速度加快,但可能会生成更多的顶点。
几何体(Geometry)对象的结果列表包含正确渲染场景所需的所有顶点和相关信息。
纹理和渐变图谱
如果场景具有任何纹理或渐变,则必须生成纹理图集并填充几何图形的UV。这些方法是向量数类(VectorUtils)的一部分:
public static TextureAtlas GenerateAtlas(
IEnumerable<Geometry> geoms, // The geometry generated by the TessellateScene method
uint rasterSize); // The desired atlas size (128 is enough for most purposes)
public static void FillUVs(
IEnumerable<Geometry> geoms, // The geometry for which the UVs will be filled
TextureAtlas texAtlas); // The texture atlas generated by the GenerateAtlas method
GenerateAtlas方法是一项昂贵的操作,因此尽可能缓存生成的纹理2D对象。仅当场景内的纹理或渐变发生变化时,才需要重新生成图集。
当顶点在几何体内部发生变化时,请调用FillUVs方法。绘制镶嵌场景您可以通过多种方式渲染几何图形。例如:
- 填充Mesh资产
- 建立一个Sprite资产
- 使用Unity的低级图形库
对于这些方法,使用任何一种提供的材料来绘制镶嵌矢量图形内容。如果场景包含纹理或渐变,请使用以下材质:
var mat = new Material(Shader.Find("Unlit/VectorGradient"));
否则,你可以使用:
var mat = new Material(Shader.Find("Unlit/Vector"));
要填充网格资源,请使用以下“VectorUtils”方法:
public static void FillMesh(
Mesh mesh, // The mesh to fill, which will be cleared before filling
List<Geometry> geoms, // The geometry resulting from the "TessellateScene" call
float svgPixelsPerUnit, // How many "SVG units" should fit in a "Unity unit"
bool flipYAxis = false); // If true, the Y-axis will point downward
要构建精灵资源,请使用以下VectorUtils类型方法:
public static Sprite BuildSprite(
List<Geometry> geoms, // The geometry resulting from the "TesselateScene" call
float svgPixelsPerUnit, // How many "SVG units" should fit in a "Unity unit"
Alignment alignment, // The sprite alignement
Vector2 customPivot, // If alignment is "Custom", this will be used as the custom pivot
UInt16 gradientResolution); // The resolution used for the gradient texture
要将精灵渲染到Texture2D,请使用以下VectorUtils方法:
public static Texture2D RenderSpriteToTexture2D(
Sprite sprite, // The sprite to draw
int width, int height, // The texture dimensions
Material mat, // The material to use (should be Unlit_Vector or Unlit_VectorGradient)
int antiAliasing = 1); // The number of samples per pixel
要使用即时模式GL命令渲染生成的精灵,请使用VectorUtils类中的“RenderSprite”方法将精灵绘制成一个单位方块(X和Y方向上0和1之间的框):
public static void RenderSprite(
Sprite sprite, // The sprite to draw
Material mat); // The material to use (should be Unlit_Vector or Unlit_VectorGradient)