Каков наилучший способ отображения миллионов изображений на Java?

Вы видите это?

Каждый кирпич каждого дома представляет собой изображение размером 16x16 пикселей.

Что вы можете увидеть здесь версию на основе простого JavaFX, а некоторые Imageview переместились на X и Y, чтобы дать эффект "построения".

Я просто адаптирую это значение для Swing с помощью paintComponent.

Проблема: - С JavaFX: у моего компьютера проблемы. То, что вы видите на картинке, заняло 2 секунды, чтобы загрузить, а затем движется очень медленно и рывком. - С Swing: я не знаю, как адаптировать каждый блок в соответствии с яркостью, тенями и т.д. Итак, это выглядит так:

Какой метод выбрать? Оба имеют серьезные недостатки. Мне бы хотелось сохранить метод JavaFX, а также найти что-то еще, кроме Imageview. Это не должно быть хорошей идеей.

2 ответа

Информацию о оптимизации и реализации Swing см. в других ответах, так как мой ответ специфичен для JavaFX.

Если вы придерживаетесь реализации JavaFX, выполните следующие действия:

  • Используйте node.setCache(true) для включения кэширования node.
  • Используйте node.setCacheHint(CacheHint.SPEED), чтобы включить высокоскоростные преобразования node.
  • Предоставить реализацию без эффектов, а другую - с эффектами и посмотреть, будет ли эффект без эффектов работать заметно лучше. (Если в этом случае вам может понадобиться использовать более эффективную цепочку эффектов или вообще отказаться от некоторых эффектов).
  • Проверьте системные требования JavaFX, чтобы убедиться, что ваша установка соответствует минимальным требованиям к аппаратным ускорениям с точки зрения комбинаций оборудования /os/driver.
  • Если вы используете Регионы и обработку на основе css, будьте осторожны, чтобы система css не вызывала слишком (например, имея версию кода, которая не использует css и сравнивает ее производительность).
  • При необходимости реализуйте уровень детального масштабирования (например, при увеличении изображения для всего дома нужно создать единое изображение, а не отдельное изображение для каждой домашней плитки).
  • Убедитесь, что вы загружаете только один Image один раз и повторно используете его в нескольких ImageViews.
  • Используйте профайлер для определения узких мест.
  • Измените тестовый процессор или графическую карту, чтобы узнать, является ли это узким местом.
  • Попробуйте предварительный просмотр Java 8, в котором реализованы многие внутренние оптимизации производительности для JavaFX.
  • Если вы загружаете большое количество изображений, используйте загрузку фона и перед началом загрузки изображений на экране анимации или выполнения, перед тем как загружать изображения.
  • Если вы загружаете большое количество изображений, масштабируйте их заранее в конструкторе изображений, чтобы они не занимали слишком много памяти или требовали (потенциально) дополнительной обработки мощность для дополнительных пикселей (только на самом деле стоит учитывать, если вы используете много разных текстур с очень высоким разрешением, чего вы, похоже, не делаете).

Например:

Image tile = new Image("tile.png");
Group house = new Group();
house.setCache(true);
house.setCacheHint(CacheHint.SPEED);
Effect lighting = new Lighting();
for (int i = 0; i < houseWidth; i++) {
 // here is the critical part => don't do new ImageView(new Image("tile.png"))
 ImageView tileView = new ImageView(tile));
 tileView.setEffect(lighting);
 tileView.setCache(true);
 tileView.setCacheHint(CacheHint.SPEED);
 house.add(tileView); 
}

Предложения Мантрида интересны. Я верю, что с помощью JavaFX вам не нужно самостоятельно реализовывать алгоритм грязного прямоугольника (поскольку базовая платформа способна заботиться о грязной обработке области для вас). Возможно, потому что это общий механизм, он не обеспечивает уровень оптимизации, необходимый для вашего конкретного случая, и в этом случае вам нужно обрабатывать грязную обработку самостоятельно (например, удаляя узлы из сценария и повторно добавляя при необходимости).

