How did he get into the car when the progress bar reached 100%?There seems to be no stagnation.
Does he add the rendering progress?Is there any way to get the progress of rendering?
On my project, I need to add the rendering progress of some models or materials to my loading page.
In order to enter the page directly when the progress bar reaches 100%, it is not to stuck for a moment before entering the page at 100%
There is also a question on the forum post, but it hasn’t been solved yet.
Looks like they are trying to keep the loading bar to be less than 100% until the shaders have finished compiling on the first render frame.
The preload of assets downloading etc seem to be for the first 50% (maybe more?) and then they fire their own internal events to manage the reminder of the loading bar on whatever custom loading logic they’ve created.
Preload I guess is 50%.
Will this internal event be a callback to the model rendering progress? Because I don’t seem to see this in the life cycle of playcanvas. Is there any common way to do this for playcanvas?
The events you have highlighted are custom to that project so it’s whatever custom loading logic they’ve implemented.
At a guess, they’ve loaded parts of the car at a time and added it to the scene in camera view so that the shaders are compiled.
Is the second half of the loading progress bar the callback when the camera sees the model?
Again, its custom project logic so I don’t really know what they are doing. I’m just guessing.
Is there a way to obtain a series of model renderings in playcanvas? That is, the callback of rendering.Or how to know how many models the camera sees?
In a nutshell, models (or more specifically mesh instances) are rendered in the current frame if:
- Entities and model/render components are enabled and not hidden at the mesh instance level
- The AABB of the mesh instance is in the camera frustum (if frustum culling is enabled on the camera)
- The assets used (meshes, materials, textures) are loaded
There’s no public API to know exactly what or how many are rendered (@mvaligursky may be able to chime in).
I’m not sure exactly what that project is doing or the issues that you are facing to give any more specific advice.
If you have provide a public project that shows the issue you are running into, that would be great.
That is correct. There are some stats available in debug or profiling builds on the engine for performance reporting, but it’s not something reliable for this.
I’d say that counting number of assets that are not loaded yet would be a way to go, if there’s some easy way to find out. When all of them are loaded, the next frame will finish compiling last remaining shaders and render the mesh. From the frame following this, there should be no slowdowns.
This is a private project. Can you send me your account number? I will add you to my project team so that you can view it, but please also keep it private. This is not open to the public.I have another question.
When I released my project, I found it’s very strange on the iPhone, that is, when the progress bar reaches 100%, it will be stuck for 2~10 seconds, Android devices(2secs), especially iPhone is very slow around 8~10secs.
Why does the Civic TypeR shows the 3D contents(the car & environment) immediately when the prograss bar reached 100%, both in iPhone and Android?
What can we do to show 3D contents immediately when the prograss bar reached 100% link the Civic TypeR?
Civic TypeR link:
There’s several parts to unpack so I will try to address these:
Here’s a link to the default flow of opening the app: https://developer.playcanvas.com/en/user-manual/scripting/application-lifecyle/
The default loading bar goes from 0 to 100% based on the download progress of the assets set to preload.
When all the preload assets are loaded, the bar is at 100% and it starts the app. This includes the initialisation of the components, scripts, first update and rendering the first frame.
If you are finding that there is a freeze/pause between the preload finishing and seeing the first render frame, this is likely to be one of these reasons:
-
You are using mesh collision and have multiple mesh collisions, some of which have a high poly count. This is because the collision mesh has to be built at runtime and can take a while depending on the number of different mesh collisions and poly count.
-
There’s a lot of logic happening in the initialisation/post initialisation/first update of the scripts. This all runs before the first frame render.
-
Shader compilation. When a material is first rendered to the scene, the engine has to compile the shader based on features used in the Standard Material. eg use of the diffuse material channels etc. The more complex and more unique materials you have, the longer it takes on devices.
3 is usually the issue (use the browser devtools profiler to check) and not an easy thing to optimise.
Reducing complexity of the shaders from lighting
If you aren’t using multiple omni or spotlights in the scene, then I would disable Clustered Lighting in the project settings to reduce the shader size to be compiled.
In either case, I would disable shadow casting from lights where possible.
Reducing shader/material variants
You can reduce the number of shaders needed to compile by reducing the different combinations of properties used in the materials.
As a simple example: PlayCanvas 3D HTML5 Game Engine
Scene 1 uses two separate materials
‘Scene 1 Material A’ is using a texture for the diffuse channel
‘Scene 1 Material B’ is just using the color
When we run the scene, we see how many shaders are being compiled in the PlayCanvas profiler:
In Scene 2, we have same visual render with ‘Scene 2 Material B’ using a texture instead for color
Now both materials in the scene are using the same materials properties as each other and therefore can use the same generated shader code which is seen in the PlayCanvas profiler
You can also see that my compile time is reduced from 2.7 ms to 1.2 ms
However, the downside in this case is that using a texture for color requires a lot more shader code which we can see in Spector.js:
Compared to Scene 1’s material of just using the color
This means that Scene 2 is doing more work per pixel and would be more expensive to render at runtime.
It’s also not easy to know which properties would add/remove code from the shader too which makes this process difficult if they wanted to go down this route.
Lag when moving the camera
Similar to the above. The lag is likely because it is rendering new materials in view and having to compile the shaders and upload textures needed for them. To work around this would be to have these materials in camera view somewhere (on a cube for example in the corner behind some UI) before they are needed over time.
Hiding the lag on preload complete
As mentioned before, the loading bar only shows download progress. Once it is complete, it will do all the initialisation for the scene, entities, materials etc needed to update and render the first frame.
To hide this, some developers have changed the preloader so the loading bar only goes from 0%-90% showing to the user that it is still ‘loading’.
Or if you want something more granular. You can disable all entities in the scene in the Editor and have the loading bar go from 0 to 50% (or some other number) for the preload assets download progress.
Then when the app is started, enable groups of Entities frame by frame and fire an event to update the progress bar. eg. first frame, enable all the wheels, wait for render, fire event. Second frame, the car exterior, wait for render, fire event, etc
This way, the materials are rendered and compiled in groups on a frame by frame basis so you can update the progress bar on progress.
On top of this, they have also added a transparent iframe on top that has a loading animation (eg spinning disc) because even though the parent page is thread locked, the iframe is still updated. This means that the user is not looking at a frozen screen.
Another possible method is to have the first scene / frame be as simple as possible. (eg disable the car entities) and the engine won’t compile the shaders until the materials are used to render in the scene. Once the user is in the experience, the app can enable car parts over time (this can be hidden in some way, Polaris do this quite well) so that it doesn’t completely lock up the page.
Ok, I will try to use these methods you suggested. Thanks for your help
Hi Yaustar, nice detailed explanation. What is the method to determine the frame is rendered?
You can wait till the next frame as rendering blocks the thread. You could try listening for the renderend event (see https://developer.playcanvas.com/en/user-manual/scripting/application-lifecyle/) but I don’t know if that is actually when it has rendered to the canvas/screen.
Will ‘frameend’ be displayed on the screen? I have seen this in the life cycle
As mentioned before, I’m not sure. Personally, I would wait till the next frame start/update to be 100% sure that the frame has finished.
I haven’t tried this but I wonder if the layer onPostCull callback and onDrawCall callback could be leveraged to get some more granularity. For example, in the onPostCull callback, count the number of total number of mesh instances that are going to be rendered on eg World layer. Then in the onDrawCall callback, which is called after any shader compilation I think, increment a count of the number of mesh instances rendered this frame. Then fire an event passing count and total that could be used in the logic to update the loading bar. Then at the end of the first frame remove the callbacks. I don’t have actual need for this myself, just interested.
I’m not sure its particularly useful to do this, as all those callbacks would be called inside a single frame. You cannot display a progress of that as the screen updates only once a frame.
You need a solution that takes multiple frames. And in generaly there is only one frame, unless you add meshes one by one? (I didn’t follow this whole thread, so maybe I don’t understand the end goal here)
Hi @mvaligursky
If the loading progress UI is handled in HTML/CSS like in the default playcanvas loading screen example and not the canvas, could the the loading UI be updated with the method I suggested during the first frame?
The goal is that the loading progress bar keeps moving as each mesh instance is processed during the first frame.
I’m not sure, I’m not an expert on HTML rendering side. But I think in some browsers, even animated gifs stop playing if WebGL does not update.