2011-12-13 83 views
7

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

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

我缺少什么?

+3

显然,一个对象对前面创建的对象只是半透明的。如果那有意义的话。红色框呈现为粉红色,因为尽管可以看到白色背景,但您无法通过它看到绿色或蓝色框。通过绿色框,你可以看到白色背景和红色框,但不是蓝色框。我也有同样的事情与text3d对象发生。 – 2011-12-14 00:22:12

回答

4

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

FireMonkey只支持混合半透明物体(通过,因为他们的纹理的透明度财产或者,例如半透明PNG图像),但blending是不够用得到它的权利在3D一个Z-Buffer(这是什么FMX,和大多数3D应用程序正在使用)。

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

因此,要获得正确的渲染,您需要从摄像机的角度后面到前面排列您的半透明对象。

你可以得到更多的细节和一些代码在这个岗位要解决这个问题:

Rendering semi-transparent object in FireMonkey

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

理想情况下,这应该由FireMonkey场景图处理,因为它依赖于渲染,否则,最终不得不更改场景图结构,该结构可能具有各种其他副作用,甚至更多如果您有多台相机在同一场景中观看,则会出现问题。

此外,排序方法将只能与不相交的凸对象的工作,和你没有三重叠,如:

Triple Overlap example

对于那些不存在正确的排序(没有任何元素在其他人面前)。

0

正如你已经发现你必须从后到前绘制透明物体。

绘制透明物体时,绘制物体并与其后面的像素混合。

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

但是现在我们从前到后绘制:
我们首先绘制红色平面。它与您可以看到的白色背景相融合,因为它是粉红色而不是红色。现在我们画绿色的飞机。它与白色背景融为一体,你可以通过颜色来判断,它不是纯粹,深沉,绿色。但是,渲染者看到一部分落在红色的飞机后面,所以它不会吸引那部分。但是,你认为:红色的飞机是透明的,渲染者应该在这架红色飞机后面画画!嗯,渲染器只跟踪z缓冲区/深度缓冲区中像素的深度/ z顺序,它不知道该像素是否透明。同样的故事也适用于蓝色飞机,只有没有被其他物体遮挡的部分才会被绘制出来。

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

如果要以正确的方式绘制透明物体,请参见this answer。从这个答案

摘录:

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

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