Кроме того, предварительный расчет размытия/яркости/и т.д. на изображениях можно было сделать, определяя эффекты в JavaFX, применяя эффекты к заставке ImageView node, затем принимая моментальный снимок внешнего экрана ImageView node, чтобы получить предварительно рассчитанное изображение. Этот метод позволит вам повторно использовать существующий конвейер эффектов JavaFX без необходимости его повторного внедрения с использованием механизма ConvolveOp. Возможно, вы можете получить тот же уровень производительности, просто установив кеш в true и cacheHint, чтобы ускорить работу с узлами ImageView, так как я полагаю, что это делает подобную вещь за сценой (т.е. Увеличивает скорость за счет увеличения использования памяти).

Сценарий JavaFX довольно эффективен и может обрабатывать тысячи узлов. Однако в вашем приложении может быть больше. Если вышеуказанные точки оптимизации вам не помогут, вы можете рассчитать счетчик node и отправить ссылку на свой вопрос (и, возможно, некоторый источник) на рассылку open-jfx список, где разработчики JavaFX, которые знают детали оптимизации приложений JavaFX,

JavaFX 8 имеет гораздо лучшую поддержку 3D-сценграфовв, чем (в основном бесполезный) 3D-сценарий в JavaFX 2.2. Похоже, что ваше текущее приложение представляет собой psuedo-3d, где вы трансформируете 2D-объекты, индивидуально применяете световые эффекты и настраиваете яркость каждой плитки, чтобы получить 3D-вид. Если это произойдет, использование полностью аппаратно ускоренного 3D-сценария с единой 3D-моделью освещения может оказаться лучше, лучше выглядеть и работать с ним - вам придется оценить его в контексте вашего приложения, чтобы узнать, стоит переключить ваше приложение с 2D-сценария JavaFX на 3D-графику JavaFX или с JavaFX на Swing или на другую технику, например libgdx.

Добавление

Ответы на некоторые дополнительные вопросы Mizur:

Итак, почему они настолько энергоемкие?

Как видно из моего ответа, есть много аспектов, которые входят в производительность, поэтому выделение одной конкретной причины того, почему что-то является энергоемким, иногда сложно и часто невозможно. Иногда это сочетание вещей, которые способствуют проблемам производительности. Самые большие выигрыши обычно исходят от оптимизации материала, выполняемого во внутренних циклах или путем изменения стратегии, используемой для решения проблемы.

Если им так нужно, позвольте мне переместить плитки или просто отобразиться, не?

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

Есть ли способ генерировать изображения каждого здания с помощью этой техники Imageview, а затем интегрировать эти изображения зданий в финальную сцену?

Да - вы можете визуализировать здание на неэкранированной сцене с использованием многих изображений и узлов, снимок экрана вне экрана, чтобы создать одно изображение, а затем наложить это изображение на ваш финальная сцена.


изменение размытия/яркости/и т.д. на изображениях до их рисования

Я не использовал его сам, но здесь намек - используйте механизм Swing/AWT Kernel + ConvolveOp: http://www.java-tips.org/java-se-tips/java.awt.image/styling-digital-images-with-convolveop.html

BufferedImage biSrc = ...
BufferedImage biDest = ...
float[] data = new float[] { 0.0625f, 0.125f, 0.0625f, 0.125f, 0.25f, 0.125f, 0.0625f, 0.125f, 0.0625f };
Kernel kernel = new Kernel(3, 3, data);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
convolve.filter(biSrc, biDest);
Операции

определяются через матрицу 3x3 (данные). вы можете выполнить поиск примеров для brigthness, blur и т.д.

картинке потребовалось 2 секунды для загрузки, но она двигалась очень медленно и рывком после

используйте алгоритм Dirty Rectangles: Dirty Rectangles

licensed under cc by-sa 3.0 with attribution.