Three.js performance issues using SVGLoader

58 Views Asked by At

I use the SVG loader to extrude a 3D object and then make a brush out of it using the Three CSG. But this causes alot of lag and performance issues and I think this is because of the post processing. What is the problem with my code structure?

import * as THREE from 'three';
import { SUBTRACTION, INTERSECTION, ADDITION, Brush, Evaluator } from 'three-bvh-csg';

import { SVGLoader } from 'three/addons/loaders/SVGLoader';
import { OrbitControls } from 'three/addons/controls/OrbitControls';

const loader = new SVGLoader();


let renderer, camera, scene;
let brush1, brush2, result;

const modelViewerWidth = (window.innerWidth / 4) * 3;
const modelViewerHeight = window.innerHeight;

let csgEvaluator = new Evaluator();
csgEvaluator.attributes = [ 'position', 'normal' ];
csgEvaluator.useGroups = false;

const params = {
    displayBrush: true,
    operation: ADDITION,
};

start();
init();

async function init() {

    // create the scene and set a background color
    scene = new THREE.Scene();
    scene.background = new THREE.Color( "#dadada" );

    // set up the camera, its position and rotation
    camera = new THREE.PerspectiveCamera( 50, modelViewerWidth/modelViewerHeight, 1, 100 );
    camera.position.set(0, 15, 20);
    camera.rotation.x = Math.PI * -0.2;

 
    // set up the renderer and the size of the model viewer
    renderer = new THREE.WebGLRenderer ( { antialias: false } );
    renderer.setSize(modelViewerWidth, modelViewerHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.shadowMap.enabled = false;

    // add the renderer to the modelViewer element 
    document.getElementById("modelViewer").appendChild( renderer.domElement );

    // add the gridHelper to show orientation 
    const gridHelper = new THREE.GridHelper( 20, 20 );
    scene.add(gridHelper);

    // add the grid axis
    const axesHelper = new THREE.AxesHelper( 3 );
    axesHelper.position.set(-10, 0, -10);
    scene.add(axesHelper);

    // add controls to enable the user to view the model from different angles
    const controls = new OrbitControls( camera, renderer.domElement );

    brush1 = new Brush(
        renderSVG(),
        new THREE.MeshBasicMaterial({ color: "#ff0000" })

    );
    
    brush2 = new Brush(
        renderSVG(),
        new THREE.MeshBasicMaterial({ color: "#ff0000" })
    );
    
    result = new THREE.Mesh();
    scene.add( result );
    render()

}

    
function renderSVG() {
    let bufferGeometry = new THREE.BufferGeometry();

    const positions = [];
    const normals = [];

    loader.load(
        'Merry Christmas.svg',
        function (data) {
            const paths = data.paths;

            for (let i = 0; i < paths.length; i++) {
                const path = paths[i];
                const shapes = path.toShapes(true);
                const extrudeSettings = {
                    depth: 20,
                    bevelEnabled: false,
                };

                for (let j = 0; j < shapes.length; j++) {
                    const shape = shapes[j];
                    const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);

                    // Extract data from geometry and add it to the arrays
                    const vertices = geometry.getAttribute('position').array;
                    const vertexCount = vertices.length / 3;

                    for (let k = 0; k < vertexCount; k++) {
                        positions.push(vertices[k * 3], vertices[k * 3 + 1], vertices[k * 3 + 2]);
                        normals.push(0, 0, 1);
                    }
                }
            }

            // Set attributes to bufferGeometry
            bufferGeometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
            bufferGeometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));

            // Optional: Scale or transform the bufferGeometry if needed
            bufferGeometry.scale(0.02, 0.02, 0.02);
        }
    );

    return bufferGeometry;
}


function render() {
    setTimeout(() => {

        requestAnimationFrame( render );


    }, 1000 / 30 );

        // Update the scene every updateFrequency frames
        if (params.operation === -1) {
            result.geometry.dispose();
            result.geometry.copy(brush1.geometry);
        } else {
            result = csgEvaluator.evaluate(brush1, brush2, params.operation, result);
        }

    renderer.render(scene, camera);

   
    
}


I tried to tweak with the renderer and adding intervals, but that did not do the job. Should I call the SVGLoader get an object and then use that through out the entire run. How would I accomplish that?

0

There are 0 best solutions below