Предотвратить муаровый узор в пикси. js - PullRequest
0 голосов
/ 05 августа 2020

Я пытаюсь создать масштабируемый холст с прямоугольниками, расположенными в сетке, используя pixi. js. Все работает плавно, за исключением того, что сетка создает сильный муар. Мои знания о pixi js и webgl очень поверхностны, но я подозреваю, что что-то со сглаживанием работает не так, как я ожидал. Я рисую прямоугольники с помощью текстуры 2048x2048 пикселей, которую создаю заранее на отдельном холсте. Я делаю его таким большим, поэтому я могу увеличить его полностью, сохраняя четкий прямоугольник. Я также пробовал использовать app.renderer.generateTexture(graphics), но получил аналогичный результат.

Черные прямоугольники нарисованы с использованием pixi. js, а красные нарисованы с использованием SVG в качестве ссылки. В SVG все еще присутствует муар, но его гораздо меньше. Есть идеи, как я могу приблизиться к тому, как выглядит версия SVG? Вы можете найти рабочую версию здесь .

pixi. js прямоугольники слева черным цветом, прямоугольники svg в качестве справки красным справа

Вот соответствующий код, который я использую для настройки pixi. js приложение:

// PIXI SETUP

const app = new Application({
  view: canvasRef,
  width,
  height,
  transparent: true,
  antialias: false,
  autoDensity: true,
  resolution: devicePixelRatio,
  resizeTo: window
});

const particleContainer = new ParticleContainer(2500, {
  scale: true,
  position: true,
  rotation: true,
  uvs: true,
  alpha: true
});

app.stage.addChild(particleContainer);

// TEXTURE

const size = 2048;
const canvas = document.createElement("canvas");
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, size, size);
ctx.fill();
const texture = PIXI.Texture.from(canvas);

// RECTANGLE GRID

const size = 10;
for(let i=0; i<2500; i++) {
  const particle = Sprite.from(texture);
  particle.x = i % 50 * size * 1.5;
  particle.y = Math.floor(i / 50) * size * 1.5;
  particle.anchor.set(0);
  particle.width = size;
  particle.height = size;
  parent.addChild(particle);
}

1 Ответ

1 голос
/ 06 августа 2020

Не отображать детали субпикселей.

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

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

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

Сетка определяется как повторяющиеся двумерные узоры для уменьшения накладных расходов на рендеринг .

Также я считаю, что линии сетки более проблематичны c, чем квадраты сетки (в демо есть оба)

Это очень простой c и может быть адаптирован к любому типу макета сетки.

requestAnimationFrame(mainLoop);
const ctx = canvas.getContext("2d");
const size = 138;
const grids = createPatterns(size, 4, "#222", "#EEE", "#69B", "#246");
var zoom = 1;
var zoomTarget = 16;
var zoomC = 0;
var gridType = 0;
var origin = {x: ctx.canvas.width / 2, y: ctx.canvas.height / 2};
const scales = [0,0,0];

function createPatterns(size, lineWidth, color1, color2, color3, color4){
    function grid(col1, col2) {
        ctx.fillStyle = col1;
        ctx.fillRect(0, 0, size, size);
        ctx.fillStyle = col2;
        ctx.fillRect(0, 0, size, lineWidth);
        ctx.fillRect(0, 0, lineWidth, size);
    }
    function grid2(col1, col2) {
        ctx.fillStyle = col1;
        ctx.fillRect(0, 0, size, size);
        ctx.fillStyle = col2;
        ctx.fillRect(0, 0, size / 2, size / 2);
        ctx.fillRect( size / 2, size / 2, size / 2, size / 2);

    }
    const patterns = [];
    const ctx = Object.assign(document.createElement("canvas"), {width: size, height: size}).getContext("2d");
    grid(color1, color2)
    patterns[0] =  ctx.createPattern(ctx.canvas, "repeat");
    grid2(color3, color4)
    patterns[1] =  ctx.createPattern(ctx.canvas, "repeat");
    return patterns;
}


function drawGrid(ctx, grid,  zoom, origin, smooth = true) {
    function zoomAlpha(logScale) {
        const t = logScale % 3;
        return  t < 1 ? t % 1 : t > 2 ? 1 - (t - 2) % 1 : 1;
    }
    function fillScale(scale) {
        ctx.setTransform(scale / 8, 0, 0, scale / 8, origin.x, origin.y);
        ctx.globalAlpha = zoomAlpha(Math.log2(scale));
        ctx.fill();
    }
    ctx.fillStyle = grid;
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.imageSmoothingEnabled = smooth;
    ctx.beginPath();
    ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);    
    ctx.globalAlpha = 1;
    const l2 = Math.log2(zoom);
    
    scales[0] = 2 ** ((l2 + 122) % 3); //  zoom limit 1 / (2 ** 122) (well beyond number precision)
    scales[1] = 2 ** ((l2 + 123) % 3); 
    scales[2] = 2 ** ((l2 + 124) % 3);    
    scales.sort((a,b) => a - b);
    
    fillScale(scales[0]);
    fillScale(scales[1]);
    fillScale(scales[2]);
    ctx.globalAlpha = 1;
}

function mainLoop() {
    if (innerWidth !== ctx.canvas.width || innerHeight !== ctx.canvas.height) {
        origin.x = (ctx.canvas.width = innerWidth) / 2;
        origin.y = (ctx.canvas.height = innerHeight) / 2;
        zoomTarget = 16;
        zoom = 1;
    }
    zoomC += (zoomTarget - zoom) * 0.3;    
    zoomC *= 0.02;
    zoom += zoomC;
    if (gridType === 0) {
        drawGrid(ctx, grids[0], zoom, origin);
    } else {
        drawGrid(ctx, grids[1], zoom, origin, false);
    }
    requestAnimationFrame(mainLoop);
}
zoomIn.addEventListener("click", () => zoomTarget *= 2);
zoomOut.addEventListener("click", () => zoomTarget *= 1/2);
toggle.addEventListener("click", () => gridType = (gridType + 1) % 2);
* { margin: 0px;}
canvas { position: absolute; top: 0px;left: 0px; }
.UI { position: absolute; top: 14px; left: 14px; }
<canvas id="canvas"></canvas>
<div class="UI">
<button id="zoomIn">Zoom In</button><button id="zoomOut">Zoom Out</button><button id="toggle">Toggle grid type</button>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...