Very low FPS with Vue

Hi guys!

I was experiencing very low FPS (5-10) when using Vue instead of steady 60 FPS on the same scene using a plain HTML page. I was passing the engine object to the parent component to get the fps, that was the issue.

The solution is not to Ref and/or emit the BabylonJS engine and/or scene object. (in other words, do not make them reactive)

I didn’t dig deeper, but I think it causes multiple calls of the renderLoop or something similar.

R.

EDIT: repo demonstrating the issue: GitHub - RolandCsibrei/quasar-vue-bjs-low-fps: Demonstrates low FPS in Quasar combined with BabylonJS.

EDIT2: Official BabylonJS + Vue documentation

Hey, unfortunately we simply cannot help without a clear repro

You have to disconnect BJS from the VUE state and not let Vue touch any of the BJS objects or it will chain and try to make everything reactive every frame.

You have to make a communication bus that separates the BJS data from the react elements.

Just output the BJS object after you pass a param to make something on it reactive and look at the listeners its binding, you will see its toxic AF and its doing that every frame.

3 Likes

Hello,
my post is an advice for others, as you can read, I already solved the issue by not making the BJS Engine object reactive.

Thank you!

2 Likes

Hi there!
Yes, I did exactly the same. The GUI is based on Quasar/Vue2 and I introduced a Puppeteer class which serves as an interface between BJS and Quasar and simply translates method calls from the GUI to messages sent/received to/from the BJS part of the application. The GUI doesn’t know anything about BJS, and BJS doesn’t know anything about the GUI part, the Puppeteer is the bridge. The cool thing about this is, that I could move the BJS scene into a web worker.

Thanks for your response!

2 Likes

How can I understand this (you must disconnect BJS from Vue state, and Vue is not allowed to touch any BJS object). Now I define all BJS objects in methods. I use Vue, and I don’t bind any this, but FPS is still very low. I can keep FPS stable at 60 with H5. Can you give me some guidance.
This is my code, from initialization to rendering are completed in this method, without binding any this
inittest () {
let canvas = document.getElementById(‘renderCanvas’)
let engine = new BABYLON.Engine(canvas, true, {
preserveDrawingBuffer: true,
stencil: true,
disableWebGL2Support: false
})

  let target = new BABYLON.Vector3.Zero()
  let position = new BABYLON.Vector3(0, 260, 300)


  let scene1 = new BABYLON.Scene(engine)
  scene1.useRightHandedSystem = true

  // This creates and positions a free camera1 (non-mesh)
  let arcCamera1 = new BABYLON.ArcRotateCamera('arcCamera1', 0, 2, 10, target, scene1)
  // This positions the camera1
  arcCamera1.setPosition(position)

  // This targets the camera1 to scene1 origin
  // arcCamera1.setTarget(BABYLON.Vector3.Zero());

  // This attaches the camera1 to the canvas
  arcCamera1.attachControl(canvas, true)
  arcCamera1.allowUpsideDown = false
  // arcCamera1.upperRadiusLimit = 400
  // arcCamera1.lowerRadiusLimit = 5
  // arcCamera1.maxCameraSpeed = 10

  arcCamera1.panningSensibility = 50 
  arcCamera1.panningInertia = 0 

  // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
  let light1 = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene1)
  // let light2 = new BABYLON.HemisphericLight('hemi', new BABYLON.Vector3(0, 1, 0), _that.scene2);

  // Default intensity is 1. Let's dim the light a small amount
  // light1.intensity = 0.7;

  let importMeshs = []

  let gltfArr = [
    'https://models.babylonjs.com/seagulf.glb'
  ]
  // _that.createCameraSprite()
  gltfArr.forEach(item => {
    importMeshs.push(
      BABYLON.SceneLoader.ImportMeshAsync(null, item, '', scene1).then(res => {
          item.freezeWorldMatrix()
        })
      }))
  })
  Promise.all(importMeshs).then(res => {
    scene1.freezeActiveMeshes()
  })
  scene1.debugLayer.show({
    embedMode: true
  })
  const spriteManagerTrees = new BABYLON.SpriteManager('camerasManager', '/static/gltf/image/camera.png', 100, {
    width: 1024,
    height: 1024
  }, scene1)
  spriteManagerTrees.isPickable = true
  for (let i = 0; i < 20; i++) {
    // Mutliple trees
    const myCamera = new BABYLON.Sprite('cameras', spriteManagerTrees)
    myCamera.isPickable = true
    myCamera.useAlphaForPicking = true
    myCamera.position.x = i
    myCamera.position.y = 0
    myCamera.position.z = i
    myCamera.actionManager = new BABYLON.ActionManager(scene1)
  }
  engine.runRenderLoop(function (res) {
      scene1.render()
  })


}

Hi!
The important part of the code is the Vue part, so the snippet you provided is no help at all. Can you provide a github repo? I will gladly have a look at it.

1 Like

If I don’t go to my GitHub, can I use gitee? This is the demo address
I can’t go to GitHub. Is it OK to use gitee? This is the demo address of gitee

If I only load the model, I only draw once

When I added the sprites, the number of times I drew kept rising

Hello, the problem is not VUE, but your code:

Comment out line 99, 100 amd 101 and you will en up with 3 draw calls.

      // Promise.all(importMeshs).then(res => {
      //   scene1.freezeActiveMeshes();
      // });

You can freeze the mesh when iterating the loaded meshes, add this at line 80:
item.freezeWorldMatrix()

I didn’t dig deep, but you have a cyclic condition somewhere.

R.

2 Likes

It doesn’t seem to be the problem
// Promise.all(importMeshs).then(res => {
// scene1.freezeActiveMeshes();
// });
I have created 300 new spheres, and the number of drawing times does not increase all the time. The number of frames remains at about 50. I don’t know if it’s the problem of sprites, but it’s not very similar. Because I draw 200000 sprites alone, and the number of frames can reach 60. As long as the sprites and the imported gltf are used together, the number of drawing times will increase all the time, and the number of frames will drop slowly, Until 0 to 1 frames per second

You’re right. It’s really that the rendering times have been rising. Now I have a new problem. After I add Scene1. Freezeactivemeshes(), my FPS has been improved. I don’t add Scene1. Freezeactivemeshes(); My FPS has only 12 frames. I don’t know how to optimize it now. Can you help me?

1 Like

Post your code.

Post your code / Playground.

I don’t know how to upload the model, and it’s very big. I found someone else’s model. You see, the genie is rendering all the time. If you don’t add scene. Freezeactivemeshes(), it won’t render all the time
https://playground.babylonjs.com/#IQJ1BZ#1

Sorry, I am not sure I understand what is the issue here. What exactly do you want to achieve?

First of all, I import the gltf file. I have to use scene. Freezeactivemeshes() to increase my frame count. Then I use sprites. However, when using gltf and sprites together, the rendering times keep increasing, and then the frames will drop slowly. I can’t find a better way to improve my frame count except through scene. Freezeactivemeshes()

What is the playground URL?

You can optimize you scene (as far as I know) tweaking these:

If you a have a lot of meshes, you can use Instances or ThinInstances to juice more out of your GPU. Just check out the BJS documentation.

One more thing, you have low fps on this playground or in your Vue app? This is a very basic scene and there should be no performance problems so I assume there is a problem elsewhere.

@babylonjs197s it would be great to see a repro in the playground as I would like to preserve as much as I can our perfs ?