Improving performance and anti-alliasing on a background animation (Line2)

Hello,

Im quiet new to the world of 3D and three.js. Im experimenting with the following background animation. https://hobiewetzels.nl/projects/calvi/Prototype3D/2.0/ (not sure how to host on code-pen while including files).

I am only rendering 10 lines, however my PC (which has a dedicated graphics card) tries to lift off and fly away whenever I run it for a longer time. Also the anti-aliasing can be quite bad and the lines look jagged. Any tips on how to improve this are much appreciated. My apologies for the dirty code, I’d really like to learn more about this library.

Also how would I do a performance check/benchmark to test if changes have a positive impact?
The code:

   <!DOCTYPE html>
<html lang="en">
  <head>
    <title>three.js webgl - lines - fat</title>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
    />
  </head>
  <style>
    body{
      background-color: white;
      height: 3000px;
      overflow-x: hidden;
      margin: 0;
    }
  </style>

  <body style="height: 3000px;">
    <canvas id="three-canvas"></canvas>

    <script type="module">
      import * as THREE from "../Includes/ThreeJS/build/three.module.js";
      import Stats from "../Includes/ThreeJS/examples/jsm/libs/stats.module.js";
      import { GUI } from "../Includes/ThreeJS/examples/jsm/libs/dat.gui.module.js";
      import { OrbitControls } from "../Includes/ThreeJS/examples/jsm/controls/OrbitControls.js";
      import { Line2 } from "../Includes/ThreeJS/examples/jsm/lines/Line2.js";
      import { LineMaterial } from "../Includes/ThreeJS/examples/jsm/lines/LineMaterial.js";
      import { LineGeometry } from "../Includes/ThreeJS/examples/jsm/lines/LineGeometry.js";
      import { GeometryUtils } from "../Includes/ThreeJS/examples/jsm/utils/GeometryUtils.js";

      //bloom effect
      import { EffectComposer } from '../Includes/ThreeJS/examples/jsm/postprocessing/EffectComposer.js';
			import { RenderPass } from '../Includes/ThreeJS/examples/jsm/postprocessing/RenderPass.js';
      import { UnrealBloomPass } from '../Includes/ThreeJS/examples/jsm/postprocessing/UnrealBloomPass.js';
      //FXAA
      import { ShaderPass } from '../Includes/ThreeJS/examples/jsm/postprocessing/ShaderPass.js';
      


      //global vars
      var line, renderer, scene, camera, controls, composer, bloomPass, group, fxaaPass;
      var matLine, matLine2, matLine3;
      var stats;
      var gui;
      // viewport
      var insetWidth;
      var insetHeight;
      //bloom
      var angle = 0;
      var params = {
				exposure: 1,
				bloomStrength: 1,
				bloomThreshold: 0.2,
				bloomRadius: 0.5
      };
      //position
      var xInc = 0;
      //arrays
      init();

      function init() {
        var canvasElm = document.getElementById('three-canvas');
        renderer = new THREE.WebGLRenderer({canvas: canvasElm, antialias: true, alpha: false });
        renderer.setClearColor(0x030337, 1);  
        renderer.setSize(window.innerWidth, document.documentElement.scrollHeight);
        renderer.autoClear = false;
        scene = new THREE.Scene();
        scene.background = new THREE.Color( 0x030337);
        camera = new THREE.PerspectiveCamera(
          40,
          window.innerWidth / window.innerHeight,
          1,
          1500
        );
        camera.position.set(0, 0, 500);
        //controls

        //controls = new OrbitControls(camera, renderer.domElement);
        //controls.minDistance = 100;
        //controls.maxDistance = 1000;
      var renderScene = new RenderPass( scene, camera );


			bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, document.documentElement.scrollHeight ));
			bloomPass.threshold = params.bloomThreshold;
			bloomPass.strength = params.bloomStrength;
			bloomPass.radius = params.bloomRadius;
			composer = new EffectComposer( renderer );

			composer.addPass( renderScene );
      composer.addPass( bloomPass );
      
      //draw line
        // Position and THREE.Color Data
        var positions = [];
        var points = [];
        var angle = 0;
        for (let index = 0; index < 30; index++) {
          points.push(new THREE.Vector3(150 * Math.sin(index * 0.01 + angle), 200 - (index * 20) , 0 + 50 * Math.sin(index * 0.6 + angle)));
          angle += 0.8;
        }
        
        var spline = new THREE.CatmullRomCurve3(points);
        var divisions = Math.round(30 * points.length);
        //colors
        var colors = [];
        var colors2 = [];
        var colors3 = [];

        var colorLerp;
        var colorLerp2; 
        var colorLerp3;
     
        //colorLerp
        for (var i = 0, l = divisions; i < l; i++) {
          var point = spline.getPoint(i / l);
          positions.push(point.x, point.y, point.z);
          //push colors
          var colorEnd = new THREE.Color("rgb(255, 60, 30)");
          var colorStart = new THREE.Color("rgb(255, 78, 13)");
          colorLerp = colorStart.lerp(colorEnd, i * (1 / divisions));
					colors.push( colorLerp.r, colorLerp.g, colorLerp.b );
        }
        //colorLerp2
        for (var i = 0, l = divisions; i < l; i++) {
          //push colors
          var colorEnd = new THREE.Color("rgb(255, 117, 43)");
          var colorStart = new THREE.Color("rgb(255, 146, 13)");
          colorLerp2 = colorStart.lerp(colorEnd, i * (1 / divisions));
					colors2.push( colorLerp2.r, colorLerp2.g, colorLerp2.b );
        }
        //colorLerp3
        for (var i = 0, l = divisions; i < l; i++) {
          //push colors
          var colorEnd = new THREE.Color("rgb(255, 117, 43)");
          var colorStart = new THREE.Color("rgb(255, 255, 255)");
          colorLerp3 = colorStart.lerp(colorEnd, i * (1 / divisions));
					colors3.push( colorLerp3.r, colorLerp3.g, colorLerp3.b );
        }

        //geometrys
        var geometry = new LineGeometry();
        geometry.setPositions(positions);
        geometry.setColors(colors);

        var geometry2 = new LineGeometry();
        geometry2.setPositions(positions);
        geometry2.setColors(colors2);

        var geometry3 = new LineGeometry();
        geometry3.setPositions(positions);
        geometry3.setColors(colors3);

        group = new THREE.Group();
        //materials

        matLine = new LineMaterial({
          opacity: 1,
          color: 0xffffff,
          linewidth: 3, // in pixels
          vertexColors: THREE.VertexColors,
          resolution:  1,
          dashed: false
        });


        matLine2 = new LineMaterial({
          opacity: 1,
          color: 0xffffff,
          linewidth: 3, // in pixels
          vertexColors: THREE.VertexColors,
          //resolution:  1,
          dashed: false
        });

        matLine3 = new LineMaterial({
          opacity: 1,
          color: 0xffffff,
          linewidth: 5, // in pixels
          vertexColors: THREE.VertexColors,
          resolution:  1,
          dashed: false
        });
        console.log(matLine3);
        console.log(geometry3);

        //create lines
        for (var x = 0; x < 10; x++) {
        if (x > -1 && x < 5){
          line = new Line2(geometry, matLine);
          console.log("0 - 5: " + x)
        }
        if (x > 4 && x < 9){
          line = new Line2(geometry2, matLine2);
          console.log("5 - 8: " + x)
        }
        if (x > 8){
          line = new Line2(geometry3, matLine3);
          console.log("8 - 12: " + x)
       }

        line.computeLineDistances();
        line.scale.set(1, 1, 1);
        line.position.x = xInc;
        group.add(line);
        xInc += 4;

      }

        scene.add(group);
        stats = new Stats();
        document.body.appendChild(stats.dom);
      }
      

      //vars


      function animate() {
        requestAnimationFrame(animate);
        stats.update();
        matLine.resolution.set(window.innerWidth, document.documentElement.scrollHeight); // resolution of the viewport
        matLine2.resolution.set(window.innerWidth, document.documentElement.scrollHeight); // resolution of the viewport
        matLine3.resolution.set(window.innerWidth, document.documentElement.scrollHeight); // resolution of the viewport
        renderer.clearDepth(); // important!
        //renderer.render();
        composer.render();
        for (let index = 0; index < scene.children[0].children.length; index++) {
          scene.children[0].children[index].position.x = 2 * Math.sin(index * index / 0.2 + angle);
          scene.children[0].children[index].position.y = 3 * Math.sin(index * index / 0.8 + angle);
          scene.children[0].children[index].position.z = 4 * Math.sin(index * index / 0.3 + angle);
        }
          scene.children[0].rotation.y += 0.003;
          angle += 0.01;
        
      }
      console.log(scene.children[0].children);
      animate();
    </script>
  </body>
</html>

Thanks in advance.

Greetings,

Hobie

An easy way is to check if FPS reaches 60 or instead throttles to 30 (which is doing for me)

A small tip (it will not be a huge improvement): Instead of doing:

scene.children[0].children[index].position.x = ...
scene.children[0].children[index].position.y = ...
scene.children[0].children[index].position.z = ...

You can do:

scene.children[0].children[index].position.set(  ... ,  ... , ... );

Thanks! Ill try that for sure. Still wondering if i´m doing something fundamentally wrong, since I don´t think it should be such a hit on performance. There are examples with 100´s of shapes which run smoothly…

Maybe it would be better to cap FPS at 30.