Skip to content

RESOURCES / BLOG

Generating 360 gifs from 3D Models

As we transition into the world of augmented and virtual reality, we will see normal applications interact with 3D models and animations everywhere. Let us learn how we can generate a 360 degree animated image from a 3D model with Nuxt.Js

The final project can be viewed on Codesandbox.

You can find the full source code on my Github repository.

We will be using Nuxt.Js in this project. It is a performance and easy-to-use Vue.Js framework. To get started, ensure you have either Yarn or NPM v5.1+ or v6.2+ installed. Open your directory of choice and run the following command in the terminal.

yarn create nuxt-app nuxtjs-3d-model-to-360-gif
# OR
npm init nuxt-app nuxtjs-3d-model-to-360-gif
# OR
npx create-nuxt-app nuxtjs-3d-model-to-360-gif
Code language: PHP (php)

The above command will trigger a set of setup questions. Here are our recommended defaults:

Project name: uxtjs-3d-model-to-360-gif Programming language: JavaScript Package manager: Yarn UI framework: Tailwind CSS Nuxt.js modules: N/A Linting tools: N/A Testing framework: None Rendering mode: Universal (SSR/SSG) Deployment target: Server (Node.js hosting) Development tools: N/A

Once the setup is complete, you may enter and run your project. The app will be accessible through the URL https://localhost:3000.

cd nuxtjs-3d-model-to-360-gif

yarn dev
# OR
npm run dev
Code language: PHP (php)

Cloudinary is a media management platform that enables us to make the most of our media assets. This is through its comprehensive set of APIs and SDKs. Let us install the recommended Nuxt.Js plugin, @nuxtjs/cloudinary.

Open the terminal in your project folder to add the dependency:

yarn add @nuxtjs/cloudinary
# or
npm install @nuxtjs/cloudinary
Code language: CSS (css)

Once installation is complete, add the module in the modules section of the nuxt.config.js file:

// nuxt.config.js
export default {
    ...
    modules: [
        '@nuxtjs/cloudinary'
    ]
    ...
}
Code language: JavaScript (javascript)

We will then configure our Cloudinary instance by adding a cloudinary section to the nuxt.config.js file:

// nuxt.config.js
export default {
    ...
    cloudinary: {
        cloudName: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
        useComponent: true,
        secure: true
    }
    }
Code language: JavaScript (javascript)

Environmental variables as values that are not dependent on our code itself but on the environment in which the code is executed. In the above piece of code, we refer to the NUXT_ENV_CLOUDINARY_CLOUD_NAME environmental variable.

To set it up, let’s first create the .env file which will contain our environmental variables:

touch .env
Code language: CSS (css)

We will then set our environmental variables in the file

NUXT_ENV_CLOUDINARY_CLOUD_NAME=<secret-cloud-name>
Code language: HTML, XML (xml)

We will be uploading our 3D models just as we upload images. Cloudinary currently only supports the following file formats: .glb, .gltz, and .fbxz.

First, we create a simple HTML form.

<!-- pages/index.vue -->
<template>
    ...
    <form @submit.prevent="upload">
        <input 
            @change="handleFile"
            id="model" 
            name="model" 
            type="file" 
            accept=".glb, .gltz, .fbxz"
            required 
                    />
        <p v-if="uploading">Uploading...</p>
        <button
            v-else
            type="submit"
        >
        Upload
        </button>
    </form>
    ...
</template>
Code language: HTML, XML (xml)

This will trigger the handleFile method when a file is selected and the upload method when the form is submitted.

// pages/index.vue
export default {
    data() {
        return {
            model: null,
            uploading: false,
            display: null ,
        };
    },
    ...
    methods: {
        async handleFile(e) {
            this.model = e.target.files[0];
        },
        async readData(f) {
            return new Promise((resolve) => {
                const reader = new FileReader();
                reader.onloadend = () => resolve(reader.result);
                reader.readAsDataURL(f);
            });
        },
        async upload() {
            this.uploading = true;
            const modelData = await this.readData(this.model);
            const cloudinaryModel = await this.$cloudinary.upload(modelData, {
                upload_preset: "default-preset",
                folder: "nuxtjs-3d-model-to-360",
            });
            this.display = {
                publicId: cloudinaryModel.public_id
            }
            this.uploading = false;
        },
    },
};
Code language: JavaScript (javascript)

handleFile stores the selected file in the page state. When upload is triggered, readData reads the file data and returns it to the upload method which uploads the model to Cloudinary.

Once the upload is complete, the models public_id in Cloudinary is stored in the display page variable. This variable will hold the public_id of the model we will be displaying.

During upload, we refer to the default-preset upload preset. This is a set of instructions we configure to be applied to our file uploads. You can add one on the create upload preset page. Here are our recommended defaults:

Name: default-preset Mode: unsigned Unique filename: true Delivery type: upload Access mode: public

We want the users of our app to be able to preview 360 degree GIFs of pre-loaded 3D models. This is so that they don’t have to look for 3D models if they already don’t have some. To get started, upload the following 3D models into your Cloudinary dashboard in a folder named nuxtjs-3d-model-to-360.

The resultant folder should look similar to this:

Sample models

Let us store these samples in our page state. We will include the credits as we downloaded the models from additional sources.

// pages/index.vue
<script>
export default {
  name: 'IndexPage',
  data(){
    return {
      ...
      samples:[
        {
          name: "Cloudinary logo",
          credit: "Cloudinary logo by Cloudinary",
          publicId: 'nuxtjs-3d-model-to-360/CldLogo3D',
        },
        {
          name:"18th century oilсan",
          credit: "18th century oilсan (https://skfb.ly/oqKtP) by motionpix is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).",
          publicId:"nuxtjs-3d-model-to-360/OilCan",
        },
        {
          name:"Pencil",
          credit: "Pencil (https://skfb.ly/o7GUU) by jackie glade is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).",
          publicId:"nuxtjs-3d-model-to-360/pencil",
        }
      ]
    };
  },
}
Code language: HTML, XML (xml)

We now need to allow the user to select a model. We can do this by adding buttons underneath the upload form.

<!-- pages/index.vue -->
<template>
    ...
    <div
        v-for="sample in samples"
        :key="sample.publicId"
    >
        <button @click="display=sample">
            <span>{{sample.name</span>
        </button>
    </div>
    ...
</template>
Code language: HTML, XML (xml)

To render the 360-degree GIFS, we use the cld-image componenent. We load up the public-id of the model we want to use. We use transformations to:

  • animate it as a GIF with a 10-second delay
  • limit the height and weight ensuring if fills the container
  • add a background color so that the model is easily visible.

We only do this when display is actually set.

<!-- pages/index.vue -->
<template>
    ...
        <div v-if="display" >
            <cld-image
                :alt="`${display.name} loading`" :public-id="display.publicId"
            >
                <cld-transformation
                    delay="10" 
                    flags="animated" 
                    fetch-format="gif"
                >
                </cld-transformation>
                <cld-transformation 
                    height="200" 
                    width="400" 
                    crop="fill"
                >
                </cld-transformation>
                <cld-transformation
                    background="#3448C5"
                >
                </cld-transformation>
            </cld-image>
            <p>
                {{ display.credit }}
            </p>
        </div>
      ...
</template>
Code language: HTML, XML (xml)

With the above we have uploaded 3D models, preloaded others and rendered the selected model into a 360 degree GIF. There is more that we can achieve with the Cloudinary platform and toolset. Feel free to review the extensive documentation here.

Start Using Cloudinary

Sign up for our free plan and start creating stunning visual experiences in minutes.

Sign Up for Free