Steps for embedding a dynamic 3D model onto a website with THREE.js

Seeking guidance on integrating animated 3D models onto a webpage using THREE.js. Currently, I have successfully loaded a static 3D model named 'aaa.gltf' with auto rotation and orbit control functionality. However, when trying to load another animated 3D model named "bbb.glb", it fails to display.

Below is the HTML file structure:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <link rel="stylesheet" href="./style.css" />
    <title>Document</title>
  </head>
  <body>
    <div class="scene"></div>
    <script src="./three.min.js"></script>
    <script src="./GLTFLoader.js"></script>
    <script src="./OrbitControls.js"></script>
    <script src="./app.js"></script>
  </body>
</html>

Attached below you'll find the JavaScript setup:

//JavaScript setup

let container;
let camera;
let renderer;
let scene;
let house;
let mixer;

function initialize() {
  container = document.querySelector(".scene");

  //Setting up the scene
  scene = new THREE.Scene();

  const fov = 35;
  const aspect = container.clientWidth / container.clientHeight;
  const near = 0.1;
  const far = 1000;

  //Camera configuration
  camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.set(0, 0, 100);

  const ambient = new THREE.AmbientLight(0x404040, 2);
  scene.add(ambient);

  const light = new THREE.DirectionalLight(0xffffff, 2);
  light.position.set(50, 50, 100);
  scene.add(light);
  
  //Renderer settings
  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
  renderer.setSize(container.clientWidth, container.clientHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  
  controls = new THREE.OrbitControls(camera, renderer.domElement);

  container.appendChild(renderer.domElement);

  const clock = new THREE.Clock();

  //Loading the Model
  let loader = new THREE.GLTFLoader();
  loader.load("./house/bbb.glb", function(gltf) {
    scene.add(gltf.scene);
    house = gltf.scene.children[0];

    mixer = new THREE.AnimationMixer(house);
    mixer.clipAction(gltf.animations[0]).play();

    animate();
  });
}

function animateModel() {
  requestAnimationFrame(animate);

  const delta = clock.getDelta();
  mixer.update(delta);

  house.rotation.z += 0.005;
  renderer.render(scene, camera);
}

initialize();

function updateWindow() {
  camera.aspect = container.clientWidth / container.clientHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(container.clientWidth, container.clientHeight);
}

window.addEventListener("resize", updateWindow);

CSS styling has been applied as follows:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: sans-serif;
  overflow: hidden;
  background: url("https://wallpaperaccess.com/full/1155041.jpg");
}

.scene,
canvas {
  position: absolute;
  width: 100%;
  height: 100%;
}

The change made was updating the source of the 3D model from 'aaa.gltf' to 'bbb.glb' in line 46 of the JavaScript file:

Replaced this

  loader.load("./house/aaa.gltf", function(gltf) {

with this

  loader.load("./house/bbb.glb", function(gltf) {

Attachments for 'aaa.gltf' can be accessed here: https://drive.google.com/file/d/1RCO8iSvYwTZdcTC55EVzJ0rBLl6aZy9L/view?usp=sharing

For 'bbb.glb' check out the link provided: https://drive.google.com/file/d/1fzk7AZl2VHwTvZm0Gl0m-oyaIZUmHyeB/view?usp=sharing

If anyone has insights on resolving this issue, your assistance would be greatly appreciated! Thanks in advance!

Answer №1

Your code lacks the necessary steps to animate the 3D model effectively. Simply loading the model won't play the embedded animations. To accomplish this, you must create an AnimationMixer, select the clip action for the animation, and then update the animation accordingly.

In addition, I included DRACO encoding for the model. Other adjustments such as using THREE.sRGBEncoding to display true colors of the model and reducing brightness due to its intensity were made...

EDIT: COMPLETE PAGE CODE

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: sans-serif;
            overflow: hidden;
        }

        .scene,
        canvas {
            position: absolute;
            width: 100%;
            height: 100%;
        }
    </style>

</head>
<body>
    <div class="scene"></div>
    <script src="https://threejs.org/build/three.min.js"></script>
    <script src="https://threejs.org/examples/js/loaders/GLTFLoader.js"></script>
    <script src="https://threejs.org/examples/js/loaders/DRACOLoader.js"></script>
    <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

    <script>

        //Variables for setup

        let container;
        let camera;
        let renderer;
        let scene;
        let house;
        let mixer;
        const clock = new THREE.Clock();

        function init() {
            container = document.querySelector(".scene");

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

            const fov = 35;
            const aspect = container.clientWidth / container.clientHeight;
            const near = 1;
            const far = 10000;

            //Camera setup
            camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
            camera.position.set(0, 0, 1000);

            const ambient = new THREE.AmbientLight(0x404040, 1);
            scene.add(ambient);

            const light = new THREE.DirectionalLight(0xffffff, 1);
            light.position.set(50, 50, 100);
            scene.add(light);

            //Renderer
            renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
            renderer.setSize(container.clientWidth, container.clientHeight);
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.outputEncoding = THREE.sRGBEncoding;
            container.appendChild(renderer.domElement);

            const controls = new THREE.OrbitControls(camera, renderer.domElement);
            controls.target.set(0, 0.5, 0);
            controls.update();
            controls.enablePan = false;
            controls.enableDamping = true;

            const dracoLoader = new THREE.DRACOLoader();
            dracoLoader.setDecoderPath('https://threejs.org/examples/js/libs/draco/gltf/');

            //Load Model
            let loader = new THREE.GLTFLoader();
            loader.setDRACOLoader(dracoLoader);
            loader.load("./house/bbb.glb", function (gltf) {
                scene.add(gltf.scene);
                house = gltf.scene.children[0];

                mixer = new THREE.AnimationMixer(house);
                mixer.clipAction(gltf.animations[0]).play();

                animate();
            });
        }

        function animate() {
            requestAnimationFrame(animate);

            const delta = clock.getDelta();
            mixer.update(delta);

            house.rotation.z += 0.005;
            renderer.render(scene, camera);
        }

        init();

        function onWindowResize() {
            camera.aspect = container.clientWidth / container.clientHeight;
            camera.updateProjectionMatrix();

            renderer.setSize(container.clientWidth, container.clientHeight);
        }

        window.addEventListener("resize", onWindowResize);

    </script>
</body>
</html>

If these steps are followed, you'll witness the animated features of various objects like trams, cats, and more...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Discontinuing the fieldset tab interface feature from a Dexterity content type

I am looking to modify a condition to prevent the loading of certain javascript code when inserting an object of my content type. The current condition works only when editing the object: <?xml version="1.0"?> <object name="portal_javascripts"> ...

Dynamically load select options using Ajax

I'm a newcomer to javascript and ajax, and I'm working on implementing Ajax to display the current category on my HTML select in a CodeIgniter project. Below is the code snippet: HTML: <select class="form-control" name="category" id="categor ...

find all occurrences except for the last of a pattern in javascript

When considering the patterns below: "profile[foreclosure_defenses_attributes][0][some_text]" "something[something_else_attributes][0][hello_attributes][0][other_stuff]" It is possible to extract the last part by utilizing non-capturing groups: var rege ...

Error: Unable to access the 'classList' property of null in HTMLSpanElement.expand function

Encountering a minor issue with my javascript code. Following a tutorial for a seemingly simple task: link What I did: Adapted the HTML from the tutorial to fit my desired visual outcome while maintaining correct class and id attributes. Utilized identic ...

When utilizing the .populate() method in Mongoose, how can you retrieve and append ObjectIds with extra attributes to an array (which is returned by .populate()) collected from the

When using the .populate() method in Mongoose, how can I retrieve and add ObjectIds with additional properties to an array (returned by .populate()) if their corresponding document in the collection no longer exists? This question pertains to MongoDB and ...

Restricting slash commands in Discord.js to a specific permission level

I'm currently developing a purge command, and I'm struggling to restrict its usage to users with the MANAGE_MESSAGES permission. Below is the source code for the client.on("ready") section as well as the entire command logic. Any assistance on ...

By default, the sidebar is open on desktop devices while closed on mobile devices

I am struggling to figure out how to set my sidebar/navigation content, using Bootstrap, to be expanded by default on desktop and closed by default on mobile with the icon only showing on mobile devices. Despite multiple attempts, I cannot seem to make thi ...

Focus on targeting dynamic IDs such as #event_rules_attributes_0_interval, #event_rules_attributes_1_interval, etc. using CSS3 styling

Styling input tags using their IDs can be very convenient due to the higher precedence weight they hold compared to classes. For instance, I set a default width for input.text elements within a specific container: .details .metadata input.text { width: 2 ...

What is the process of incorporating a select form within a component?

I am currently working on creating a user registration form. Once the form is filled out and the submit button is clicked, I need the values from the form to be displayed in a specific <p id="data></p> component. Can anyone assist me with this ...

Audio issues plaguing audio playback on Discord

After spending two exhausting days, I am still trying to figure out what is going on. I am currently working on a Bot for my Discord Channel that should play an audio.mp3 file when a specific command, like !laugh, is entered. However, despite trying variou ...

Enhance your iPhone web app with high-resolution retina images!

As I develop a mobile web application accessible on any smartphone, I have the index.html file available for review: The app includes 2 jQuery functions. One detects if the user is using an iPhone and displays a bubble with instructions to add it to the h ...

exploring the network of connections

This is what the HTML structure of the webpage looks like: <body> <form> <input type='file'/> </form> <div id='list'> <div>value here<input id='delete' type='button'/>< ...

Is there a glitch in the three.js loadOBJMTL loader?

Encountering an issue with the OBJMTL loader in three.js. I'm working with obj/mtl/jpeg files and getting load errors that look like this: "THREE.OBJMTLLoader: Unhandled line 4033/5601/6659" OBJMTLLoader.js:347 Seems like there is a problem with a c ...

The issue arises when using multiple route files in Route.js, as it hinders the ability to incorporate additional functions within the

After breaking down Route.js into multiple controllers, I'm stuck on why I can't add an extra function to block permissions for viewing the page. // route.js module.exports = function(app, passport) { app.use('/profile&apos ...

"Stay informed with the latest updates on Wordpress through our

I am currently working on creating a static homepage with a newsfeed, but I only want to display the title and date posted. I considered using a widget, but I plan to integrate this news feed with a slideshow in the future and didn't want to limit my ...

Issue with Collapse Feature on Bootstrap 3.x Navbar

The Bootstrap 3 Navbar expands properly in full screen and on a browser with a small width on a desktop PC and mobile browsers, but when using the Toggle navigation button, it doesn't slide down. I have tried to replicate the code from this example: h ...

Tips for effectively implementing an Ajax request with JavaScript when the page loads

I have been developing a shopping cart application that utilizes local storage to store the items added by users. The challenge I'm currently facing is populating the page with the user's cart items stored in local storage when they navigate away ...

Align text to the left and right with a centered div

Visualize the asterisk * at the center of the div textAlignRight * text AlignLeft This is essentially my goal to accomplish <center> <span class="left_host">Right aligned</span> * <span class="righ ...

Text input fields failing to record text

I've set up a forum using react-redux and material ui, but I'm facing an issue where the text fields are not updating based on state changes. When users try to type in the text field, nothing seems to happen. onChange={e => onT ...

Execute a sudo command using an html button

Looking for a way to create a simple website with HTML buttons on my Raspberry Pi that can execute sudo commands. I attempted the following method: <?php if (isset($_POST['button'])) { exec('sudo reboot'); } ?> ...