I am currently working on a project using Three.js where I’m facing performance issues when using the Three.js CSG library on two BufferGeometries. The scenario involves creating two independent geometries, object_1
and object_2
, using the renderSVG
function. The goal is to perform a CSG operation between these two geometries.
The issue arises when using object_2
alongside object_1
. As soon as object_2
is introduced, the performance degrades significantly and the software becomes unmanageable. Any insights or suggestions on optimizing the performance and resolving this problem would be greatly appreciated!
Here is the code:
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: SUBTRACTION,
};
init();
async function init() {
// create the scene and set a background color
scene = new THREE.Scene();
scene.background = new THREE.Color( "#dadada" );
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: true } );
renderer.setSize(modelViewerWidth, modelViewerHeight);
renderer.setPixelRatio( window.devicePixelRatio );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// add the renderer to the modelViewer element
document.getElementById("modelViewer").appendChild( renderer.domElement );
// add the gridHelper to show orientation
const gridHelper = new THREE.GridHelper( 100, 100 );
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(0.05),
new THREE.MeshBasicMaterial({ color: "#ff0000" })
);
brush2 = new Brush(
renderSVG(0.05),
new THREE.MeshBasicMaterial({ color: "#ff0000" })
);
result = new THREE.Mesh();
result.material.color.set("#004D9A");
scene.add( result );
render()
}
function renderSVG(size) {
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(size, size, 0.1);
}
);
return bufferGeometry;
}
function render() {
requestAnimationFrame( render );
result = csgEvaluator.evaluate(brush1, brush2, params.operation, result);
result.castShadow = true;
result.receiveShadow = true;
renderer.render(scene, camera);
}
Thank you!