three.js / meshoptimizer simplification

Example using meshoptimizer to simplify three.js mesh geometry.

by donmccurdy

HTML

<script type="importmap">
	{
		"imports": {
			"three": "https://unpkg.com/three/build/three.module.js",
      "three/addons/": "https://unpkg.com/three/examples/jsm/",
      "meshoptimizer": "https://unpkg.com/meshoptimizer@0.20.0/index.module.js",
      "lil-gui": "https://unpkg.com/lil-gui@0.19.2/dist/lil-gui.esm.js"
		}
	}
</script>

CSS

body {
	margin: 0px;
}

JavaScript

// Simple three.js example

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { MeshoptSimplifier } from 'meshoptimizer';
import { GUI } from 'lil-gui';

const params = { ratio: 1, error: 0.01, lockBorder: true } ;

let mesh, renderer, scene, camera, controls;

let srcGeometry, dstGeometry;

MeshoptSimplifier.ready.then(() => {

  init();
	animate();

});



function init() {

    // renderer
    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setPixelRatio( window.devicePixelRatio );
    document.body.appendChild( renderer.domElement );

    // scene
    scene = new THREE.Scene();
    
    // camera, controls
    camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.set( 20, 20, 20 );
    controls = new OrbitControls( camera, renderer.domElement );
    scene.add( new THREE.AxesHelper( 20 ) );
    
    // geometry
    srcGeometry = new THREE.TorusKnotGeometry( 5, 2.5, 124, 32 );
    dstGeometry = srcGeometry.clone();
    
    // mesh
    mesh = new THREE.Mesh( dstGeometry, new THREE.MeshBasicMaterial( { wireframe: true } ) );
    scene.add( mesh );
    
    // gui
    const gui = new GUI();
    gui.add( params, 'ratio', 0, 1, 0.01 );
    gui.add( params, 'error', 0, 0.25, 0.0001 );
    gui.add( params, 'lockBorder' );
    gui.onChange( simplify );
    
}

function simplify() {

  const srcIndexArray = srcGeometry.index.array;
  const srcPositionArray = srcGeometry.attributes.position.array;
  
	const targetCount = 3 * Math.floor( params.ratio * srcIndexArray.length / 3 );

	const [ dstIndexArray, error ] = MeshoptSimplifier.simplify(
		srcIndexArray,
		srcPositionArray,
		3,
		targetCount,
		params.error,
		params.lockBorder ? [ 'LockBorder' ] : [],
	);
  
  console.log( `targetCount: ${targetCount}, count: ${dstIndexArray.length}` );
  
  dstGeometry.index.array.set(...