So, I already have autoRender
off, but I can’t depend on renderNextFrame
staying false while a model is being loaded. Anyone know of a way to forcibly freeze the screen or override renderNextFrame
to prevent any rendering for a certain period of time?
I don’t understand what you mean here. Why can’t you depend on it?
There’s code in various locations that will set renderNextFrame
to true. But, under certain situations I don’t want any new frames. The ideal solution would be to create a boolean and have those locations all check this boolean to see whether their allowed to set renderNextFrame
to true before doing so, just wondering if there’s an easier way to prevent new renders.
idk, maybe there’s a way to set renderNextFrame
back to false
right before the renderer updates.
You can do some basic reference counter and use a global event.
eg On some script (untested):
this.app.on('render:lock', function() {this.renderLockCount++; this.app.autoRender = false;}, this);
this.app.on('render:unlock', function() {this.renderLockCount--; if(this.renderLockCount === 0){this.app.autoRender = true;}, this);
And for every load request, you can fire render:lock
, and when it’s finished loading, fire render:unlock
.
Hmm, okay. Thanks for the code example. So, the project I’m working in behaves a little bit differently. It’s a product configurator, so autoRender
is never used and renderNextFrame
is used very frequently for anything that would update the visuals. That’s why I’m in this situation where I have a ton of different places that use renderNextFrame
.
I don’t have the full context of your project so these would be the general approach I would take:
- Only have one place where autoRender is set to true that checks for all conditions
- Have a list of clear conditions that may be counters on assets still to be loaded, flags that need to be true etc
- Use global events to update status of each sub system that may prevent a render
TLDR, have these different places that can prevent rendering use events notify a central system so that it can work out whether it should render or not.
Thanks @yaustar that definitely sounds like the most optimal solution. Having renderNextFrame
everywhere and trying to override it is just turning into a mess, a good refactoring is in order. I appreciate the help.
For anyone coming across this thread with a similar dilema, here’s the end result of what I did.
renderCenter.js script
/*jshint esversion: 6 */
var RenderCenter = pc.createScript('renderCenter');
// initialize code called once per entity
RenderCenter.prototype.initialize = function() {
// If no blocking assets AND renderRequested, screen will be rendered
this.renderRequested = false;
this.blockingAssets = 0;
// forceRender and forceFreeze OVERRIDE the above behavior (for special situations), if both are true forceFreeze takes precedent
this.forceRender = false;
this.forceFreeze = false;
// --- Events ---------------------------------------------------------------------
// asset blocking - prevent 'render:requestRender' events from going through when asset is currently loading
// Call on asset load start when updating visuals is not wanted
this.app.on('render:block', () => this.blockingAssets++, this);
// Call on asset load completion; automatically initiates render when no blocking assets are left
this.app.on('render:unblock', () => { this.blockingAssets--; this.renderRequested = true; }, this);
// Call on anything that makes a visual update
this.app.on('render:requestRender', () => this.renderRequested = true, this);
// For special situations..
this.app.on('render:forceRender', () => this.forceRender = true, this);
this.app.on('render:unforceRender', () => this.forceRender = false, this);
this.app.on('render:forceFreeze', () => this.forceFreeze = true, this);
this.app.on('render:unforceFreeze', () => this.forceFreeze = false, this);
};
// update code called every frame
RenderCenter.prototype.update = function(dt) {
if ((this.renderRequested && this.blockingAssets < 1) || (this.forceRender && !this.forceFreeze)) {
this.app.renderNextFrame = true;
// Only reset when finally rendered, this way once there are no more blockingAssets, the render goes through
this.renderRequested = false;
}
};
Requesting render (ie after a visual like color or position changes)
BEFORE
// Push frame
this.app.renderNextFrame = true;
AFTER
// Request frame
this.app.fire('render:requestRender');
Asset Blocking (ie prevent the screen from rendering until all models are done loading)
Here’s an example of asset blocking being used. onLoad()
cannot be relied on to always be called, so had to use the asset error
event to make sure the screen doesn’t get frozen on the very real possibility of an asset load randomly failing.
Forcibly Freezing (used to prevent rendering in situations that weren’t asset-blocking related)
Below is an example where entities were being replaced by disabling one entity and enabling another (had to be done in this order due to iOS Safari WebGL texture count limits). Screen is forcibly frozen while that switch is happening.