Firemonkey полупрозрачный Image3D иногда непрозрачный - PullRequest
7 голосов
/ 14 декабря 2011

Я создаю приложение FireMonkey с 3 полупрозрачными tImage3D. Вот код и экран. Все вроде хорошо.

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 ]

4 голосов
/ 14 декабря 2011

FireMonkey (на данный момент) не поддерживает рендеринг полупрозрачных объектов в 3D.

FireMonkey поддерживает только смешивание полупрозрачных объектов (либо через свойство Opacity, либо потому чтоих текстуры, например полупрозрачного PNG-изображения), но одного смешивания недостаточно для получения правильного изображения в 3D с помощью Z-Buffer (что и является FMX, ибольшинство 3D-приложений используют).

Техническое объяснение вы можете прочитать о Сортировка прозрачности , статья посвящена OpenGL, но относится и к DirectX.

Таким образом, чтобы получить правильный рендеринг, вам необходимо отсортировать полупрозрачные объекты с обратной стороны с точки зрения камеры .

Более подробную информацию и некоторый код вы можете получить в этом посте.Чтобы обойти проблему:

Визуализация полупрозрачного объекта в FireMonkey

, но имейте в виду, что это просто обходной путь .

В идеале это должно быть гаУправляемый графом сцены FireMonkey, так как он зависит от рендеринга, в противном случае вам придется изменить структуру графа сцены, которая может иметь различные другие побочные эффекты, и это еще более проблематично, если у вас более одной камерыглядя на ту же сцену.

Кроме того, подход сортировки будет работать только с выпуклыми объектами, которые не пересекаются и для которых у вас нет тройного перекрытия, как в:

Triple Overlap example

Для которых не существует правильной сортировки (ни один из элементов не находится перед остальными).

0 голосов
/ 14 декабря 2011

Как вы уже обнаружили, вы должны рисовать прозрачные объекты сзади вперед.

При рисовании прозрачного объекта объект рисуется и смешивается с пикселями, которые находятся за ним.

Так происходит, когда вы рисуете сзади-вперед:
Вы рисуете красное изображение, оно смешивается с белым фоном.Вы можете сказать по «розовому» вместо чистого красного цвета, что он смешивается с белым фоном.Затем вы рисуете зеленое изображение, оно смешивается с уже нарисованным белым фоном и красным изображением.Наконец, вы рисуете синее изображение, которое смешивается с уже нарисованными объектами.

Но теперь мы рисуем спереди назад:
Сначала мы рисуем красную плоскость.Он смешивается с белым фоном, который вы видите, потому что он розовый, а не красный.Теперь мы рисуем зеленую плоскость.Он смешан с белым фоном, можно судить по цвету, он не чистый, глубокий, зеленый.Но средство визуализации видит, что часть отстает от красной плоскости, поэтому она не рисует эту часть.Но вы думаете: красная плоскость прозрачна, рендер должен рисовать за этой красной плоскостью!Нет, рендерер отслеживает только глубину / z-порядок пикселей в z-буфере / глубине-буфере, он не знает, прозрачен ли этот пиксель или нет.То же самое относится и к синей плоскости, рисуется только та часть, которая не закрыта другими объектами.

О каком буфере глубины вы говорите?
В буфере глубины глубина каждого пикселяхранится.Когда вы рисуете пиксель в 2,2 с азимутом 1, буфер глубины в 2,2 обновляется значением 1. Теперь, когда вы рисуете линию от 1,2 до 3,2 с азимутом 3, рендерербудет рисовать только те пиксели, где буфер глубины имеет значение> = 3. Таким образом, пиксель 1,2 рисуется (а буфер глубины в 1,2 устанавливается на 3).Пиксель 2,2 не прорисован, поскольку буфер глубины указывает, что этот пиксель уже прорисован с меньшей глубиной (1 против 3).Пиксель 3,2 рисуется, а буфер глубины на 3,2 устанавливается на 3.
Таким образом, буфер глубины используется для отслеживания z-порядка каждого пикселя, чтобы предотвратить перезапись этого пикселя пикселем, которыйнаходится дальше.

Если вы хотите правильно нарисовать прозрачные объекты, см. этот ответ .

Выдержка из этого ответа:

  • Первое рисование непрозрачных объектов.
  • Отключение записи в буфер глубины (поэтому буфер глубины не обновляется), но сохранение глубиныпроверка буфера включена.
  • Рисование прозрачных объектов.Поскольку буфер глубины не обновляется, у вас нет проблемы с прозрачными объектами, скрывающими друг друга.Поскольку проверка буфера глубины включена, вы не рисуете за непрозрачными объектами.

Я не знаю, поддерживает ли FireMonkey отключение записи в буфер глубины, вы должны выяснить сами.

...