繁体   English   中英

Direct2D深度缓冲区

[英]Direct2D Depth Buffer

我需要绘制一个形状列表,我正在使用Direct2D。 我从文件中获取形状列表。 列表已排序,文件中元素的顺序表示将绘制这些形状的顺序。 因此,例如,如果文件指定两个位于相同位置且具有相同大小的矩形,则只有第二个矩形可见(因为第一个将被覆盖)。

鉴于我的形状列表,我按以下方式进行绘图:

list<Shape> shapes;

for (const auto& shape : shapes)
   shape.draw();

很容易看出,如果我有两个形状,我无法反转绘图操作的顺序,这意味着我必须确保shape2将始终在shape1之后shape1 ,依此类推。 接下来我无法使用多个线程来绘制我的形状,这在性能方面是一个巨大的劣势。

我读到Direct3D支持深度缓冲区(或z缓冲区),它为每个像素指定了它的z坐标,这样只会绘制“可见”像素(更接近观察者的on), 无论顺序如何形状是绘制的 当我读取文件时,我有每个形状的深度信息。

有没有办法在Direct2D中使用深度缓冲区,或类似的技术允许我使用多个线程来绘制我的形状?

有没有办法在Direct2D中使用深度缓冲区,或类似的技术允许我使用多个线程来绘制我的形状?

这里的答案是否定的 虽然Direct2D库是建立在Direct3D之上的,但它并没有通过API为用户提供这样的功能,因为你可以绘制的基元只能用二维坐标来描述。 确保绘制到渲染目标的最后一个原始图形是可见的,因此不会进行深度测试。 此外,Direct3D中的深度缓冲区与CPU端的多线程没有多大关系。

另请注意,即使您使用多个线程发出绘图命令,它们也会由Direct3D驱动程序序列化并按顺序执行。 一些较新的图形API(如Direct3D 12Vulkan)确实提供了多线程驱动程序,允许您有效地从不同的线程中提取不同的内容,但它们具有更高的复杂性。

因此,如果你坚持使用Direct2D,你可以选择使用单个线程顺序绘制每个形状。

但是可以做的是,你可以通过测试每个形状与所有其他形状的遮挡来消除有效遮挡的形状。 因此,可以从列表中丢弃被遮挡的形状,并且根本不再渲染。 这里的技巧是由于透明区域(如文本)或者形状是复杂的多边形,一些形状不会完全填充其边界。 这样的形状不容易测试或需要更复杂的算法。

所以你必须迭代所有的形状,如果当前的形状只是一个矩形,那么用所有以前的形状的边界进行遮挡测试。

下面的代码应该被认为是伪代码,它只是为了演示这个想法。

#define RECTANGLE 0
#define TEXT      1
#define TRIANGLE  2
//etc

typedef struct {
    int type; //We have a type field
    Rect bounds_rect; //Bounds rect
    Rect coordinates; //Coordinates, which count vary according to shape type
    //Probably you have many other fields here
} Shape;

//We have all shapes in a vector
std::vector<Shape> shapes;

迭代所有形状。

for (int i=1; i<shapes.size; i++) {
  if(shape[i].type != RECTANGLE) {
    //We will not perform testing if the current shape is not rectangle.
    continue; 
  }

  for(int j=0; j<i; j++) {
    if(isOccluded(&shape[j], &shape[i])) {
      //shape[j] is totally invisible, so remove it from 'shapes' list
    }
  }
}

遮挡测试是这样的

bool isOccluded(Shape *a, Shape *b) {
  return (a.bounds_rect.left > b.coordinates.left && a.bounds_rect.right < b.coordinates.right &&
          a.bounds_rect.top > b.coordinates.to && a.bounds_rect.bottom < b.coordinates.bottom);
}

而且您不必使用单个线程迭代所有形状,您可以创建多个线程来对形状列表的不同部分执行测试。 当然,从列表中删除形状时,您需要一些锁定技术,如互斥锁,但这是另一个主题。

深度缓冲区用于丢弃将在3D空间中被其前面的东西遮挡的基元,通过不打扰无论如何都看不到的东西来节省重绘时间。 如果你想到一个在面对镜头的球前面有一个高而薄的蜡烛的场景,那么整个球都没有被绘制,然后蜡烛被拉过它,只有球的可见侧面。 这就是绘图顺序无关紧要的原因

我没有听说过在D2D中使用深度缓冲区,因为它有点无意义; 在D2D中,一切都被绘制到一个平面上,一些东西怎么能在别的前面或后面呢? API可能会支持它,但我怀疑它,因为它没有抽象意义。 每个形状的深度信息只是绘制它的顺序,基本上是你已经拥有的

相反,你可以做什么,在保持秩序的同时将你的形状划分并分配给你的线程,即

t1 { shape1, shape2, shape3 } = shape123
t2 { shape4, shape5, shape6 } = shape456
...

并将形状绘制到新对象(但不是后缓冲区)上,根据您的形状类别,您可以将结果表示为形状。 这将为您留下许多形状,这些形状仍然有序但已经并行计算。 然后,您可以通过按顺序绘制结果逐渐构成最终结果,即

t1 { shape123, shape456, shape789 }
t2 { shape101112, shape131415 }

t1 { shape123456789, shape101112131415 } = final shape

现在你有了最终形状,你可以正常绘制

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM