Skip to main content

Extreme loading times when positioning/scaling multiple objects in code

Comments

14 comments

  • Bram van Vugt

    Hi Matthijs,

    Greetings! Your post has been approved. Your creation in Fectar is awe-inspiring! I will ask one of our developers to examine your scene and code.

    Bram

    1
  • Dennis

    Hi Matthijs,

    The delay is at it seems caused by the contents of the setInterval function positionLogo, throwing a javascript exception. Our engine should stop the intervals when that happens to prevent situations like these, but seems like it didn't.

    I just took a quick look at your code to what's causing it, and a couple of things caught my attention.

    setTimeout(() => let returnTimer = setInterval(returnLogo,logoInterval));

    should become

    setTimeout(() => setInterval(returnLogo,logoInterval), 1234);

    where 1234 should be a valid timeout time in milliseconds, or discard the entire setTimeout.

    Then 

    let logoTimer = setInterval(positionLogo,logoInterval);

    should become

    var logoTimer = setInterval(positionLogo,logoInterval);

    because when using logoTimer in the positionLogo function you're in function block scope.

     

    I'll take note of the exception handling issue regarding intervals. 

    This should hopefully get you pointed in the right direction. 

     

    0
  • Matthijs Broekhuizen

    Hi Bram and Dennis!

    Thanks Bram for the approval, glad you like what I'm trying to do.

    And Dennis, thank you for your insight. As you might've guessed from my code, I'm not very experienced with javascript. I've made the changes you suggested.

    Unfortunately, it hasn't helped with the loading times. I'm quite confident the delays originate from the 'positionNormal' function, since commenting out the call to that function completely cures the problem (without positioning each element).

    Specifically within that function, the positioning/scaling code appears to be the culprit:

        elementSpot.position = new Vector3(((groep[i] - 9.5) * xInterval), ((10 - periode[i]) * yInterval + groundOffset), 0);
      elementSpot.scale = new Vector3(bgScale, bgScale, bgScale);

    And a few lines down:

        metallicSpot.position = new Vector3(((groep[i] - 9.5) * xInterval), ((10 - periode[i]) * yInterval + groundOffset), zDistanceBg);
      metallicSpot.scale = new Vector3(txtScale, txtScale, txtScale);

    Commenting out those lines within the positonNormal function makes the space load instantly.

    Creating a single new Vector3 with arbitrary values (2, 2, 2) before the for-loop and assigning that to position and scale seems to have no influence on the delay. It appears the problem is with the actual positioning and scaling, not the calculations for the position and scale of each element (which I suppose would be weird, since the calculations aren't exactly demanding).

    I've created a copy of the positionNormal function for debugging. In this 'positionDebug' function I've played around with the end of the for-loop. Up to 10 iterations gives no discernible delay in loading the space. At 20 iterations, there's a very small delay of roughly 1 second. At 40 iterations, the delay is 5 seconds. At 60 iterations it takes 21 seconds. So it appears the delay increases exponentially with more iterations.

    I've tried to comment out the lines that scale the objects, that reduces the load time by half (so for 60 iterations it goes from roughly 21 seconds to roughly 10-11 seconds). The same happens when I comment out the lines that position the objects, which appears to indicate that both scaling and positioning the objects contribute equally to the load times.

    I could duplicate and share my space if anyone's interested to take a look to figure out what is happening.

    Here's the current code (with the 'positionDebug' function added):

    const symbool = ["H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og"];

    const jaar = [1766, 1895, 1817, 1797, 1808, 0, 1772, 1774, 1886, 1898, 1807, 1755, 1825, 1824, 1669, 0, 1774, 1894, 1807, 1808, 1879, 1791, 1801, 1797, 1774, 0, 1730, 1751, 0, 0, 1875, 1886, 1250, 1817, 1826, 1898, 1861, 1790, 1794, 1789, 1801, 1778, 1937, 1844, 1803, 1803, 0, 1817, 1863, 0, 0, 1782, 1811, 1898, 1860, 1808, 1839, 1803, 1895, 1895, 1945, 1879, 1901, 1880, 1843, 1886, 1878, 1842, 1879, 1878, 1907, 1923, 1802, 1783, 1925, 1803, 1803, 1557, 0, 0, 1861, 0, 1540, 1898, 1940, 1900, 1939, 1898, 1899, 1829, 1917, 1789, 1940, 1940, 1944, 1944, 1949, 1950, 1952, 1952, 1955, 1958, 1961, 1964, 1967, 1974, 1976, 1984, 1982, 1994, 1994, 1996, 2004, 2004, 2003, 2004, 2010, 2002];

    const periode = [1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7];

    const groep = [1, 18, 1, 2, 13, 14, 15, 16, 17, 18, 1, 2, 13, 14, 15, 16, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];

    const metallic = ["plastic1", "plastic2", "metal1", "metal2", "half1", "plastic3", "plastic4", "plastic5", "plastic6", "plastic7", "metal3", "metal4", "metal5", "half2", "plastic8", "plastic9", "plastic10", "plastic11", "metal6", "metal7", "metal8", "metal9", "metal10", "metal11", "metal12", "metal13", "metal14", "metal15", "metal16", "metal17", "metal18", "half3", "half4", "plastic12", "plastic13", "plastic14", "metal19", "metal20", "metal21", "metal22", "metal23", "metal24", "metal25", "metal26", "metal27", "metal28", "metal29", "metal30", "metal31", "metal32", "half5", "half6", "plastic15", "plastic16", "metal33", "metal34", "metal35", "metal36", "metal37", "metal38", "metal39", "metal40", "metal41", "metal42", "metal43", "metal44", "metal45", "metal46", "metal47", "metal48", "metal49", "metal50", "metal51", "metal52", "metal53", "metal54", "metal55", "metal56", "metal57", "metal58", "metal59", "metal60", "metal61", "half7", "half8", "plastic17", "metal62", "metal63", "metal64", "metal65", "metal66", "metal67", "metal68", "metal69", "metal70", "metal71", "metal72", "metal73", "metal74", "metal75", "metal76", "metal77", "metal78", "metal79", "metal80", "metal81", "metal82", "metal83", "metal84", "metal85", "metal86", "metal87", "metal88", "metal89", "metal90", "metal91", "metal92", "metal93"];

    const lanthaniden = ["La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu"];

    const actiniden = ["Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr"];

    const logoNr = [51, 5, 0, 27, 20, 52, 9, 57];

    var xInterval = 0.12;

    var yInterval = 0.12;

    var txtScale = 0.09;

    var groundOffset = 0.1;

    var zDistanceBg = 0.0;

    var bgScale = 0.1;

    var logoZ = -0.2;

    var logoDelay = 2;

    var logoInterval = 400;

    var logoIndex = 0;

    log("Program started!");

    positionDebug();

    var logoTimer = setInterval(positionLogo,logoInterval);

    function positionNormal() {

      log("Starting normal positioning...");

      // Cache in array

      const elementSpots = symbool.map((symbol) => Space.getSpot(symbol));

      const metallicSpots = metallic.map((element) => Space.getSpot(element));

      for (let i = 0; i < symbool.length; i++) {

        if (!symbool[i]) continue;

        const elementSpot = elementSpots[i];

        elementSpot.position = new Vector3(((groep[i] - 9.5) * xInterval), ((10 - periode[i]) * yInterval + groundOffset), 0);

        elementSpot.scale = new Vector3(txtScale, txtScale, txtScale);

        if (!metallic[i]) continue;

        const metallicSpot = metallicSpots[i];

        metallicSpot.position = new Vector3(((groep[i] - 9.5) * xInterval), ((10 - periode[i]) * yInterval + groundOffset), zDistanceBg);

        metallicSpot.scale = new Vector3(bgScale, bgScale, bgScale);

      }

    }

    function positionDebug() {

      log("Starting debug positioning...");

      // Cache in array

      const elementSpots = symbool.map((symbol) => Space.getSpot(symbol));

      const metallicSpots = metallic.map((element) => Space.getSpot(element));

      let tempVec = new Vector3(2, 2, 2);

      for (let i = 0; i < 60; i++) {

        if (!symbool[i]) continue;

        const elementSpot = elementSpots[i]

        elementSpot.position = tempVec;

    //  elementSpot.scale = tempVec;

        if (!metallic[i]) continue;

        const metallicSpot = metallicSpots[i];

        metallicSpot.position = tempVec;

    //  metallicSpot.scale = tempVec;

      }

    }

    function positionLogo() {

        log("Positioning logo!");

        if (logoIndex > 7) {

            logoIndex = 0;

            clearInterval(logoTimer);

            setTimeout(() => setInterval(returnLogo,logoInterval), 2500);

        }

        else {

            smoothMove(logoNr[logoIndex], ((-1.5 + Math.floor(logoIndex % 4)) * xInterval), (5 - (Math.floor(logoIndex / 4))) * yInterval, logoZ, logoDelay);

            if (logoNr[logoIndex] == 9) {

                Space.getSpot(symbool[9]).scale = new Vector3(-bgScale, bgScale, bgScale);

            }

            logoIndex = logoIndex + 1;

        }

    }

    function returnLogo() {

        log("Returning logo!");

        let u = logoNr[logoIndex];

        log("u is set!");

        smoothMove(u, ((groep[u] - 9.5) * xInterval), ((10 - periode[u]) * yInterval + groundOffset), 0, logoDelay);

        Space.getSpot(symbool[u]).scale = new Vector3(bgScale, bgScale, bgScale);

        logoIndex = logoIndex + 1;

    }

    function smoothMove(symb, x, y, z, time) {

        Space.getSpot(symbool[symb]).moveTo(new Vector3(x, y, z), time).ease(EaseType.outQuad);

        Space.getSpot(metallic[symb]).moveTo(new Vector3(x, y, z + zDistanceBg), time).ease(EaseType.outQuad);

    }
    0
  • Dennis

    Thank you for your feedback Matthijs,

    If you could make a copy of your space for me and share the url. You can keep it unlisted.

    Then I can have a look if something else went wrong, leading to the delay issues you were having while loading your space. 

    0
  • Matthijs Broekhuizen

    Awesome, thanks for your help Dennis.

    Here's the link to the copied space: https://share.fectar.com/RSJDV

    If you need me to transfer it to you instead, let me know.

    0
  • Dennis

    Hi Matthijs,

    Short update on the status:

    I transfered a copy of your copied space to my own account and ran some tests. 

    It seems there's indeed something wrong with the performance. The first time I tested it in our debug environment, it was working fine after the proposed fixes. But with your thorough rundown on the issue in mind, I ran the tests again and sometimes ran into similar delay issues. And now with your copy in the browser I experience them all the time, when the spot count increases in your first for-loop. 

    So I'm writing some tests on our side and still looking into the issue. I will keep you updated on the progression.

    Thanks again for your feedback and patience ! 

     

    0
  • Matthijs Broekhuizen

    Hi Dennis,

    Thank you for looking into this so thoroughly!

    While it may just be a cause of unoptimized code on my end, if the issue does turn out to be related to the workings of the 'position' and 'scale' functions, it might be helpful to know that it worked in an earlier version of Fectar Studio. Before my license expired I had a meeting with someone about this space on January 23th, and I distinctly remember the space working fine at that point. Unfortunately, since my license expired temporarily thereafter and I wasn't working on it for a couple of months, I can't give you a more exact timeframe than that, but maybe it's helpful to track down the issue.

    Let me know if there's anything I can do to help.

    0
  • Dennis

    Hi Matthijs, 

    Did some tests and digging and it might be a bug in the collision event registration in combination with a larger amount of spots internally (even if you have physics disabled) which let the registration of  moved spots that hit each other grow exponentially (which is in line with what you experience as the timing gets worse after increasing the amount of spots you set). 

    You could test this by setting the position coordinates in fectar studio (instead of initializing the positions by code) to a value at which they don't intersect with eachother and avoid overlapping when moving them. They can be at different Z depths and overlap on screen, as long as they don't collide in 3d.

    There might be other issues at play as well, but this is an issue I discovered today which might get you to a solution.

    I'll keep you updated on our progress. 

    0
  • Matthijs Broekhuizen

    Hi Dennis,

    Thanks for the update. I've changed the position of each spot to a unique position. For now I've moved each spot by changing the X, Y or Z coördinate to a unique value with enough distance between them so they don't intersect. I'm not sure to what extent it matters if a spot intersects one or more other spots during the move, but I've also changed the code so each spot is scaled before it is moved to reduce the chance of spots colliding/intersecting. Unfortunately, this doesn't appear to have had a noticeable effect on the loading times.

    To prevent intersections completely I'd have to take the time to find a suitable position for each spot, which would basically mean positioning them where they would roughly end up in the periodic table. This would be quite tedious for the amount of spots I have in the space, and this is partly why I wanted to positon them in code. Also, the rough positioning I have done now should've reduced the amount of collisions by a lot, and seeing how the current changes haven't had a noticeable effect yet, I'm hesitant to spend more time manually positioning the spots.

    Is it possible to create a spot in code? I haven't found it in the API, but if that is possible I could instantiate text spots in the right position instead of relying on premade 3D models for the text. Creating each text spot in advance and positioning and editing the contents would still cause the same collisions.

    Thanks again!

    0
  • Dennis

    Hi Matthijs,

    Thanks for trying my suggestions. I understand it's quite cumbersome to have such amount of spots manually placed. Unfortunately it's not possible to create spots by code. 

    In our development environment I created a performance test which resembles your situation to a bare minimum and experienced the same issues when setting positions. I could narrow it down to the collision events always being processed for legacy reasons. On a PC it was noticeable at around 30 spots overlapping. After the rewrite it solved all issues in the test scenario and in a duplicate local version of your space. 

    This new code will first go through some testing stages before it can be released, so expect this change to be available within a couple of versions through an update of the app.

    Until then I'm afraid I can only suggest to put them all at fixed positions. 

    0
  • Matthijs Broekhuizen

    Hi Dennis,

    Glad to hear you were able to fix it in a rewrite! I can keep working on other parts of the space and on entirely different spaces, so I don't mind waiting for the update.

    Thank you for your thorough investigation, I look forward to the update!

    0
  • Dennis

    Hi Matthijs,

    Yes I also hope this will solve the issues. Good to hear this will not hold you up creating other great experiences!

    Thank you for your help improving the platform!

    0
  • Matthijs Broekhuizen

    For anyone monitoring this thread: the code works great in the current version, so it appears to be solved!

    0
  • Dennis

    Good to hear. Thanks for the feedback!

    0

Please sign in to leave a comment.