DEV Community

Cover image for Adding motion to 3D models with Framer Motion and Three.js
Daichi Izushi
Daichi Izushi

Posted on

Adding motion to 3D models with Framer Motion and Three.js

Libraries

Framer Motion

Framer Motion is an animation library for React. The declarative aspect of the library is in line with the React philosophy, making it very comfortable to use. You can see an example in the official documentation below, you can control complex animations with a simple description.

Documentation | Framer for Developers

An open source, production-ready motion library for React on the web.

favicon framer.com

React Three Fiber

A library that enables Three.js to be used as a React component, providing the basic functionality of Three.js as a React component.

Introduction - React Three Fiber

React-three-fiber is a React renderer for three.js.

favicon r3f.docs.pmnd.rs

Drei

This helper library for React Three Fiber provides useful components and hooks to make Three.js easier to use with React. This makes building 3D scenes easier and improves code readability and maintainability.

Introduction - Drei

Useful helpers for @react-three/fiber

favicon drei.docs.pmnd.rs

Library Installation

Framer Motion

npm install framer-motion
Enter fullscreen mode Exit fullscreen mode

React Three Fiber

npm install @react-three/fiber
Enter fullscreen mode Exit fullscreen mode

Drei

npm install @react-three/drei
Enter fullscreen mode Exit fullscreen mode

Introduction of 3D model

Saving 3D Model Files

First, download a 3D model of your choice from Sketchfab, etc., and save the gltf and bin files under /src/assets/models in your React application.

GLTF model loading

url
property specifying the path to the directory where the 3D model was placed earlier

useGLTF hook
Loads a 3D model in GLTF format asynchronously from the path of the directory where the 3D model was placed

import { Canvas } from '@react-three/fiber';
import { useGLTF } from '@react-three/drei';

const Model = ({ url }: { url: string; }) => {
  const { scene } = useGLTF(url);

  return (
    <group>
      <primitive object={scene} />
    </group>
  );
};

const ThreeModel = () => {
  return (
    <div>
      <Canvas>
        <Model url="/src/assets/models/scene.gltf"/>
      </Canvas>
    </div>
  );
};

export default ThreeModel;
Enter fullscreen mode Exit fullscreen mode

Rendering the model

The loaded GLTF Model scene object is used within the primitive component and added to the scene in Three.js.

Image description

Manipulation of 3D models

Brightness adjustment of 3D model

ambientLight
Light up the 3D model

const ThreeModel = () => {
  return (
    <div>
      <Canvas>
        <ambientLight intensity={3}/>
...
      </Canvas>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Image description

Adjust the size, position, and tilt of the 3D model

Added scale, position, and rotation properties to the Model component.

scale
Property specifying the size of the model

position
Property that specifies the position of the model. In array format, each element represents a position relative to the x, y, and z axes.

  • 1st value of array: 0 (position along x-axis)
  • 2nd value of array: -1.2 (position along y-axis)
  • 3rd value of array: 1 (position along z-axis)
import { Canvas } from '@react-three/fiber';
import { useGLTF } from '@react-three/drei';

const Model = ({
  url,
  scale,
  position,
  rotation
}: {
  url: string;
  scale: number;
  position: number[];
  rotation: number[];
}) => {
  const { scene } = useGLTF(url);

  return (
    <group>
      <primitive
      object={scene}
      scale={scale} 
      position={position}
      rotation={rotation} />
    </group>
  );
};

const ThreeModel = () => {
  return (
    <div
    className='w-full h-[700px]'>
      <Canvas>
        <ambientLight intensity={3}/>
        <Model
        url="/src/assets/models/scene.gltf"
        scale={0.8}
        position={[0, -1.2, 1]}
        rotation={[Math.PI / 7, -Math.PI / 10, 0]} />
      </Canvas>
    </div>
  );
};

export default ThreeModel;
Enter fullscreen mode Exit fullscreen mode

Image description

Adjust camera position and field of view

camara property
The object that specifies Three.js camera settings

position
Specifies the camera position. Array format, with each element representing a position relative to the x, y, and z axes.

fov
Specify the camera’s field of view

import { Canvas } from '@react-three/fiber';
...
<Canvas camera={{ position: [0, 0, 15], fov: 30 }}>
Enter fullscreen mode Exit fullscreen mode

Image description

Add wave motion to the 3D model

Within the useFrame hook, the y-coordinate of the group is periodically varied using sine waves to achieve an animation of the 3D model moving up and down.

useRef
Create a reference to the group element using the useRef hook. This reference is used to access DOM elements and Three.js objects.

import { useRef } from 'react';
...
const groupRef = useRef(null);
Enter fullscreen mode Exit fullscreen mode

Rendering of group element

group element
Corresponds to the Group object in Three.js. This element is used to manipulate multiple objects together.

ref={groupRef}
A reference to this group element is set to groupRef.

return (
  <group ref={groupRef}>
    <primitive object={scene} scale={scale} position={position} rotation={rotation} />
  </group>
);
Enter fullscreen mode Exit fullscreen mode

Animation loop processing

useFrame
React Three Fiber hook, used to hook into the Three.js rendering loop for animation and frame-by-frame updates.

Math.sin(state.clock.elapsedTime)
Generate a sine wave based on the elapsed time in seconds since the animation started

groupRef.current.position.y
By setting the result multiplied by the sine wave value, the y-coordinate of group will fluctuate up and down. In this case, the amplitude is set to 0.25.

import { useFrame } from '@react-three/fiber';
...
useFrame((state) => {
  if (groupRef.current) {
    groupRef.current.position.y = Math.sin(state.clock.elapsedTime) * 0.25;
  }
});
Enter fullscreen mode Exit fullscreen mode

Image description

Move 3D model with mouse operation

OrbitControls
Control the camera to rotate, translate, and zoom in and out around a central point. Easily available in React Three Fiber using a helper library drei.

enableZoom property
Disable the zoom function by setting it to false.

import { OrbitControls} from '@react-three/drei';
...
const ThreeModel = () => {
  return (
    <div
    className='w-full h-[700px]'>
      <Canvas camera={{ position: [0, 0, 15], fov: 30 }}>
...
        <OrbitControls enableZoom={false} />
      </Canvas>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Image description

Add animation to 3D model with Framer motion

motion.div is a component for adding animation using the Framer Motion library. motion.div works like a normal div element, but allows you to add animation settings.

Properties of motion.div

initial
Specify the initial state of the animation. In this case, x: 100 and opacity: 0 are specified.

animate
Specify the final state of the animation. In this case, x: 0 and opacity: 1 are specified.

transition
Specify settings for animation transitions

  • type: 'spring'
    The spring type simulates the movement of a physical spring and provides animation with a natural damping effect.

  • duration
    Specifies the duration of the transition in seconds.
    However, if type: ‘spring’ is specified, stiffness and damping have priority.

  • delay
    Specify the delay in seconds before the transition starts. In this case, the animation starts 0.9 seconds later.

  • stiffness
    Specifies the hardness of the stiffness of the spring. The higher the value, the stiffer the spring and the faster the animation.

import { motion } from 'framer-motion';
...
const ThreeModel = () => {
  return (
    <motion.div
      initial={{ y: -100, opacity: 0 }}
      animate={{ y: 0, opacity: 1 }}
      transition={{
        type: 'spring',
        duration: 0,
        delay: 0.9,
        stiffness: 200,
      }}
    className='w-full h-[700px]'>
...
    </motion.div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Image description

Conclusion

How to add animation effects to a 3D model using Framer Motion
,React three fiber and Drei make it easy to build interactive and visually appealing web applications.Use it to make your website more attractive!

Top comments (1)

Collapse
 
dark_coder_vibes profile image
Dark Coder

threejs is cool.