几何实现概述
本主题介绍如何使用 Direct2D 几何图形实现来提高应用在某些情况下的几何图形呈现性能。
它包含以下部分:
什么是几何图形实现?
Windows 8.1中引入的几何图形实现是一种新型的绘图基元,它使 Direct2D 应用能够在某些情况下轻松提高几何图形呈现性能。 几何实现由 ID2D1GeometryRealization 接口表示。
为什么使用几何图形实现?
当 Direct2D 呈现 ID2D1Geometry 对象时,它必须将该几何图形转换为图形硬件通过称为分割的过程理解的形式。 通常,Direct2D 必须对绘制的每个帧的几何图形进行细化,即使几何图形不会更改。 如果应用每帧呈现相同的几何图形,则重复的重新分割表示浪费的计算工作量。 缓存几何图形的分割甚至完全光栅化,以及绘制每个帧的缓存表示形式而不是重复重新细化,在计算上效率更高。
开发人员解决此问题的一种常见方法是缓存几何图形的完整光栅化。 具体而言,通常创建一个新位图,将几何图形光栅化为该位图,然后根据需要将该位图绘制到场景中。 (此方法在提高 Direct2D 应用的性能的 几何图形呈现 部分中进行了介绍。) 虽然此方法在计算上非常高效,但它有一些缺点:
- 缓存的位图对应用于场景的转换中的更改很敏感。 例如,缩放光栅化可能会导致明显的缩放项目。 使用高质量的缩放算法缓解这些项目的计算成本可能很高。
- 缓存的位图会消耗大量内存,尤其是在以高分辨率光栅化时。
几何实现提供了一种缓存几何图形的替代方法,可避免上述缺点。 几何实现不是像完全光栅化) 一样用像素 (表示,而是用数学平面上的点表示。 因此,它们对缩放和其他操作的敏感度不如完全光栅化,并且占用的内存要少得多。
何时使用几何图形实现
当你的应用呈现形状不常更改但可能会更改转换的复杂几何图形时,请考虑使用几何图形实现。
例如,假设有一个映射应用程序显示静态地图,但允许用户放大和缩小。此应用可以从使用几何图形实现中受益。 由于要呈现的几何图形保持静态,因此缓存它们以节省细化工作非常有用。 但是,由于地图是在用户缩放时缩放的,因此由于缩放项目,缓存完全光栅化并不理想。 缓存几何图形实现将允许应用避免重新分割工作,同时在缩放期间保持较高的视觉质量。
另一方面,请考虑具有不断变化的动画几何图形的万花筒应用。 此应用可能不会受益于使用几何图形实现。 由于形状本身会因框架而变化,因此缓存其细化没有用。 此应用的最佳方法是直接绘制 ID2D1Geometry 对象。
创建几何图形实现
必须从现有的 ID2D1Geometry 对象创建 ID2D1GeometryRealization 对象。 若要创建几何图形实现,请调用 CreateFilledGeometryRealization 方法或 CreateStrokedGeometryRealization 方法,并传入要实现的 ID2D1Geometry 。
- CreateFilledGeometryRealization 创建形状内部的实现:通过调用 FillGeometry 绘制的区域。
- CreateStrokedGeometryRealization 创建形状笔划的实现:通过调用 DrawGeometry 绘制的区域。
这两种几何图形实现都由 ID2D1GeometryRealization 接口表示。
创建几何图形实现时, Direct2D 必须将所提供的几何图形中的任何曲线平展为多边形近似值。 必须向创建方法提供平展容错参数,该参数指定几何图形的真实曲线与其多边形近似值之间的最大距离(以设备无关的像素 (DIP) )。 提供的平展容差越低,生成的几何图形实现对象的保真度就越高。 同样,提供较高的平展容差会产生较低的保真几何实现。 请注意,与低保真度几何图形相比,高保真几何图形实现的绘制成本更高,但在引入可见项目之前,可以进一步缩放它们。 有关使用平展容差的指导,请参阅下面的 缩放几何图形实现 。
注意
几何图形实现对象与特定的图形设备相关联:它们是依赖于设备的资源。
绘制几何图形实现
绘制几何图形实现类似于绘制其他 Direct2D 基元,如位图。 为此,请调用 DrawGeometryRealization 方法,并向其传递要绘制的几何体实现对象和要使用的画笔。 与其他 Direct2D 绘图方法一样,必须在对 BeginDraw 和 EndDraw 的调用之间调用 DrawGeometryRealization。
缩放几何图形实现
与其他 Direct2D 基元一样,几何实现遵循设备上下文上的转换集。 尽管平移和旋转转换对几何图形实现的视觉质量没有影响,但缩放转换可以产生视觉伪像。
具体而言,对任何几何图形实现应用足够大的刻度可以揭示真实曲线的多边形近似值。 此处的图像显示了一对椭圆几何体实现, (填充和笔划) ,这些实现已纵向扩展太远。 曲线平展项目可见。
对视觉质量敏感的应用应采取措施确保不会发生这种情况。 如何处理缩放取决于应用的需求。 下面是几种不同类型的应用的建议方法。
在无法缩放的应用中使用几何图形实现
如果你的应用不对几何图形实现执行任何缩放,则使用单个平展容差仅创建一次实现是安全的。 (非缩放转换不会影响呈现的几何图形实现的视觉质量。) 使用 ComputeFlatteningTolerance 函数计算 DPI 的适当平展容差:
float dpiX, dpiY;
deviceContext->GetDpi(&dpiX, &dpiY);
float flatteningTolerance = D2D1::ComputeFlatteningTolerance(
D2D1::Matrix3x2F::Identity(), // apply no additional scaling transform
dpiX, // horizontal DPI
dpiY // vertical DPI
);
在按少量缩放的应用中使用几何图形实现
例如,如果应用可以仅将几何图形实现纵向扩展一小部分 (,) 最多缩放 2 倍或 3 倍,则只需创建一次几何实现,其平展容差比默认值成比例更低。 这将创建一个更高的保真度实现,在发生缩放项目之前,可以大幅纵向扩展;缺点是绘制高保真度实现需要更多的工作。
例如,假设你知道你的应用永远不会将几何图形实现缩放超过 2 倍。 你的应用可以使用默认值的一半的平展容差创建几何图形实现,并且只需根据需要缩放实现(最多 2 倍)。 使用 ComputeFlatteningTolerance 函数通过将 2.0 作为 maxZoomFactor 参数传递来计算适当的平展容差:
float dpiX, dpiY;
deviceContext->GetDpi(&dpiX, &dpiY);
float flatteningTolerance = D2D1::ComputeFlatteningTolerance(
D2D1::Matrix3x2F::Identity(), // apply no additional scaling transform
dpiX, // horizontal DPI
dpiY, // vertical DPI
2.0f // realization can be scaled by an additional 2x
);
在按大量缩放的应用中使用几何图形实现
如果应用可以纵向扩展或缩减几何图形实现,例如, (缩放 10 倍或更多) ,则适当地处理缩放会更加复杂。
对于其中大多数应用,建议的方法是在纵向扩展场景时以逐渐较低的平展容差重新创建几何体实现,以便保持视觉保真度并避免缩放项目。 同样,在缩小场景时,应用应以逐渐更高的平展容差重新创建几何实现,以避免浪费呈现不可见的详细信息。 应用不应在每次缩放更改时重新创建几何图形实现,因为这样做会破坏缓存细化工作的目的。 相反,应用应减少重新创建几何图形实现的频率:例如,在缩放比例每增加或减少 2 倍之后。
每次应用中的缩放更改以响应用户交互时,应用都可以将新比例与上次创建几何实现 (存储的比例进行比较,例如,在 m_lastScale 成员) 中。 在这种情况下,如果两个值在 2) 的因子内接近 (,则不采取进一步的操作。 但是,如果两个值不接近,则重新创建几何图形实现。 ComputeFlatteningTolerance 函数用于计算适合新刻度的平展容差,并将m_lastScale更新为新刻度。
此外,应用始终使用比通常用于新缩放的容差更小的容差来创建实现,方法是将值 2 作为 maxZoomFactor 参数传递给 ComputeFlatteningTolerance。 这样,新的几何图形实现可以按 2 的附加系数纵向扩展,而不会产生缩放项目。
注意
此处所述的方法可能并不适合所有应用。 例如,如果你的应用允许以非常大的因子非常快速地缩放场景 (,如果它包含一个“缩放”滑块,该滑块可在几帧) 的跨度从 100% 移动到 1,000,000%,则此方法可能会通过重新创建每个帧的几何图形实现来产生额外的工作。 另一种方法是在完成对场景比例的每次操作后重新创建几何图形实现, (例如,在用户完成收缩手势) 之后。