#javascript #webgl #pixi.js
Вопрос:
Я использую плагин WebGL pixi-overlay для листовки https://github.com/manubb/Leaflet.ИнкрУстация пикси. Существуют маркеры, которые имеют анимационный эффект при перемещении карты листовки, и они отображаются с помощью средства визуализации WebGL. Я оптимизировал анимацию WebGL, но все равно иногда выпадали кадры. Я полагаю, это потому, что рендеринг анимации листовок пересекается с рендерингом WebGL. Я обнаружил, что в Листовке используются CSS-переходы. Я хотел бы знать, как повысить производительность, чтобы избежать пропущенных кадров.
animation.js:
container,
flags,
timestamp,
delta,
targetScale,
currentScale
) {
var time = flags.scalingTime;
var progress = timestamp - time;
var lambda = progress / delta;
if (lambda > 1) lambda = 1;
lambda = lambda * (0.4 lambda * (2.2 lambda * -1.6));
for (var markerSprite of container.children) {
markerSprite.scale.set(
currentScale lambda * (targetScale - currentScale)
);
}
if (progress >= delta) {
flags.scaling = false;
}
}
function transformFading(container, flags, timestamp, delta, coef = 1) {
var fadeMarkers, time;
if (coef > 0) {
fadeMarkers = flags.fadeInMarkers;
time = flags.fadingInTime;
} else {
fadeMarkers = flags.fadeOutMarkers;
time = flags.fadingOutTime;
}
var progress = timestamp - time;
var lambda = progress / delta;
if (lambda > 1) lambda = 1;
lambda = lambda * (0.4 lambda * (2.2 lambda * -1.6));
for (var markerSprite of fadeMarkers) {
markerSprite.alpha = coef > 0 ? lambda : 1 - lambda;
}
if (progress >= delta) {
if (coef < 0) {
flags.fadingOut = false;
container.removeChild(...fadeMarkers);
} else flags.fadingIn = false;
}
}
export function animate(
flags,
timestamp,
container,
renderer,
delta,
targetScale = null,
currentScale = null
) {
if (flags.scaling)
transformScaling(
container,
flags,
timestamp,
delta,
targetScale,
currentScale
);
if (flags.fadingIn) transformFading(container, flags, timestamp, delta, 1);
if (flags.fadingOut) transformFading(container, flags, timestamp, delta, -1);
renderer.render(container);
if (flags.scaling || flags.fadingIn || flags.fadingOut) {
var frame = requestAnimationFrame(() =>
animate(
flags,
Date.now(),
container,
renderer,
delta,
targetScale,
currentScale
)
);
} else {
cancelAnimationFrame(frame);
flags.animateRunning = false;
}
}
основной цикл: (для простоты был удален некоторый код)
export function preloadApp(map) {
var loader = new PIXI.Loader();
loadTextures(loader);
loader.load(function (loader, resources) {
var container = new PIXI.Container();
var prevZoom
var renderer, project;
var pointToCoords = {};
var sentCount = 0;
var firstDraw = true;
var flags = {
scaling: false,
fadingIn: false,
fadingOut: false,
animateRunning: false,
};
var delta = 200;
var pixiOverlay = L.pixiOverlay(function (utils) { // calls each time when map position updates
if (typeof renderer === "undefined") {
renderer = utils.getRenderer();
}
var zoom = map.getZoom();
//...
sentCount = 1; // count moving
sendRequest("GET", `http://localhost:5000/api/markers/${requestString}`)
.then((mapObjects) => {
setTimeout(() => { // Imitation timeout
// if position was changed multiiple times we should work with the last one
if (sentCount > 1) {
sentCount -= 1;
return;
}
var scale = utils.getScale();
project = utils.latLngToLayerPoint; // projection
pointToCoords.cur = utils.layerPointToLatLng;
var fadeOutMarkers = [
...container.children.filter(
//[rule]
),
];
flags.fadingOut = true;
flags.fadingOutTime = Date.now();
flags.fadeOutMarkers = fadeOutMarkers;
if (!flags.animateRunning) {
animate(
flags,
timestamp,
container,
renderer,
delta,
targetScale,
currentScale
);
flags.animateRunning = true;
}
// оставляем в контейнере только те элементы, которые совпадают с теми, что пришли с сервера
var clusterPoints = mapObjects;
var fadeInMarkers = [];
for (let /*!*/ coordinate in clusterPoints) {
let objectCoords = clusterPoints[coordinate].coords; // координаты в виде массива
var options = {
objectCoords,
project,
scale,
map,
container,
renderer,
clusterPoints,
mapObjects,
pointToCoords,
};
var newMarker = createMarker(options);
newMarker.alpha = 0;
fadeInMarkers.push(newMarker);
container.addChild(newMarker);
}
prevZoom = zoom;
flags.fadingIn = true;
flags.fadeInMarkers = fadeInMarkers;
flags.fadingInTime = Date.now();
if (!flags.animateRunning) {
animate(
flags,
timestamp,
container,
renderer,
delta,
targetScale,
currentScale
);
flags.animateRunning = true;
}
sentCount -= 1;
}, 0);
})
.catch((err) => {
alert(err);
});
// Rescaling
if (zoom !== prevZoom amp;amp; !firstDraw) {
var scale = utils.getScale();
var targetScale = 1 / scale / 4;
var currentScale = container.children[0].transform.scale.x;
var timestamp = Date.now();
flags.scaling = true;
flags.scalingTime = timestamp;
if (!flags.animateRunning) {
animate(
flags,
timestamp,
container,
renderer,
delta,
targetScale,
currentScale
);
flags.animateRunning = true;
}
}
prevZoom = zoom;
firstDraw = false;
// if(!flags.animateRunning) ???
renderer.render(container);
}, pixiContainer);
pixiOverlay.addTo(map);
});
}
Комментарии:
1. листовка определенно не является картографической библиотекой на основе WebGL. Вы не можете попросить его отрисовывать с помощью webgl. Для этого типа библиотеки посмотрите на mapbox или arcgis js api. Я бы пересмотрел ваш вопрос, чтобы сосредоточиться на том, какая у вас проблема конкретно с тем, как происходит анимация с наложением пикселей.
2. @Сет Луцке, Спасибо. Я обновил свой вопрос