`sphericalPolynomial` really slow

CubeMapToSphericalPolynomialTools.ConvertCubeMapToSphericalPolynomial takes about 15s on Safari. For comparison, it takes about 3s on Chrome. Still very slow.

Screenshot 2022-11-18 at 11.01.12 AM

What happens is:

  1. A mesh (with a PBR material) enters the frustum.

  2. Even though it’s completely occluded, the engine calls bindForSubMesh, which decides it mustRebind. Shouldn’t the mesh be ignored?

  3. Then we have this:

    if (!ubo.useUbo || !this.isFrozen || !ubo.isSync) {
    useUbo=false, isFrozen=true, ubo.isSync=true.

    We proceed because useUbo is false, but… should we be checking for ubo.isSync, if useUbo is false?

  4. We then check if there’s a reflection texture, and if so, get its sphericalPolynomial property. That’s what’s slow.

  5. The worst part is… the reason we computed the polynomials is to update ubo, which is disabled!

  6. It seems odd that we’re reading a property (sphericalPolynomial) synchronously, while the actual computation is done in a Promise. The property returns null until it’s computed, so the whole UBO update fails anyway.

  7. Using a promise doesn’t help anyway, b/c it still runs on the main thread… It should be in a worker.

My apologies, if I’m jumping to conclusions. There’s a lot I don’t understand, so I could be totally wrong.

Anyway, I’m working around this by converting all PBR materials to standard. I don’t use PBRs, but that’s how GLTF materials are loaded.

@alekop this should be precomputed and cached if you use an env file instead of hdr for your environment texture.

Computing on the client is a waste of resources except in scenari of configurators like the sandbox where the user could dynamically chose any HDR files or with dynamic probes and so on,

This one is really interesting @Evgeni_Popov could you double check ?

if (!ubo.useUbo || !this.isFrozen || !ubo.isSync) {

If ubo.useUbo is false, the other expressions are not evaluated because !ubo.useUbo is true and all the expressions are ORed.

So, ubo.isSync is evaluated only if ubo.useUbo=true, which is the expected behavior. Note that ubo.isSync has no meaning if ubo.useUbo=false.

ahah Thanks a lot, sorry to disturb for this one, was in a meeting :wink:

Makes sense. But if UBO is disabled, why do the whole polynomial computation? We use the result to update ubo.

we also update uniforms if ubos are not availables, we need the value somewhere :slight_smile: either in ubo or in uniforms

1 Like

The polynomial computation is not related to ubo.

When you see ubo.updateXXX(...), the uniform buffer is updated if ubo.useUbo==true and it is the effect which is updated if ubo.useUbo==false. ubo.updateXXX(...) is not an empty operation when ubo.useUbo==false.