Перейти к содержанию
Fire Monkey от А до Я

HoShiMin

Пользователи
  • Постов

    16
  • Зарегистрирован

  • Посещение

Весь контент HoShiMin

  1. HoShiMin

    TPlane и Альфа-канал

    Delphi 10.1 Berlin Update 1 На форме два TPlane'a, один позади другого. На каждый накладываются текстурки из png с альфа-каналом (TTextureMaterialSource). Если привязывать MaterialSource'ы в дизайн-тайме (кидать для каждого TPlane'a на форму свой TTextureMaterialSource), альфа-канал обрабатывается корректно (в прозрачных участках видно, что находится "позади" TPlane'a). Если создавать TTextureMaterialSource и привязывать в рантайме, то при при повороте TPlane'ов прозрачность исчезает, и всё, что позади переднего TPlane'а, перестаёт рендериться. Привязываю так: procedure TForm1.FormCreate(Sender: TObject); var MS1, MS2: TTextureMaterialSource; begin MS1 := TTextureMaterialSource.Create(Plane1); MS2 := TTextureMaterialSource.Create(Plane2); MS1.Parent := Form1; MS2.Parent := Form1; Plane1.MaterialSource := MS1; Plane2.MaterialSource := MS2; MS1.Texture.LoadFromFile('C:\Users\Администратор\Pictures\TestTransparentTexture.png'); MS2.Texture.LoadFromFile('C:\Users\Администратор\Pictures\TestFilledTexture.png'); end; И результат - задняя красная панелька не рендерится за большой передней: То же самое, но с TTextureMaterialSource'ами, привязанными в дизайн-тайме через визуальные компоненты (как должно быть): Как это исправить? TPlane'ов будет много, на каждую панельку кидать свой компонент материала - не вариант. Проект в аттаче TransparentPlane.zip
  2. Загружаю в Bitmap значок 16х16, должно получиться что-то вроде такого: А получается так: Помогает только изменение размеров холста в фотошопе. В ХЕ8 всё работало как надо, в 10 - вот. Хотел отредактировать стиль, убрав Stretch у картинки, но у всплывающего меню нельзя отредактировать стиль. Как поправить, не меняя размеры самих картинок значков?
  3. По сети программа получает картинку в png (грузится в TMemoryStream), оттуда загружается во временный TBitmap, из которого потом грузится в TImage на форме. И в промежуточном Bitmap'е она время от времени бьётся: не отрисовывается на форме, а при сохранении получаю лишь несколько первых байт оригинальной картинки, которая в целости и сохранности лежит в TMemoryStream. Метод LoadFromStream в TBitmap'е как раз реализован через BitmapCodecManager, поэтому "ручная" конвертация проблему не решит, ибо получится то же самое. Меня больше смущает то, что бьётся не всегда, а довольно редко. При этом другие потоки не пытаются получить доступ к промежуточному битмапу, скопировать картинку никто не мешает. С TResourceStream то же самое. Иногда не грузится из него картинка. И если с ним можно замаскировать проблему, закинув картинки в Deployment, то с TMemoryStream так не получится, т.к. картинки приходят по сети.
  4. Один поток, один и тот же ресурс, и под Win32, и под Win64. И ещё раз уточню - это происходит не всегда, а достаточно редко. Причём проблема именно с заполнением битмапа из TStream'a (из любого), а не именно с TResourceStream.
  5. Картинки в пределах 50 Кб, с hInstance'ом всё нормально. В большинстве случаев всё грузится нормально, но иногда копируется только пара сотен первых байт оригинала.
  6. Загружаю картинку в TBitmap из TMemoryStream, но иногда в TBitmap копируется только часть картинки. Загружаю следующим кодом: var ResourceStream: TResourceStream; Bitmap: TBitmap; begin ResourceStream := TResourceStream.Create(hInstance, 'IMAGE_NAME', RT_RCDATA); ResourceStream.Position := 0; Bitmap.LoadFromStream(ResourceStream); ResourceStream.SaveToFile('img_res.png'); Bitmap.SaveToFile('img_bitmap.png'); FreeAndNil(ResourceStream); end; В итоге в img_res.png нормальное изображение, а в img_bitmap.png первые N байт оригинала, при одинаковом размере картинки N одинаковое. С TMemoryStream аналогично. Как исправить?
  7. Так и есть, ничего это не решило. Теперь отсекается задняя поверхность. Вот где здесь найти логику?
  8. Так и есть) Пробовал уже пробежаться по коду FMX, но ничего это не дало, что, в общем-то, неудивительно) Но вот что интересно - для каждого TPlane'a в OnRender добавил Application.ProcessMessages (ни из каких соображений это не следовало, просто на авось) и отчасти помогло. Плоскости уже не отсекаются, но и текстурки под шлемом не прорисовываются, а заливаются почему-то чёрным до первого взаимодействия с моделью (стоит её ухватить мышью и чуть-чуть подвинуть - всё прорисовывается). Но надолго ли? Я даже не знаю, почему обработка очереди сообщений помогла, а Repaint'ы и Invalidate'ы - нет. Может, это иллюзия починки, ведь в первом посте я выяснил, что рендеринг может починить совершенно любой код, вставленный в совершенно произвольное место (и он же может его сломать).
  9. неужели так трудно прогнать в отладчике программу и пошагово выяснить почему не прорисовываются определенные плоскости? исходники FMX есть. Действительно, пошагово пробежаться по тысячам строчек с неизвестным принципом работы и исправить рендеринг - это же так просто.
  10. Ну так что? Больше никто с такой проблемой не сталкивался?
  11. Лаунчер для одной очень известной игры. Это такая функциональная запускалка с проверкой игрового клиента, выбором сервера, настройкой внешнего вида игрока (для визуализации и нужна моделька) и мощной низкоуровневой антиотладочной защитой и защитой от редакторов памяти. Подробнее здесь. И всё было бы здорово, если бы не досадное отсечение плоскостей у головы, которое я никак не могу победить. Здесь уже нужна помощь разработчиков FMX...
  12. Это-то как раз понятно, вопрос немного в другом: необходимо ли предотвращать перерисовку на время, скажем, загрузки битмапа или в похожих случаях. Именно чтобы избежать артефактов. И если я выставлю BeginUpdate для TImage, внутри которого лежит ещё куча объектов, они тоже не будут перерисовываться, пока к компоненту-родителю не будет применён EndUpdate, или нужно их блокировать отдельно? И какой вообще принцип работы с ними? Например, будет ли назначена объекту принудительная перерисовка после EndUpdate, или нужно вызывать Repaint. Ну а в плане багов, кроме этого (и невозможности комбинировать эффекты, типа размытия, с другими) пока что всё идёт хорошо, верстать формы - одно удовольствие, от обилия эффектов радуется душа, хочется попробовать всё и сразу, да и с производительностью всё обстоит в целом неплохо. Попробовал всю свою форму закинуть в ещё один Viewport3D, чтобы сделать эффект изменения перспективы, как в главном меню Crysis 2, когда двигаешь мышью и немного поворачивается перспектива, но для таких нагрузок, видимо, FMX не предназначен - крутиться моделька стала с подтормаживаниями (возможно, полноценный перенос в 3D решит проблему, но в HD приложении так, от эффекта этакого "параллакса" пока пришлось отказаться).
  13. Уже создавал тему по этому вопросу, надеялся, что в ХЕ8 рендеринг исправят, но нет. Кроме того, проблема обросла подробностями. Итак, та же моделька того же человечка в шлеме, собрана на TPlane'ах, код текстурирования тот же, всё так же не рендерится голова внутри. В тот раз проблема решилась случайно и я сам не понял, что же именно привело к решению. С тех пор форму старался не трогать, но рано или поздно дошёл и до неё черёд. И как результат, та же проблема - уже в ХЕ8. Подробнее о том, как организована модель: Viewport3D, внутри него лежит TDummy, в котором собрана TPlane'ами модель, а также камера, которая на это безобразие смотрит: Теперь непосредственно к проблеме: Смотрим на скрин: По вайрфреймам можно понять, что боковые плоскости головы не рендерятся вообще (а не пропадает текстурка, как я полагал раньше). Интересно, а что "внутри" шлема? Чтобы узнать, сделал возможность в рантайме, не закрывая программу, "снять" шлем (Visible для всех граней в False). Смотрим: Оп! Все грани на месте, всё отлично прорендерилось! А если снова "надеть" шлем? Нет, надевание шлема привело всё к той же грустной картине на первом скрине - боковые плоскости просто отсеклись и упрямо не хотят рендериться... Следующим шагом попробуем уменьшить прозрачность одной из плоскостей шлема и посмотреть сквозь неё на отсечённую плоскость головы: Так точно, и полупрозрачность не заставляет включаться рендеринг "внутренних" граней. А что будет, если поменять разрядность платформы? Выставим Win64/Debug и - о чудо! - рендеринг внезапно заработал! И под конец экспериментов всплыл не такой страшный, но всё же назойливый баг, из-за которого иногда не прорисовываются те или иные графические элементы: к примеру, здесь не прорисовались текстуры модельки, иногда не прорисовываются некоторые превьюшки списка серверов, но это лечится обновлением битмапа. Итак, что же мы узнали из этих исследований? Ровным счётом ничего. Рендеринг или, наоборот, нерендеринг не имеют никаких закономерностей. Какими способами удалось повлиять на прорисовку этих поверхностей: 1) Изменение целевой платформы (Win32/Win64/Debug/Release) дают разный результат - практически всегда из четырёх комбинаций есть удачная, где всё рендерится 2) Изменение формы - добавление новых элементов или удаление существующих, помогает не всегда. На рабочей конфигурации может наоборот привести к отсечению граней 3) Изменение кода. ЛЮБОЕ. Даже никак не связанное с рендерингом. Достаточно воткнуть в произвольное место что-то типа Inc(Variable), чтобы рендеринг починился. Этого же, впрочем, достаточно и для того, чтобы рендеринг сломался. Что НИКАК не влияет на рендеринг: А не влияет всё то, что должно было бы повлиять, а именно: 1) Расстановка в любых мыслимых и немыслимых местах BeginUpdate'ов и EndUpdate'ов 2) Repaint'ы и Invalidate'ы всего и вся 3) Обновление текстур (грубо говоря, заливка модели новой текстурой) 4) Использование StyleBook'a Исходя из вайрфреймов, нарисованных на каждой плоскости, мы видим, что не прорисовываются сами TPlane'ы. Могу предположить, что движок считает их невидимыми и отсекает как ненужные для оптимизации, но почему, в таком случае, рендерятся передняя и задняя плоскости головы? Итак, вопрос - классика: кто виноват и что делать. Баг ли это в движке FMX, или же всё учтено и достаточно задать волшебную опцию, которая разом всё починит - я так и не узнал. Приветствуется любая помощь, а также хотелось бы раз и навсегда закрыть вопрос: в каких случаях нужно делать BeginUpdate/EndUpdate и влияет ли он на обработку отрисовки унаследованных объектов.
  14. Есть моделька человека, собранная из TPlane'ов, на голове - шлем, на шлем накладывается текстура с прозрачными пикселями. Модельку можно вращать. Если подключить StyleBook, то голова перестаёт прорисовываться сквозь прозрачные пиксели при вращении. Запустили приложение, голова прорисована: Поворачиваем - голова мгновенно "стирается": Отключаем StyleBook - крутим модельку, всё хорошо: Как исправить рендеринг сквозь прозрачные пиксели? P.S.: Если в StyleBook'e поставить галочку на UseStyleManager, то снова всё отрисовывается нормально, но использовать StyleManager очень неудобно. Код текстурирования // Скопировать часть битмапа в другой битмап: procedure CopyBitmapToBitmap( const SrcBitmap : FMX.Graphics.TBitmap; // Из какого битмапа копируем const DestBitmap : FMX.Graphics.TBitmap; // В какой битмап копируем const SrcRect : TRectF; // Какой прямоугольник const DstRect : TRectF; // В какой прямоугольник ScaleCoeff : Single = 1.0; // Коэффициент масштабирования (DstRect * ScaleCoeff) Opacity : Single = 1.0; // Коэффициент прозрачности накладываемого изображения FlushBeforeDrawing : Boolean = True; // Очищать ли предыдущее содержимое Interpolate : Boolean = False // Интерполировать ли при масштабировании ); function Max(const A, B: Single): Single; inline; begin if A > B then Result := A else Result := B; end; begin if FlushBeforeDrawing then DestBitmap.Clear($00000000); DestBitmap.SetSize(Round(Max(DstRect.Left, DstRect.Right) * ScaleCoeff), Round(Max(DstRect.Top, DstRect.Bottom) * ScaleCoeff)); DestBitmap.Canvas.BeginScene; DestBitmap.Canvas.DrawBitmap( SrcBitmap, SrcRect, RectF( DstRect.Left, DstRect.Top, DstRect.Left + ((DstRect.Right - DstRect.Left) * ScaleCoeff), DstRect.Top + ((DstRect.Bottom - DstRect.Top) * ScaleCoeff) ), Opacity, not Interpolate ); DestBitmap.Canvas.EndScene; end; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - procedure TMainForm.DrawSkin(FileStream: TMemoryStream); type TTextureInfo = array of Integer; // OffsetX, OffsetY, Width, Height TCubeTexture = array of TTextureInfo; // Front, Back, Left, Right, Top, Bottom TSurfaceArray = array of ^TPlane; // Индексы элементов в массивах: const iOffsetX = 0; iOffsetY = 1; iWidth = 2; iHeight = 3; iFront = 0; iBack = 1; iLeft = 2; iRight = 3; iTop = 4; iBottom = 5; iHead = 0; iTorso = 1; iLeftArm = 2; iRightArm = 3; iLeftLeg = 4; iRightLeg = 5; iHelmet = 6; const HeadTexture : TCubeTexture = [// X Y W H [8 , 8, 8, 8], // Front [24, 8, 8, 8], // Back [0 , 8, 8, 8], // Left [16, 8, 8, 8], // Right [8 , 0, 8, 8], // Top [16, 0, 8, 8] // Bottom ]; ... { здесь пропущен список координат для каждой текстуры из битмапа } ... const ScaleCoeff: Single = 16.0; var Bitmap: FMX.Graphics.TBitmap; // Список поверхностей каждой части модели: HeadPlanes : TSurfaceArray; TorsoPlanes : TSurfaceArray; LeftArmPlanes : TSurfaceArray; RightArmPlanes : TSurfaceArray; LeftLegPlanes : TSurfaceArray; RightLegPlanes : TSurfaceArray; HelmetPlanes : TSurfaceArray; // Список частей модели: ModelParts: array of ^TSurfaceArray; // Список текстур каждой части модели: ObjectTextures: array of ^TCubeTexture; // I - счётчик по частям модели, J - счётчик по поверхностям: I, J: LongWord; begin // Загружаем битмап из PNG-файла: Bitmap := FMX.Graphics.TBitmap.Create; Bitmap.LoadFromStream(FileStream); // Составляем массив из групп текстур для каждой части модели: ObjectTextures := [@HeadTexture, @TorsoTexture, @LeftArmTexture, @RightArmTexture, @LeftLegTexture, @RightLegTexture, @HelmetTexture]; // Составляем список поверхностей: HeadPlanes := [@HeadFront , @HeadBack , @HeadLeft , @HeadRight , @HeadTop , @HeadBottom ]; TorsoPlanes := [@TorsoFront , @TorsoBack , @TorsoLeft , @TorsoRight , @TorsoTop , @TorsoBottom ]; LeftArmPlanes := [@LeftArmFront , @LeftArmBack , @LeftArmLeft , @LeftArmRight , @LeftArmTop , @LeftArmBottom ]; RightArmPlanes := [@RightArmFront, @RightArmBack, @RightArmLeft, @RightArmRight, @RightArmTop, @RightArmBottom]; LeftLegPlanes := [@LeftLegFront , @LeftLegBack , @LeftLegLeft , @LeftLegRight , @LeftLegTop , @LeftLegBottom ]; RightLegPlanes := [@RightLegFront, @RightLegBack, @RightLegLeft, @RightLegRight, @RightLegTop, @RightLegBottom]; HelmetPlanes := [@HelmetFront , @HelmetBack , @HelmetLeft , @HelmetRight , @HelmetTop , @HelmetBottom ]; // Составляем список частей модели: ModelParts := [@HeadPlanes, @TorsoPlanes, @LeftArmPlanes, @RightArmPlanes, @LeftLegPlanes, @RightLegPlanes, @HelmetPlanes]; // Проходимся по каждой части модели (голова, корпус, ...): for I := 0 to High(ModelParts) do begin // Проходимся по каждой поверхности модели: for J := 0 to High(ModelParts[I]^) do begin // Рисуем текстуру на каждой поверхности: with (ModelParts[I]^)[J]^ do begin CopyBitmapToBitmap( Bitmap, TTextureMaterialSource(MaterialSource).Texture, RectF( (ObjectTextures[I]^)[J][iOffsetX], (ObjectTextures[I]^)[J][iOffsetY], (ObjectTextures[I]^)[J][iOffsetX] + (ObjectTextures[I]^)[J][iWidth], (ObjectTextures[I]^)[J][iOffsetY] + (ObjectTextures[I]^)[J][iHeight] ), RectF(0, 0, (ObjectTextures[I]^)[J][iWidth], (ObjectTextures[I]^)[J][iHeight]), ScaleCoeff ); // Инвертируем текстуры для симметрии: if I in [iLeftArm, iLeftLeg] then TTextureMaterialSource(MaterialSource).Texture.FlipHorizontal; end; end; end; FreeAndNil(Bitmap); end;
  15. Нашёл более удобный для себя компонент - TRectangle3D. Как раз позволяет текстурировать 2 грани отдельно, а остальные - длинной "опоясывающей" текстурой. Чтобы не писать рендеринг вручную, взял именно его. И с ним проблема: текстура не растягивается по длине в поверхность. Получается что-то вроде этого: Длинной зелёной заливки быть не должно, справа вывел рабочую текстуру из того же битмапа - проблема не в ней. Если поиграть с геометрическими размерами кубика, то можно подогнать текстуру вровень, но нельзя ли сделать автоматическое растягивание под размер? Конкретно в этом примере с текстурой 256х64 при размерах кубика 0.83х0.83х0.83 всё совпадает пиксель в пиксель (0.83 подобран экспериментально), но умножая 0.83 на какой-нибудь коэффициент, снова подогнать текстуру под размер не выходит. И ещё один вопрос: нельзя ли выключить интерполяцию при растягивании на 3D, как это можно сделать в TImage флагом DisableInterpolation?
  16. Есть моделька, собранная из нескольких TCube'ов, как наложить на каждую грань каждого куба свою собственную текстуру?
×
×
  • Создать...