What could be causing the decrease in speed of my Three.js animation within Vue.js?

I attempted to replicate the impressive wave simulation from this CodePen link: https://codepen.io/cheekymonkey/pen/vMvYNV, using Vue.js. However, the animation seems to be running significantly slower when implemented in Vue.js.

In my effort to recreate it, I ensured that all functions were converted into Vue.js methods and all necessary variables were included in the data section of the component.

<template>
    <div id="container" style="width:100%; height:100vh;"></div>
</template>

<script>
import * as Three from 'three'
import SimplexNoise from'simplex-noise'

export default {
  name: 'ThreeTest',
  data() {
    return {
      camera: Three.PerspectiveCamera,
      scene: Three.Scene,
      renderer: Three.WebGLRenderer,
      mesh: Three.Mesh,
      noise: SimplexNoise,
      geometry: null,
      factor: 0
    }
  },
  methods: {
    init: function() {
      this.createScene();
      this.createCamera();
      this.createShape();
      this.addSpotlight('#fdffab');
      this.addAmbientLight();
      this.animate();
      window.addEventListener('resize', this.onResize())

    },
    onResize: function() {
      let container = document.getElementById('container');
      this.renderer.setSize(container.clientWidth, container.clientHeight);
      this.camera.aspect = container.clientWidth / container.clientHeight;
      this.camera.updateProjectionMatrix();
    },
    createScene: function() {
      this.scene = new Three.Scene();
      this.renderer = new Three.WebGLRenderer({
        antialias: true,
        alpha: true
      });
      let container = document.getElementById('container');
      this.renderer.setSize(container.clientWidth, container.clientHeight);
      this.renderer.setPixelRatio(window.devicePixelRatio);
      this.renderer.setClearColor(new Three.Color('#fff'));
      //this.render.shadowMap.type = Three.PCFSoftShadowMap;
      this.noise = new SimplexNoise()
      container.appendChild(this.renderer.domElement);
    },
    createCamera: function() {
      this.camera = new Three.PerspectiveCamera(20, container.clientWidth/container.clientHeight, 1, 1000);
      this.camera.position.set(0, 0, 20);
    },
    createShape: function() {
      const seg = 100
      this.geometry = new Three.PlaneGeometry(5, 8, seg, seg)
      const material = new Three.MeshPhysicalMaterial({
        color: '#da0463',
        metalness: 0.6,
        emissive: '#000',
        side: Three.DoubleSide,
        wireframe: true
      })
      this.mesh = new Three.Mesh(this.geometry, material)
      this.mesh.receiveShadow = true
      this.mesh.castShadow = true
      this.mesh.position.set(0, 0, 0)
      this.mesh.rotation.x = -Math.PI / 3
      this.mesh.rotation.z = -Math.PI / 4
      this.scene.add(this.mesh)
    },
    addSpotlight: function(color) {
      const light = new Three.SpotLight(color, 2, 1000)
      light.position.set(0, 0, 30)
      this.scene.add(light)
    },
    addAmbientLight: function() {
      const light = new Three.AmbientLight('#fff', 0.5)
      this.scene.add(light)
    },
    adjustVertices: function() {
      for (let i = 0; i < this.geometry.vertices.length; i++) {
        const vertex = this.geometry.vertices[i]
        const x = vertex.x / 4
        const y = vertex.y / 6
        vertex.z = this.noise.noise2D(x, y + this.factor)
      }
      this.factor += 0.007
      this.geometry.verticesNeedUpdate = true
      this.geometry.computeVertexNormals()
    },
    animate: function() {
        requestAnimationFrame(this.animate);
        this.adjustVertices();
        this.camera.updateProjectionMatrix();
        this.renderer.render(this.scene, this.camera);
    }
  },
  mounted() {
      this.init();
  }
}
</script>

While the wave animation does work correctly, it noticeably runs slower. I'm not sure if this sluggish performance is due to Vue.js or an issue with how I've configured it. Any guidance would be greatly appreciated!

Answer №1

The reason for this issue is due to Vue's internal mechanism that makes each component attached to the instance reactive. If you want to delve deeper into reactivity in Vue, check out Reactivity in Depth. Try opening the developer tools and monitoring your memory usage. Upon running your code snippet on my machine, it consumed around 300mb of memory compared to a similar codepen example which only used about 20mb.

When you access console.log(this.scene), what you're actually seeing are the getters/setters utilized by Vue to monitor objects.

https://i.stack.imgur.com/iDCCY.png

