Performance issue when rendering multiple objects

Hello there!

I’m trying to recreate the solar system with Processing using somewhat realistic proportions (at scale) and real astronomical data. My goal is to instill a feeling of vastness; users should get an approximate idea of how big is our solar system.

You can find the project source code in this github repository: PocketPlanetarium

I apologize in advance for the ugly code, this project started as a college assignment and I consider it a proof of concept. I’m aware it could use a bit of refactoring love and decoupling as well. I plan to overhaul and expand it in the future, I’m also looking forward to port it to P5.js.

A quick introduction to the codebase

The main entity is the AstronomicalBody, which represents any physical body that could be found in a solar system: be it a star, a planet, a comet, etc. Right now it can only be either the Sun, one of the 8 main planets, or a moon of some planet. This entity has a bunch of properties, such as the radius, mass and parameters that define its orbit. It also contains a 3D mesh, and a list of orbitating bodies, which are AstronomicalBodies too.

When an AstronomicalBody is told to be displayed, it first computes its axial rotation and orbit rotation for the current time using Kepler laws of orbitation, draws itself in the correct position, and tells its orbitating bodies to display themselves too. This way we can draw the whole Solar system by telling the Sun to display itself, which in turn propagate to all planets and their respective moons.

SolarSystem is another entity whose main role is to load the Sun and all planets, and render the whole system and lightning. There are more components involved, but they’re mostly controls, camera and stuff.

The problem

The problem, or question to be more precise, is the following: when I try to execute it using an iGPU, such as Intel UHD 630 (which is the one I’m using), it takes quite a while to show something. Using a discrete GPU solves the problem, but I would like to understand why is happening, and if there’s a solution for a iGPU or a low spec GPU.

I have some sort of loading screen, to ease that UX itch, and I wanted to code a simple animation tweaking the “LOADING…” text opacity. I noticed that loading all data from files and creating all the data structures takes a breeze, but as soon as it reaches the “drawing time” it takes ages. However, it only happens at the initial render, after that the app runs smoothly. I fail to understand why the performance is so bad just at the first render.

This is a problem, because I would like to show the loading screen animation while all the slow stuff is running in the background. But this is impossible, as the main loop freezes at that single iteration, when the loading finishes and the sun.display() takes place, leaving the screen blocked in the last loading animation frame as it cannot clear the screen buffer. It is not possible to throw a thread for carrying out that initial render while the main loop shows the animation, because thread() doesn’t have drawing capabilities.

In my first versions it was a complete no-go, as it took +30min to load with an iGPU. I was able to solve it though when I noticed I was forcing a gigantic scale →

perspective(PI/3.0,(float)width/height,1, 10000000); and camera.setMaximumDistance(10000000);

Managed to reduce it to just 1min by tuning it down to something more reasonable →

perspective(PI/3.0,(float)width/height,1, 900); and camera.setMaximumDistance(550)

However, it doesn’t matter if I tweak the size nor the distance scales to accomodate an even smaller perspective, I cannot surpass that 50s - 1min wall. Any ideas?

Hi, Captain

i will love to produce such nice documented code…
it run quite smoothly here, i wonder if
synchronized void draw() {
can be a problem during loading: in your setup you don’t set a frameRate, so draw() is called without any pause taking available ressources, if i well understand synchronized, other thread will be blocked when it run, (and draw() is quite peticular in processing) , and it look to me it s not needed as you have a flag “loading” to deal with it ?
i tried frameRate(25) and it run smoothly with a 30% cpu usage

i don t see anything wrong there, may be for low end graphics card, images are heavy, i see you have few 8k ones in data

nice app btw

1 Like

Hi th75!

Thank you for your answer and kind words :blush:

I’ve been thinking on what you said about synchronized and framerate() and I’m afraid that doesn’t solve my problem :worried: . I tried removing the synchronized of the draw loop and also set different framerates just in case, and the problem persisted.

The thread I create on setup doesn’t really take part in the problem I described. The actual problem appears when both setup and the thread finish, so that loading is set to true and therefore the draw loop reaches renderScene(), which eventually calls sun.display(), rendering all AstronomicalBodies at once. The line sun.display() takes a lot of time to finish, to the point draw hangs in there for a whole 1 min (on my computer). This only happens the first time is called, after that, the app runs smoothly.

This is what I really struggle to understand, if performance as a whole was consistently bad, I would just blame it on the algorithm being too heavy for the iGPU and make it a day :confounded:

Did you execute it with your iGPU? How was the loading time on your machine?

Thank you for your help!

hi,

yes and no, i’m on a mac m1, so it’s an all integrated chip but i’m not sure it"s relevant to compare to igpu (specially about memory bandwith)

from run pressed to loading message it s about 1~2 second of white screen then, 1s of “loading”

otherwise i don t see any bottleneck, next i will try to temporary replace textures with small images to check, i think it can be that textures are effectively uploaded to videocard only at first display

1 Like

My my

Isn’t the blazing fast one? My nvidia 1050ti only manages to load in 6s. Btw, I just discovered I’m stupid :^D! Thanks to what you said, I tried commenting out the textures, and I realized that I had left the 8k sun texture all the time! I had replaced all textures with 1k, that’s the reason I wasn’t understanding the bottleneck. After commenting out the sun texture it only takes 5s even with my crappy Intel UHD Graphics!

Btw, even with this, those 5s are a unavoidable block. How could I handle that initial texture load into the GPU without blocking draw into a single frame? I would like to transition smoothly from the loading animation to the actual experience. Do you think it would be possible?

Thank you very much!!

good !
i used the timeSinceLastStep you set : println(frameCount,timeSinceLastStep);
and i see too that first renderScene() frame is really longer 500ms in place of 10~15ms for next ones

i’m not totally sure about what i said, but i think textures are uploaded to videocard only at first use ( i hope a more confirmed user can tell us that), if it s the case a way is to use model/texture during your loading sequence like loading a model/texture by frame (frameCount ) and display it offscreen.

otherwise it puzzle me a lot, it looks quite light to me (compare of what you can do with processing usually) but i can t find the bottleneck, i tried to replace sphere with cubes, no changes, so it s not about a complex geometry, disabling textures doesn’t change much , even removing all moons doesn t bend time, damn

an ugly way, just to hide this freezing frame under “loading” can be:

if (loading) {
    try{solarSystem.sun.display();
         loading = false;
     }catch(Exception e){}
    showLoadingScreen();
  } else {
   renderScene();
  }

it will renderScene only when it succeed a first draw under the loading screen… but i’m sure there is a more elegant solution…it can be two flags in place of try/catch

1 Like

Hello again th75!

I’ve been tinkering with println(frameCount,timeSinceLastStep); and found out it’s both solarSystem.display() and spaceship.display() who are slowing things down, with ~300ms and ~200ms respectively, hence the 500ms you got on that particular frame (without any texture). I think it must be something related to all the transformations that take place, and also solarSystem.display() being kind of recursive in nature. The spaceship seems simple, but I manually reset the transformation matrix, that may explain why the small difference :face_with_raised_eyebrow:

After some research on off-rendering, PGraphics and ways of rendering outside of draw() I stumbled upon this stackoverflow post. I might try to perform some magic with Java Thread, although it seems like some kind of rabbit hole that will surely take me a couple of days :face_exhaling: . Also, the same answer that propose Thread, suggests it may not be thread secure.

I’ll come back to you in a couple of days with news, be them of victory or defeat :joy:

That’ll definitely set me on a good track!

Thank you very much!