PixiJS only draws a certain amount of rectangles?

寵の児 提交于 2021-02-05 11:49:59

问题


I want to draw a grid dynamically (based on the user definied size) with Pixi.js. My code is pretty straightforward:

let app, graphics;

const cellSize = 10;

initBoard();
updateGridAlgorithm(false, true, 53);   //does work for values < 53

function initBoard() {
    const width = window.innerWidth;
    const height = window.innerHeight;

    app = new PIXI.Application({
        width: width,
        height: 900,
        backgroundColor: 0xffffff,
        resolution: window.devicePixelRatio || 1,
        autoResize: true,
        antialias: true
    });

    document.body.appendChild(app.view);
    graphics = new PIXI.Graphics();

    app.stage.addChild(graphics);
}

function updateGridAlgorithm(randomStart, showGrid, iterations){
    graphics.clear();
    if(showGrid){
        drawNewGrid(iterations);
    }
}

function drawNewGrid(iterations){
    const width = window.innerWidth;
    const gridWidth = iterations * 2 + 1;
    const startX = width/2 - gridWidth/2 * cellSize;
    const startY = 20;

    for (let i = 0; i < iterations; i++) {
        for (let j = 0; j < gridWidth; j++) {
            graphics.lineStyle(0.5, 0x999999);
            graphics.drawRect(startX+j*cellSize, startY+i*cellSize, cellSize, cellSize);
        }
    }
}

This code works for values smaller than 53 (see comment in code). For values higher than that, there seems to be a constant limit of how many rectangles can be drawn (~5461). In order to visualize that, test with a larger number.

I also made a JSFiddle for you to play around (advice: use Tabs (rows) editor layout for best results...).

Detailed explanation of the Problem

For values below 53 (e.g. 52 iterations) I get the correct result, which looks like that: Notice the number of rects is 52*(52*2+1) = 5460 which is smaller than 5461 (difference of 1 seems pure coincidence).

For values greater or equal 53, some rectangles at the end of the grid are not drawn. The missing rectangles are marked red in the following picture: According to my analysis below, there should be 53*(53*2+1)-5461=210 rectangles missing.

There seems to be a constant maximum of how many rectangles are drawn at most. I will try to roughly calculate that using 194 iterations: So the number of rectangles drawn is 14 * (194*2+1) + 15 = 5461 wich I suspect is the maximum number of rectangles that can be drawn.

This same number can be obtained for other iteration counts like for example 209: 13 * (209 * 2 + 1) + 14.

Concrete Question

I would like to know, why the above described problem occurs and how I can fix it (e.g. draw the full grid for more than 52 iterations)?


回答1:


For me your code works for values greater than 53. For 1000 it doesnt work indeed. To understand why please try running following version of your drawNewGrid function:


function drawNewGrid(iterations){
    const width = window.innerWidth;
    const gridWidth = iterations * 2 + 1;
    const startX = width/2 - gridWidth/2 * cellSize;
    const startY = 20;

    var countAllRectangles = 0;

    for (let i = 0; i < iterations; i++) {
        for (let j = 0; j < gridWidth; j++) {
            graphics.lineStyle(0.5, 0x991111);
            graphics.drawRect(startX+j*cellSize, startY+i*cellSize, cellSize, cellSize);

            countAllRectangles++;
        }
    }

    console.log(countAllRectangles);
}

Run it and observe the Devtools console in browser. When the iterations is 500 then it prints: 500500. Also please take a look at "Memory" tab in Chrome Devtools:

  • when iterations is 100 then countAllRectangles is 20100 and i see around 25 MB memory usage.
  • when iterations is 200 then countAllRectangles is 80200 and i see around 90 MB memory usage.
  • when iterations is 300 then countAllRectangles is 180300 and i see around 200 MB memory usage.
  • when iterations is 400 then countAllRectangles is 320400 and i see around 370 MB memory usage.
  • when iterations is 500 then countAllRectangles is 500500 and i see around 570 MB memory usage.
  • when iterations is 600 then countAllRectangles is 720600 and i see around 840 MB memory usage etc.