In the provided code snippet, the Vue data object containing three.js elements is extracted and attached to a custom vue-static object. This plugin enables specific variables to be designated as non-reactive.

<template>
    <div id="container" style="width:100%; height:100vh;"></div>
</template>

<script>
import * as Three from 'three'
import SimplexNoise from'simplex-noise'

export default {
  name: 'ThreeTest',
  static(){
    return {
      scene: new Three.Scene(),
      camera: null,
      renderer: Three.WebGLRenderer,
      mesh: new Three.Mesh,
      noise: SimplexNoise,
      factor:0
    }
  },
  mounted() {
    this.init();
  },
  methods: {
    init: function() {
      this.createScene();
      this.createCamera();
      this.createShape();
      this.addSpotlight('#fdffab');
      this.addAmbientLight();
      this.animate();
      window.addEventListener('resize', this.onResize())
    },
    onResize: function() {
      let container = document.getElementById('container');
      this.renderer.setSize(container.clientWidth, container.clientHeight);
      this.camera.aspect = container.clientWidth / container.clientHeight;
      this.camera.updateProjectionMatrix();
    },
    createScene: function() {
      
      console.log("TCL: this.$options.bigHairyHorseNuts ",this.bigHairyHorseNuts)

      this.renderer = new Three.WebGLRenderer({
        antialias: true,
        alpha: true
      });
      let container = document.getElementById('container');
      this.renderer.setSize(container.clientWidth, container.clientHeight);
      this.renderer.setPixelRatio(window.devicePixelRatio);
      this.renderer.setClearColor(new Three.Color('#fff'));
      //this.render.shadowMap.type = Three.PCFSoftShadowMap;
      this.noise = new SimplexNoise()
      container.appendChild(this.renderer.domElement);
    },
    createCamera: function() {
      this.camera = new Three.PerspectiveCamera(20, container.clientWidth/container.clientHeight, 1, 1000);
      this.camera.position.set(0, 0, 20);
    },
    createShape: function() {
      const seg = 100
      this.geometry = new Three.PlaneGeometry(5, 8, seg, seg)
      const material = new Three.MeshPhysicalMaterial({
        color: '#da0463',
        metalness: 0.6,
        emissive: '#000',
        side: Three.DoubleSide,
        wireframe: true
      })
      this.mesh = new Three.Mesh(this.geometry, material)
      this.mesh.receiveShadow = true
      this.mesh.castShadow = true
      this.mesh.position.set(0, 0, 0)
      this.mesh.rotation.x = -Math.PI / 3
      this.mesh.rotation.z = -Math.PI / 4
      this.scene.add(this.mesh)
    },
    addSpotlight: function(color) {
      const light = new Three.SpotLight(color, 2, 1000)
      light.position.set(0, 0, 30)
      this.scene.add(light)
    },
    addAmbientLight: function() {
      const light = new Three.AmbientLight('#fff', 0.5)
      this.scene.add(light)
    },
    addjustVertices: function() {
      for (let i = 0; i < this.geometry.vertices.length; i++) {
        const vertex = this.geometry.vertices[i]
        const x = vertex.x / 4
        const y = vertex.y / 6
        vertex.z = this.noise.noise2D(x, y + this.factor)
      }
      this.factor += 0.007
      this.geometry.verticesNeedUpdate = true
      this.geometry.computeVertexNormals()
    },
    animate: function() {
        requestAnimationFrame(this.animate);
        this.addjustVertices();
        this.camera.updateProjectionMatrix();
        this.renderer.render(this.scene, this.camera);
    }
  }
}
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I transfer a selected value from a unique dropdown component to react-hook-form?

I am utilizing react-hook-form for form validation in this Gatsby project. However, my dropdown component is not a <select> tag but a customized component created with divs and an unordered list. This design choice was made to meet our specific custo ...

When using Ionic Vue, the `this.$router.push('/home')` command successfully changes the link, but unfortunately it continues to

After logging in, I am trying to redirect to the home page. Using the following code: this.$router.push() The URL changes from localhost:8100/auth/login to localhost:8100/home However, the page remains the same, i.e., the Login Page. The routes ind ...

Library of CSS styling information

Has anyone come across a reliable javascript library that can retrieve the original style (not computed) of a specific element in the DOM? Essentially, I am looking for something that can provide results similar to what is displayed in Firebug's style ...

Modify all the content within the DIV using Regex, while keeping the HTML tags intact

