• 0
SerhioUser

Z-Order для 3D-объектов с ZWrite=false

Вопрос

Как задать Z-последовательность 3d-объектов, например TImage3D, у которых ZWrite=false. Пробовал менять Position.Z - не помогает. Картинка становится маленькая и "далеко", но если она была поверх другой, то так сверху и остается.

Как уже где-то писали BringToFront и SendToBack не работают. Но OpenGL ведь отрисовывает их последовательно. Значит где-то есть этот порядок. Как до него добраться?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

1 ответ на этот вопрос

  • 0

Так. Сорцекопание выявило, что за сортировку 3d-объектов отвечает класс TRenderingCompare и код находится в методе TCustomForm3D.RebuildRenderingList.

procedure TCustomForm3D.RebuildRenderingList;
var
  I: Integer;
  CompareFunc: TRenderingCompare;
begin
  if Assigned(Children) and (Children.Count > 0) and (FUpdating = 0) then
  begin
    if Not Assigned(FRenderingList) then
      FRenderingList := TList<TControl3D>.Create;
    FRenderingList.Clear;

    for I := 0 to Children.Count - 1 do
      if (Children[i] is TControl3D) then
        FRenderingList.Add(Children[I] as TControl3D);

    CompareFunc := TRenderingCompare.Create;
    try
      FRenderingList.Sort(CompareFunc);
    finally
      CompareFunc.Free;
    end;
  end;
end;

Никаких условий - просто сортировка без вариантов.

А вот код, собственно, проверки для сортировки:

function TRenderingCompare.Compare(const Left, Right: TControl3D): Integer;
var
  V1, V2: TPoint3D;
begin
  Result := Integer(Left.GetMaterialForSorting) - Integer(Right.GetMaterialForSorting);
  if (Result = 0) and Left.ZWrite and Right.ZWrite then
  begin
    if (Left.Opacity < 1) and (Right.Opacity >= 1) then
      Result := 1
    else if (Left.Opacity >= 1) and (Right.Opacity < 1) then
      Result := -1
    else if (Left.Context <> nil) and (Right.Context <> nil) then
      begin
        V1 := TPoint3D(Left.AbsolutePosition) - TPoint3D(Left.Context.CurrentCameraMatrix.M[3]);
        V2 := TPoint3D(Right.AbsolutePosition) - TPoint3D(Left.Context.CurrentCameraMatrix.M[3]);
        Result := Trunc(V2.Length - V1.Length);
      end;
  end;
end;

Как видно если ZWrite = false, 3D-объекты НЕ СОРТИРУЮТСЯ и находятся в порядке создания на форме. Список находится в приватной переменной FRenderingList, к которой мы не можем получить доступ даже сделав наследника от TForm3D.

Ладно. FRenderingList заполняется из списка TFmxChildrenList.Children, до которого мы можем достучаться. Но его массив Items[] доступен только на чтение. Посему повлиять на его порядок мы тоже не можем.

Пока что единственный выход, который я нашел - подключать к проекту копию исходника "FMX.Forms3D.pas" и корректировать его под свои нужды. (Под Mac OS X такой финт не работает - берется стандартный "FMX.Forms3D.pas")

А ведь достаточно было бы сделать RebuildRenderingList виртуальной и хотя-бы в protected секции.

Ну а лучше, думаю, было бы кустомизировать TRenderingCompare класс.

Может кто знает лучший вариант?

Изменено пользователем SerhioUser
Rusland понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!


Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.


Войти сейчас

  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу