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.