Home > Back-end >  How to change the size of a 2D circle using lil gui with THREE.js?
How to change the size of a 2D circle using lil gui with THREE.js?

Time:10-19

I want to change the size of a circle as I drag a lil gui slider. I have this code, which draws a circle with a blue line in a black screen, with an ortographic camera:

    initGUI();
    let radius = 0.6;
    let vertices = [];
    for(let i = 0; i <= 360; i  ){
        vertices.push(new THREE.Vector3(Math.sin(i*(Math.PI/180))*radius, Math.cos(i*(Math.PI/180))*radius, 0));
    }

    let geometry = new THREE.BufferGeometry().setFromPoints(vertices);

    let material = new THREE.LineBasicMaterial({color:"blue"})
    var lineStrip = new THREE.Line( geometry, material );

I also have this initGUI() function, which makes a slide that changes the value of controls.radius

function initGUI() {

    controls =  {   radius  : 0.6
                };

    gui.add( controls, 'radius', 0.1, 0.7).onChange(value => changeRadius(value));
    gui.open();
};

the onChange method sends the new values of the radius to the function changeRadius, which is:

function changeRadius(value) {
    radius = value;
    var vertices = [];
    for(let i = 0; i <= 360; i  ){
        vertices.push(new THREE.Vector3(Math.sin(i*(Math.PI/180))*radius, Math.cos(i*(Math.PI/180))*radius, 0));
    }
    renderer.clear();
    renderer.render(scene, camera);
}

this doesn't work, though. It produces the error "renderer is not defined". I tried to pass the renderer as the function parameter, then it gave something similar to "scene and camera are not defined", then I also set scene and camera as parameters of the function and no errors were produced, but the circle didn't change its size.

CodePudding user response:

Alternatively to what @prisoner849 suggested (meaning creating the circle with a radius of 1 and then just scale it), you can use the below code snippet to update the geometry. I guess that is what you have originally in mind.

import * as THREE from 'three';

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

let camera, scene, renderer;

let lineStrip;

const params = {
    radius: 0.6
};

init();
render();

function init() {

    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
    camera.position.z = 1;

    scene = new THREE.Scene();

    const radius = params.radius;
    const vertices = [];

    for ( let i = 0; i <= 360; i    ) {

        vertices.push( new THREE.Vector3( Math.sin( i * ( Math.PI / 180 ) ) * radius, Math.cos( i * ( Math.PI / 180 ) ) * radius, 0 ) );

    }

    const geometry = new THREE.BufferGeometry().setFromPoints( vertices );
    const material = new THREE.LineBasicMaterial( { color: 'blue' } );

    lineStrip = new THREE.Line( geometry, material );
    scene.add( lineStrip );

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    const gui = new GUI( { width: 300 } );

    gui.add( params, 'radius', 0.1, 2 ).onChange( changeRadius );
    gui.open();

}

function render() {

    renderer.render( scene, camera );

}

function changeRadius() {

    const positionAttribute = lineStrip.geometry.getAttribute( 'position' );
    const radius = params.radius;

    for ( let i = 0; i <= 360; i    ) {

        const x = Math.sin( i * ( Math.PI / 180 ) ) * radius;
        const y = Math.cos( i * ( Math.PI / 180 ) ) * radius;
        const z = 0;

        positionAttribute.setXYZ( i, x, y, z );

    }

    positionAttribute.needsUpdate = true;

    render();

}

Notice how it's not sufficient to update the vertices array. You have to update the buffer attribute instead.

  • Related