好的,这里有一些松散的伪代码,我认为可以解决这个问题。
从卡片的 z 顺序排序列表开始。每张卡片都有一个可见矩形列表(稍后解释),需要从一个矩形开始,设置为卡片的完整边界框。循环首先从最低 z 顺序卡开始。
Cards.SortZOrder();
foreach Card in Cards do
Card.ResetVisibleRects; // VisibleRects.DeleteAll; VisibleRects.Add(BoundingBox);
CurrentCard = Cards.Last;
TestCard = CurrentCard;
这里的想法是,我们将从我们的“当前”卡向上工作,看看每张更高的卡对它有什么影响。当我们测试每张更高的卡片时,有 3 种可能性。它要么完全错过,要么完全模糊,要么部分模糊。对于完全错过,我们忽略测试卡,因为它不会影响我们当前的卡。为了完全模糊,我们当前的卡被剔除。部分重叠是可见矩形列表的来源,因为部分重叠可以(可能)将下部矩形分成两部分。(如果您只抓两张扑克牌或索引卡,很容易看出这是如何发挥作用的。顶部的一张会导致底部的一张调整它的一侧,如果它们共享任何边缘,或者它会导致底部的一张分裂如果它们不共享边,则分成两个矩形。)
警告:这是非常未优化的展开代码......只是为了谈论原则。是的,我即将使用“goto”......如果你必须嘲笑我。
[GetNextCard]
TestCard = Cards.NextHighest(TestCard);
[OverlapTest]
// Test the overlap of TestCard against all our VisibleRects.
// The first time through this test, CurrentCard will have only one
// rect in the VisibleRect list, but that rect may get split up later.
// OverlapTests() checks each rect in the VisibleRects list, and
// creates an Overlap record for any of the rects that do overlap,
// like: Overlap.RectIndex, Overlap.Type. It also summarizes the
// results into the .Summary field.
Result = CurrentCard.OverlapTests(TestCard);
case Result.Summary
none:
goto [GetNextCard];
complete:
CurrentCard.Culled = true;
// we're now done with this CurrentCard, so we move upwards
CurrentCard = TestCard;
goto [GetNextCard]
partial:
// since there was some overlap, we need to adjust,
// split, or delete some or all of our visible rectangles.
// (we won't delete them all, that would have been caught above)
foreach Overlap in Result.Overlaps
R = CurrentCard.VisibleRects[Overlap.RectIndex];
case Overlap.Type
partial: CurrentCard.SplitOrAdjust(R, TestCard);
complete: CurrentCard.Delete(R);
end case
// so we've either added new rects, or deleted some, but either
// way, we're done with this test card. We leave CurrentCard
// where it is and loop to look at the next higher card.
goto [GetNextCard]
CurrentCard = Cards.First
由于最上面的卡片始终完全可见,因此测试完成。
这里还有一些想法......
我认为这在实际代码中会相当简单。关于它的最复杂的事情是将一个矩形分成两部分,并且考虑到这都是整数数学,即使那是微不足道的。
此外,不必在每个绘制周期都执行此操作。仅当内容、位置或 z 顺序发生任何变化时才需要执行此操作。
在通过列表之后,您会得到一个可绘制的卡片列表,每张未剔除的卡片至少有一个矩形,可能会落在显示器的剪切/脏区域内。当你绘制一张卡片时,你可以检查它的可见矩形列表,并且可能会跳过卡片的绘制部分,这些部分可能渲染起来很昂贵。