I am attempting to replace all the text inside a DIV, including within its children, without modifying any HTML tags. Specifically, I want to switch all instances of 'Hello' to 'Hi'. Thank you for your help. var changes = $('div ...

Dealing with a jQuery/Javascript/AJAX response: sending a string instead of an integer as a parameter to a

Trying to figure out how to handle passing integers as strings in JavaScript within an AJAX response. Here is the code snippet: message+="<td class='yellow' onclick='open_flag("+i+j+")'>"; The message variable is eventually inse ...

Error: The middleware function is not recognized | Guide to Transitioning to React Redux Firebase v3

After utilizing these packages for my project, I encountered an error in middleware composition while creating a new react app with create-react-app. Below are the packages I have included. Can someone please help me identify what is missing here? HELP I ...

Display real-time information fetched from sessionStorage (in JSON format) on a Listview widget

In my session, I have the following JSON data stored: Prescription: [{"medID":"id1","medName":"name1","medQty":"qty1","medDirec":"Directions1"}, {"medID":"id2","medName":"name2","medQty":"qty2","medDirec":"Directions2"}] I am looking to automatically dis ...

Leveraging ng-change in AngularJS when utilizing the "Controller As" syntax

Attempting to steer clear of using $scope within my controller function, I have instead chosen to use var viewModel = this; employing the "controller as" viewModel syntax. The issue at hand is that while I can access data from a service, invoking functio ...

NextJS-created calendar does not begin on the correct day

I'm facing an issue with my calendar code where it starts rendering on a Wednesday instead of a Monday. I want to adjust the layout so that it always begins on a Monday by adding some empty boxes at the start of the calendar. Essentially, I need to s ...

Is it possible to utilize Ajax submit requests within a (function($){...}(jQuery)); block?

As a PHP developer with some knowledge of JavaScript, I am currently using AJAX to send requests to the server. I recently came across the practice of enclosing all code within an anonymous JavaScript function like: (function($){ //code here }(jQuery)). Fo ...

Attempting to save data to a .txt file using PHP and making an AJAX POST request

I have been facing an issue while trying to save a dynamically created string based on user interaction in my web app. It's just a simple string without anything special. I am using ajax to send this string to the server, and although it reaches the f ...

Unable to cancel $interval within factory

I created a factory for long-polling, complete with start and stop methods. However, I am struggling to cancel the timer. Any suggestions or ideas? app.controller("AuthCtrl", function($scope, $http, $window, User, Poller) { Poller.start(1, $scope.sess ...

Unable to send image file and string via XHR is causing issues

This task may seem straightforward, but I've been struggling with it for hours. My goal is to upload an image file along with stringified coordinates to crop the image on the server-side. Below is my client-side code: var formdata = new FormD ...

Changing the order of element names depending on their location within the parent element using jQuery

<div class="content"> <div> <input type="text" name="newname[name]0"/> <div> <input type="text" name="newname[utility]0"/> <div> <textarea name="newname[text]0 ...

Updating the jQuery mobile webpage

I have set up a small demo with two pages - the Home page and the Team 1 page. By clicking on the navigation menu, you can navigate to the Team 1 page from the Home page. However, if you are already on the Team 1 page and click on the Team 1 button again ...

What are the solutions for fixing a JSONdecode issue in Django when using AJAX?

I am encountering a JSONDecodeError when attempting to send a POST request from AJAX to Django's views.py. The POST request sends an array of JSON data which will be used to create a model. I would greatly appreciate any helpful hints. Error: Except ...

Whenever a new entry is made into the textfield, the onChange feature triggers a reset on the content within the textfield

I'm experiencing an issue while creating a SignUp authentication page with Firebase. Every time I try to input text in the text field, it gets reset automatically. I have been unable to identify the root cause of this problem. It seems to be related t ...

Can you guide me on how to access an Angular route using a URL that includes query parameters?

Within my current development project, I have implemented a user profile route that dynamically navigates based on the user's _id. This means that when a user accesses the page, their _id is stored in localStorage and then used to query MongoDB for th ...

The internet browser encountered a JavaScript runtime error (0x800a138f) in which it was unable to retrieve property '0' due to it being either undefined or pointing to a

I'm encountering an issue with my javascript/jquery function that retrieves the selected dropdown value. Everything works fine in Chrome, but when I try to run my application in IE, it throws an error. $("#Application_AppCountries").change(function ( ...

I must first log a variable using console.log, then execute a function on the same line, followed by logging the variable again

Essentially, I have a variable called c1 that is assigned a random hexadecimal value. After printing this to the console, I want to print another hex value without creating a new variable (because I'm feeling lazy). Instead, I intend to achieve this t ...