How to move my 3D loaded model?

I started with three js recently and I am trying to make a static website with a space theme. I did found a yt video to render bunch of stars and make them move towards the camera and once they go past the camera, they will simply re render. resulting in a cool effect. But I want to add some space shuttles and other 3D models to make it even better, I have loaded a space shuttle model that I want to use but I don’t know how to animate it so that it can create an effect of “floating” in the space.

2023-07-03 18-34-43.mkv (4.2 MB)

This is the current state of my project, and I want the space shuttle model to also go past the camera just like stars and then re render. I am sorry if this sounds dumb, am just starting out. Do lemme know if someone want to have a look at the code.

What I would like to se: some suggestions/ study material on how to tackle this issue.

Movement of your space shuttle can also follow same process that you’ve done for your stars.

What exactly is this “floating effect” and how you intend it to be different than your stars movement? Can you elaborate?

1 Like

Yes it is suppose to be just like stars.

bunch of space shuttle will be rendered randomly and will just travel in a straight path and will re render once they pass the camera pov.

I tried following the same process like the stars. But it’s not really working. I did some searching and found out that I might need to do some basic animation. So I am figuring out the optimal solution for this.

How are you making the stars travel in a path, can you explain? And also, what is the problem you’re facing in case of the shuttle.

You can add the relevant code snippet here.

Maybe you can take procedures from these examples from the collection?

FlightRouteQuaternion
MovingCameraAlongSpline
PoinsForEngines

import * as THREE from './three.js-master/three.js-master/build//three.module.js'
import { GLTFLoader } from './three.js-master/three.js-master/examples/jsm/loaders/GLTFLoader.js'
import { TrackballControls } from './three.js-master/three.js-master/examples/jsm/controls/TrackballControls.js'

let scene, camera, renderer, starGeo, stars;

function init() {
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.z = 10;
    camera.position.x = Math.PI / 2;

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

    starGeo = new THREE.BufferGeometry();
    const vertices = [];
    for (let i = 0; i < 6000; i++) {
        const star = new THREE.Vector3(
            Math.random() * 600 - 300,
            Math.random() * 600 - 300,
            Math.random() * 600 - 300
        );
        star.velocity = 0;
        star.acceleration = 0.02;
        vertices.push(star.x, star.y, star.z);
    }
    starGeo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));

    const sprite = new THREE.TextureLoader().load('/assets/star.jpg');
    const starMaterial = new THREE.PointsMaterial({
        color: 0xaaaaaa,
        size: 0.7,
        map: sprite,
        transparent: true,
        alphaTest: 0.5,
    });

    stars = new THREE.Points(starGeo, starMaterial);
    scene.add(stars);


    const loader = new GLTFLoader();
    loader.load('assets/low_poly_space_shuttle/scene.gltf', function(gltf) {
        console.log(gltf);
        const root = gltf.scene;

        const initialRotation = new THREE.Euler(Math.PI , Math.PI , Math.PI);
        const rotationMatrix = new THREE.Matrix4().makeRotationFromEuler(initialRotation);
        root.applyMatrix4(rotationMatrix);

        root.scale.set(0.001, 0.001, 0.001);

        const textureLoader = new THREE.TextureLoader();
        const texture = textureLoader.load('assets/low_poly_space_shuttle/textures/Material_diffuse.jpeg', function() {
        const material = new THREE.MeshPhongMaterial({ map: texture });
            root.traverse(function(node) {
                if (node.isMesh) {
                    node.material = material;
                }
            });
        });

        scene.add(root);

        const controls = new TrackballControls(camera, renderer.domElement);
        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
        }

        animate();
    }, function(xhr) {
        console.log((xhr.loaded / xhr.total * 100) + "% loaded");
    }, function(error) {
        console.log('An error occurred');
    });
    const light = new THREE.AmbientLight(0xffffff, 1);
    light.position.set(2, 2, 5);
    scene.add(light);

    animate();
}

function animate() {
    starGeo.attributes.position.array.forEach((_, index) => {
        const x = starGeo.attributes.position.array[index * 3];
        const y = starGeo.attributes.position.array[index * 3 + 1];
        const z = starGeo.attributes.position.array[index * 3 + 2];
  
        starGeo.attributes.position.array[index * 3 + 2] += 0.5; // Move towards the camera
        if (z > 300) {
            starGeo.attributes.position.array[index * 3 + 2] = -300; // Reset position once it goes beyond the screen
        }
    });
    starGeo.attributes.position.needsUpdate = true;

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

this is the current state of by code if you want to have a look.

Sure, thanks for sharing.

If you want a simple movement of your space shuttle just like your stars, update your space shuttle’s position in the animate function like your are doing for stars, like so:

let scene, camera, renderer, starGeo, stars, root ; // make root global

function animate() {
    starGeo.attributes.position.array.forEach((_, index) => {
        const x = starGeo.attributes.position.array[index * 3];
        const y = starGeo.attributes.position.array[index * 3 + 1];
        const z = starGeo.attributes.position.array[index * 3 + 2];
  
        starGeo.attributes.position.array[index * 3 + 2] += 0.5; // Move towards the camera
        if (z > 300) {
            starGeo.attributes.position.array[index * 3 + 2] = -300; // Reset position once it goes beyond the screen
        }
    });
    if(root)
        root.position.z += 0.1

    starGeo.attributes.position.needsUpdate = true;

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

Also, instead of checking for root is undefined till it is loaded, better use a loading manager to wait for your space shuttle to load, then start animating.

Thank you very much, It works. I really appreciate your help.

I am trying to clone the 3D models to place them on to the scene and I have added this code, but I am running into some issue,
(1) this code have no effect
(2) but is slowing my program down and making it lag, which suggest it is working but not rendering any models?

for(let i = 0; i < 3000; i++) {
            const shuttle = root.clone();
            shuttle.position.set(
                Math.random() * 600 - 300,
                Math.random() * 600 - 300,
                Math.random() * 600 - 300,
            );
            scene.add(shuttle);
            shuttles.push(shuttle);
        }

added this code block while I loaded the initial model,

shuttles.forEach((shuttle) => {
        shuttle.position.z += 0.001;
        if(shuttle.position.z > 300) {
            shuttle.position.z = -300;
        }
    })

added this code block in my animate function so that it could move the model around while re rendering it once it passes the camera pov.

Try to have larger increments in the Z position of your shuttles like 0.1 instead of 0.001.

That’s not the case because I have already tried doing that.

Update: once I reduced the amount of 3D models to be rendered to 10 from 3000 it stopped lagging. So, there has to be some process running in the background that is not letting the cloned models to render. Also it’s not showing any warnings in the console as well.

That should run perfectly fine, may be there’s something in your code that you messed up. Can you update your latest code maybe…

import * as THREE from './three.js-master/three.js-master/build//three.module.js'
import { GLTFLoader } from './three.js-master/three.js-master/examples/jsm/loaders/GLTFLoader.js'
import { TrackballControls } from './three.js-master/three.js-master/examples/jsm/controls/TrackballControls.js'

let scene, camera, renderer, starGeo, stars, root, shuttles = [];

function init() {
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.z = 10;
    camera.position.x = Math.PI / 2;

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

    starGeo = new THREE.BufferGeometry();
    const vertices = [];
    for (let i = 0; i < 6000; i++) {
        const star = new THREE.Vector3(
            Math.random() * 600 - 300,
            Math.random() * 600 - 300,
            Math.random() * 600 - 300
        );
        star.velocity = 0;
        star.acceleration = 0.02;
        vertices.push(star.x, star.y, star.z);
    }
    starGeo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));

    const sprite = new THREE.TextureLoader().load('/assets/star.jpg');
    const starMaterial = new THREE.PointsMaterial({
        color: 0xaaaaaa,
        size: 0.7,
        map: sprite,
        transparent: true,
        alphaTest: 0.5,
    });

    stars = new THREE.Points(starGeo, starMaterial);
    scene.add(stars);


    const loader = new GLTFLoader();
    loader.load('assets/low_poly_space_shuttle/scene.gltf', function(gltf) {
        console.log(gltf);
        root = gltf.scene;

        root.scale.set(0.001, 0.001, 0.001);

        const textureLoader = new THREE.TextureLoader();
        const texture = textureLoader.load('assets/low_poly_space_shuttle/textures/Material_diffuse.jpeg', function() {
            const material = new THREE.MeshPhongMaterial({ map: texture });
            root.traverse(function(node) {
                if (node.isMesh) {
                    node.material = material;
                }
            });
        });

        // ***************** Expiremental (should render multiple 3D models, but doesnt) 
        // When you do i < 3000 (some big number) it will start lagging. That means that some process is running in the background but the cloned models are not getting rendered. 

        for(let i = 0; i < 10; i++) {
            const shuttle = root.clone();
            shuttle.position.set(
                Math.random() * 600 - 300,
                Math.random() * 600 - 300,
                Math.random() * 600 - 300,
            );
            scene.add(shuttle);
            shuttles.push(shuttle);
        }
        // *****************


        scene.add(root);

        // const controls = new TrackballControls(camera, renderer.domElement);
        // function animate() {
        //     requestAnimationFrame(animate);
        //     controls.update();
        //     renderer.render(scene, camera);
        // }
        
        animate();
    }, function(xhr) {
        console.log((xhr.loaded / xhr.total * 100) + "% loaded");
    }, function(error) {
        console.log('An error occurred');
    });
    const light = new THREE.AmbientLight(0xffffff, 1);
    light.position.set(2, 2, 5);
    scene.add(light);

    animate();
}

function animate() {
    starGeo.attributes.position.array.forEach((_, index) => {
        const x = starGeo.attributes.position.array[index * 3];
        const y = starGeo.attributes.position.array[index * 3 + 1];
        const z = starGeo.attributes.position.array[index * 3 + 2];
  
        starGeo.attributes.position.array[index * 3 + 2] += 1.0; // Move towards the camera
        if (z > 300) {
            starGeo.attributes.position.array[index * 3 + 2] = -300; // Reset position once it goes beyond the screen
        }
    });
    starGeo.attributes.position.needsUpdate = true;

    // makes the loaded model move in a straight line. 
    if(root != undefined) {
        root.position.z += 0.05;
    }

    // added as an expirement(should work, but dosent)
    shuttles.forEach((shuttle) => {
        // shuttle.position.z += 1;
        if(root != undefined) {
            shuttle.position.z += 0.05;
        }
        if(shuttle.position.z > 300) {
            shuttle.position.z = -300;
        }
    })

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

Hey, thanks for your response. This is the current state of my code.

This works fine without any issues, maybe check your model or textures are correct…
You can try to replicate the problem on codepen or stackbiltz.