Firemonkey半透明Image3D有时是不透明的

时间:2011-12-13 23:58:27

标签: delphi firemonkey

我创建了一个带有3个半透明tImage3D的FireMonkey应用程序。 这是代码和屏幕。一切似乎都很好。

procedure TForm1.Form3DCreate(Sender: TObject);

// create a new semi-transparent timage3d
// object with color and Z position.
procedure NewImage ( const nColor : tColor;
                     const nZ     : integer );
begin
  // create the image
  with tImage3D . Create ( self ) do
    begin
      // put it on the screen
      Parent := self;
      // set the size
      Width := 10;
      Height := 10;
      // set the image to a single pixel.
      Bitmap . Width := 1;
      Bitmap . Height := 1;
      // set the Alpha to $80 to make it
      // semi-transparent
      Bitmap . Pixels [ 0, 0 ] := $80000000 + nColor;
      // set the z position
      Position . Z := nZ;
    end;
end;

begin
  NewImage ( claRed,   +10 );
  NewImage ( claGreen,   0 );
  NewImage ( claBlue,  -10 );
end;

All is well

现在撤销订单。现在它们是不透明的。

begin
  NewImage ( claRed,   -10 );
  NewImage ( claGreen,   0 );
  NewImage ( claBlue,  +10 );
end;

Now they are opaque

我错过了什么?

2 个答案:

答案 0 :(得分:4)

FireMonkey(截至目前)不支持在3D中渲染半透明对象。

FireMonkey仅支持混合半透明对象(通过Opacity属性或因为它们的纹理,例如半透明的PNG图像),但仅blending不是足以使用Z-Buffer(这是FMX和大多数3D应用程序正在使用的)在3D中使用它。

有关技术说明,您可以阅读Transparency sorting,该文章是关于OpenGL的,但也适用于DirectX。

因此,为了获得正确的渲染,您需要从相机的角度将半透明对象从前到后排序

您可以在此帖子中获取更多详细信息和一些代码来解决此问题:

Rendering semi-transparent object in FireMonkey

但请记住,这只是一种解决方法

理想情况下,这应由FireMonkey场景图处理,因为它依赖于渲染,否则,您最终必须更改场景图结构,这可能会产生各种其他副作用,甚至更成问题如果你有多个摄像机在同一个场景中。

此外,排序方法仅适用于不相交的凸对象,并且没有三重叠,例如:

Triple Overlap example

没有正确的排序(其他元素都不在其他元素之前)。

答案 1 :(得分:0)

正如您已经发现的那样,您必须从后向前绘制透明对象。

绘制透明对象时,会绘制对象,并与其后面的像素混合。

所以当你从后面画到前面时会发生这种情况:
您绘制红色图像,它与白色背景混合。您可以通过“粉红色”而不是纯红色来判断它是否与白色背景混合。然后绘制绿色图像,它与已绘制的白色背景和红色图像混合。最后绘制蓝色图像,该图像与已绘制的对象混合。

但现在我们从前到后画画:
我们首先绘制红色平面。它与您可以看到的白色背景混合,因为它是粉红色而不是红色。现在我们绘制绿色飞机。它与白色背景混合,你可以通过颜色来判断,它不是纯净,深沉,绿色。但是,渲染器看到一部分落在红色平面后面,所以它不会绘制那个部分。但是,你认为:红色飞机是透明的,渲染器应该在红色飞机后面绘制!嗯不,渲染器只跟踪z缓冲区/深度缓冲区中像素的深度/ z顺序,它不知道该像素是否透明。蓝色平面也是如此,只绘制了未被其他物体遮挡的部分。

你说的深度缓冲是什么?
在深度缓冲器中,存储每个像素的深度。当您在2,2处以z为1绘制像素时,2,2处的深度缓冲区将更新为值1.现在,当您从1,2到3,2绘制一条线,其中az为3时,渲染器将仅绘制深度缓冲器具有值> = 3的像素。因此绘制像素1,2(并且将1,2的深度缓冲器设置为3)。未绘制像素2,2,因为深度缓冲区表示该像素已经以较小的深度绘制(1对3)。绘制像素3,2并将3,2的深度缓冲设置为3 因此,深度缓冲区用于跟踪每个像素的z顺序,以防止用更远的像素覆盖该像素。

如果您想以正确的方式绘制透明对象,请参阅this answer

摘录答案:

  • 首先绘制不透明物体。
  • 禁用深度缓冲区写入(因此不更新深度缓冲区),但保持启用深度缓冲区检查。
  • 绘制透明对象。由于深度缓冲区未更新,因此您不会遇到透明对象相互遮挡的问题。由于启用了深度缓冲区检查,因此不会在不透明对象后面绘制。

我不知道FireMonkey是否支持禁用深度缓冲区写入,您必须自己查找。