C++ Direct2D深度缓冲区

C++ Direct2D深度缓冲区,c++,directx,direct3d,direct2d,depth-buffer,C++,Directx,Direct3d,Direct2d,Depth Buffer,我需要绘制一个形状列表,我正在使用Direct2D。我从文件中获取形状列表。列表已排序,文件中元素的顺序表示这些形状的绘制顺序。因此,例如,如果文件在同一位置指定了两个大小相同的矩形,则只有第二个矩形可见(因为第一个矩形将被覆盖) 根据我的形状列表,我按以下方式绘制: list<Shape> shapes; for (const auto& shape : shapes) shape.draw(); 列表形状; 用于(常量自动和形状:形状) shape.draw()

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

根据我的形状列表,我按以下方式绘制:

list<Shape> shapes;

for (const auto& shape : shapes)
   shape.draw();
列表形状;
用于(常量自动和形状:形状)
shape.draw();
很容易看出,如果我有两个形状,我就不能颠倒绘图操作的顺序,这意味着我必须确保
shape2
总是在
shape1
之后绘制。因此,我不能使用多个线程来绘制我的形状,这在性能方面是一个巨大的缺点

我了解到Direct3D支持深度缓冲区(或z缓冲区),它为每个像素指定其z坐标,以便只绘制“可见”像素(靠近查看器的像素),而不考虑图形的绘制顺序。读取文件时,我有每个形状的深度信息


有没有一种方法可以在Direct2D中使用深度缓冲区,或者有一种类似的技术可以让我使用多个线程来绘制形状?

深度缓冲区用于丢弃在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
并将形状绘制到新对象(但不是backbuffer)上,根据您的形状类,您可能能够将结果表示为形状。这将给您留下t多个形状,这些形状仍然有序,但已并行计算。然后,您可以通过按顺序绘制结果来逐渐合成最终结果,即

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

t1 { shape123456789, shape101112131415 } = final shape
现在你有了最终的形状,你可以像平常一样画它了

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

这里的答案是否定的。尽管Direct2D库构建在Direct3D之上,但它没有通过API向用户提供此类功能,因为您可以绘制的基本体仅由二维坐标描述。确保绘制到渲染目标的最后一个基本体可见,因此不会进行深度测试。此外,Direct3D中的深度缓冲区与CPU端的多线程无关

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

因此,最终如果您坚持使用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;
#定义矩形0
#定义文本1
#定义三角形2
//等
类型定义结构{
int type;//我们有一个类型字段
Rect bounds_Rect;//bounds Rect
Rect坐标;//坐标,其计数根据形状类型而变化
//这里可能还有很多其他领域
}形状;
//我们有向量中的所有形状
向量形状;
迭代所有形状

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
    }
  }
}
for(int i=1;i b.coordinates.to&&a.bounds\u rect.bottom

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

我不确定
Direct2D
本身-但通常您会指定形状a
z
坐标,按该坐标排序,然后分别渲染,因此实现了一个简单的Z缓冲区。@rhughes我不需要对它们进行排序,因为当我读取文件时,它们已经被排序了。此外,使用此方法可以防止使用多个线程。我指的是按z坐标排序。您不需要在单独的线程上渲染这些。首先用最低的z坐标渲染形状,然后用最高的z坐标绘制形状。我认为你确实应该重新排序油漆,因为那里没有深度。那么你的抽签是(或可能是)一个问题