Search code examples
javascriptthree.js

Meshes overlapping with sin() and cos() animation


I'm new to JavaScript and Three.js, nice to meet all of you !

This code is for creating 4 cubes and one arrow. Like this image:

Image1

// Scene
const scene = new THREE.Scene();

// Groups
const cubes = new THREE.Group();

// Ambient Light
const light = new THREE.AmbientLight(0xffffff, 1);
scene.add(light)

// Reference Circle or Path
const circle = new THREE.CircleGeometry(5, 100)
const circlePath = new THREE.Path()
const stroke = new THREE.LineBasicMaterial({color : 'white'})
const ref = new THREE.Line(circle, stroke)
scene.add(ref)

// Mesh 
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshBasicMaterial({ color: 'red' })
const mesh = new THREE.Mesh(geometry, material)

// Mesh 2  
const geometry2 = new THREE.BoxGeometry(1, 1, 1)
const material2 = new THREE.MeshBasicMaterial({ color: 'blue' })
const mesh2 = new THREE.Mesh(geometry2, material2)

// // Mesh 3 
const geometry3 = new THREE.BoxGeometry(1, 1, 1)
const material3 = new THREE.MeshBasicMaterial({ color: 'green' })
const mesh3 = new THREE.Mesh(geometry3, material3)

// // Mesh 4 
const geometry4 = new THREE.BoxGeometry(1, 1, 1)
const material4 = new THREE.MeshBasicMaterial({ color: 'purple' })
const mesh4 = new THREE.Mesh(geometry4, material4)

// Mesh 5 Arrow
const geometry5 = new THREE.ConeGeometry(1, 4, 3)
const material5 = new THREE.MeshBasicMaterial({ color: 'yellow' })
const arrow = new THREE.Mesh(geometry5, material5)

scene.add(mesh, mesh2, mesh3, mesh4, arrow)


const axesHelper = new THREE.AxesHelper();
scene.add(axesHelper)

// Camera

const aspect = {
    width: window.innerWidth,
    height: window.innerHeight
}

const camera = new THREE.PerspectiveCamera(75, aspect.width / aspect.height)
camera.position.x = -0.15;
camera.position.z = 10;

scene.add(camera)

// Renderer 
const canvas = document.querySelector('.draw')
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setSize(aspect.width, aspect.height)
renderer.render(scene, camera)

const clock = new THREE.Clock();

const animate = () => {
    const time = clock.getElapsedTime()
    console.log(time);
    const a = time;
    let px;
    let pz;
    let r = 5;

    px = r * Math.cos(a);
    pz = r * Math.sin(a);

    mesh.position.set(px, pz, 0);
    mesh.rotation.x = time * Math.PI * 0.1;
    mesh.rotation.y = time * Math.PI * 0.3;

    mesh2.position.set(px, pz, 0);
    mesh2.rotation.x = time * Math.PI * 0.1;
    mesh2.rotation.y = time * Math.PI * 0.3;
    
    mesh3.position.set(px2, pz, 0);
    mesh3.rotation.x = time * Math.PI * 0.1;
    mesh3.rotation.y = time * Math.PI * 0.3;

    mesh4.position.set(px, pz, 0);
    mesh4.rotation.x = time * Math.PI * 0.1;
    mesh4.rotation.y = time * Math.PI * 0.3;

    arrow.rotation.y = time * Math.PI * 0.7;

    renderer.render(scene, camera)
    window.requestAnimationFrame(animate)
}
animate();

The problem I'm having is that when the animate() loop starts, I have all my geometry overlapped like this:

Image2

Do you have any suggestions on what could solve the overlapping ? Like doing some kind of delay maybe, not sure how to apply it.

What I understood was to create 4 loops for each cube. May be possible I'm not understanding correctly because when the program is running, I get: Image1.

Any suggestions on what could be done to make a delay for each mesh to avoid overlapping ?

Thanks for your time. :)


Solution

  • I've fixed your code:

    • I've fixed the typo with px2.
    • I've moved every object on the circle with r * Math.cos(time + Math.PI / 2 * idx) and r * Math.sin(time + Math.PI / 2 * idx).
    • I've removed unnecessary variables.
    • I've added arrays and loops to reduce code duplication.

    All objects had the same position and rotation.

    // Scene
    const scene = new THREE.Scene();
    
    // Ambient Light
    const light = new THREE.AmbientLight(0xffffff, 1);
    scene.add(light);
    
    // Reference Circle or Path
    const circle = new THREE.CircleGeometry(5, 100);
    const stroke = new THREE.LineBasicMaterial({color : 'white'});
    const ref = new THREE.Line(circle, stroke);
    scene.add(ref);
    
    // Meshes
    const meshes = [
        new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 'red' })),
        new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 'blue' })),
        new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 'green' })),
        new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 'purple' })),
    ];
    const arrow = new THREE.Mesh(new THREE.ConeGeometry(1, 4, 3), new THREE.MeshBasicMaterial({ color: 'yellow' }));
    scene.add(...meshes, arrow);
    
    
    const axesHelper = new THREE.AxesHelper();
    scene.add(axesHelper);
    
    // Camera
    
    const aspect = {
        width: window.innerWidth,
        height: window.innerHeight
    };
    
    const camera = new THREE.PerspectiveCamera(75, aspect.width / aspect.height);
    camera.position.x = -0.15;
    camera.position.z = 10;
    
    scene.add(camera);
    
    // Renderer 
    const canvas = document.querySelector('.draw');
    const renderer = new THREE.WebGLRenderer({ canvas });
    renderer.setSize(aspect.width, aspect.height);
    renderer.render(scene, camera);
    
    const clock = new THREE.Clock();
    
    const animate = () => {
        const time = clock.getElapsedTime();
        console.log(time);
        let r = 5;
    
        meshes.forEach((mesh, idx) => {
            mesh.position.set(r * Math.cos(time + Math.PI / 2 * idx), r * Math.sin(time + Math.PI / 2 * idx), 0);
            mesh.rotation.x = time * Math.PI * 0.1;
            mesh.rotation.y = time * Math.PI * 0.3;
        });
        arrow.rotation.y = time * Math.PI * 0.7;
    
        renderer.render(scene, camera);
        window.requestAnimationFrame(animate);
    }
    animate();