Memory usage is increasing quadratically along with iterations value. It's because of the for loop nested inside other for loop in function drawNewGrid.

This means that for iterations of 1000 it will take around 2 GB of memory and will draw around 2 millions rectangles - which is probably too much for our browsers and pixi.js to handle :)

Update 2020-03-15:

@frankenapps: Are you sure, the code worked correct for values bigger than 52? I have updated my question with a detailed explanation of my problem...

Ok - now i see more clearly what you had in mind. It seems that there is indeed a limit: number of primitives of one "PIXI.Graphics" object. Please read here:

  • https://www.html5gamedevs.com/topic/12242-a-limitation-on-the-number-of-graphics-primitives/
  • https://github.com/pixijs/pixi.js/issues/5707#issuecomment-494722310

Solution to this problem is to draw more smaller rectangles instead of one PIXI.Graphics object with many rectangles inside. Please check new version of JSFiddle with iterations = 100:

  • I changed creation of PIXI.Application so it has width and height depending on iterations so we will see all rectangles that are drawn:
    let canvasWidth = (iterations * 2 + 4) * cellSize;
    let canvasHeight = (iterations + 4) * cellSize;

...

    app = new PIXI.Application({
        width: canvasWidth,
        height: canvasHeight,
  • also please notice what is happening in updateGridAlgorithm function - gridContainer is removed from stage and new instance of it is created (if there was something else in gridContainer before then it will be garbage collected to free memory).
  • and please see drawNewGrid function - inside the nested for loops new rectangle is being drawn on each step - and then is added to gridContainer:
      let rectangle = new PIXI.Graphics();
      rectangle.lineStyle(0.5, 0x999999);
      rectangle.beginFill(0xFF << (i % 24)); // draw each row of rectangles in different color :)
      rectangle.drawRect(startX+j*cellSize, startY+i*cellSize, cellSize, cellSize);
      rectangle.endFill();

      gridContainer.addChild(rectangle);
  • i also renamed some variables

https://jsfiddle.net/bmxfoh1r/1/




回答2:


There does seam to be a limit to the number of items that can be added to the graphics object.

How to solve the problem?

I am not familiar with Pixi.js and the documentation for PIXI.Graphics provided no easy solution.

Some quick solutions that will (or may) work but will depend on how you intend to use the grid.

  1. (Maybe but best option if possible) Create a graphic with only one square (drop the bottom and right edges), convert it to a bitmap and then draw that bitmap over the area you want the grid using repeat (As you would do using CanvasRenderingContext2D.createPattern. How you would do this in Pixi I do not know as a search for "repeat" found nothing of use in the documentation

  2. Rather than render rectangles, render lines. This means you only need to add iterations + gridWidth + 2 lines rather than (iterations * (gridWidth + 1) which is a huge saving of resources. (see example code below)

  3. (Hacky method) Use as many graphics object as needed to hold the squares. IE if you can only add 5460 rectangles and want to add 15000 you will need to create Math.ceil(15000 / 5460) graphics objects. Use a counter to track the number you add to each graphic and switch when each is full.

Example using poly lines

const maxLines = Math.max(iterations, gridWidth);
const right = startX + gridWidth * cellSize;
const bottom = startY + iterations * cellSize;

graphics.startPoly();
var i = 0;
while (i <= maxLines) {
    if (i <= gridWidth) {
       graphicxs.moveTo(startX + i * cellSize, startY);
       graphicxs.lineTo(startX + i * cellSize, bottom);
    }
    if (i <= iterations) {
       graphicxs.moveTo(startX, startY + i * cellSize, startY);
       graphicxs.lineTo(right,  startY + i * cellSize, startY)
    }
    i++;
}
graphics.finishPoly();


来源:https://stackoverflow.com/questions/60685991/pixijs-only-draws-a-certain-amount-of-rectangles

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!