react-three-fiber: Planet Mars Animation  🚀
Tags: react, javascript, tutorial, webdev
Published: 2020-09-25 13:12:47

*As long as I can remember, I have always been attracted by Space. But then i heard about programming...*

Hy there! Today we will create mars planet using [three.js](https://threejs.org/) and [react-three-fiber](https://inspiring-wiles-b4ffe0.netlify.app/).

[Link to the finished project](https://codesandbox.io/s/react-three-fiber-planet-mars-wm8ov)

### What are three.js and react-three-fiber?
This tutorial is for those who already know the basics of three.js. There i won't go into details since there are already so many introductory guides. Today i want to focus on practise.

But in brief:
1. three.js — it's JavaScript library for creating 3D graphics.
2. react-three-fiber — is a React renderer for three.js on the web and react-native.

### **Here we go!**
First! The structure of our files in this guide:

![files structure](https://res.cloudinary.com/danilnotorious/image/upload/v1601015839/Screenshot_2020-09-25_at_09.31.15_sts8sj.png)

Now let's dwell on the details. In our project, we need to create three main components:  

1. **Sphere** — this will be the planet Mars
2. **SkyBox** — this is our space, we will use `CubeTextureLoader()` to create it. For this component we need to get 6 images for the background of each side of the cube.
3. **CameraControls** — very important component. This will give us the ability to rotate and scale our Sphere (Mars) as we want.

### **Sphere creating**
Let's start with the Sphere component:

````javascript
import React, { useRef } from "react";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { useFrame, useLoader } from "react-three-fiber";

const Sphere = () => {
  const planet = useRef();

  const { nodes } = useLoader(GLTFLoader, "models/mars.glb");

  useFrame(() => (planet.current.rotation.y += 0.0002));

  return (
    <mesh
      ref={planet}
      visible
      position={[0, 0, 0]}
      // Adding data from mars.glb to the geometry and material of the sphere
      geometry={nodes.Cube008.geometry}
      material={nodes.Cube008.material}
    />
  );
};

export default Sphere;
```
We are using a ready-made gltf 3D file that creates the geometry and material for our sphere. We can get it from [the official NASA website](https://solarsystem.nasa.gov/resources/2372/mars-3d-model/). To work with the gltf file we use the [GLTFLoader](https://threejs.org/docs/#examples/en/loaders/GLTFLoader) from three.js and the `useLoader()` hook from react-three-fiber. Also we use the `useFrame()` hook that add rotation for our planet.

### **SkyBox creating**
Notice how SkyBox returns null this is because we will not be creating any new objects with this component in our scene. Instead, we will use it as a controller to set a property in our scene, as we will see in the next step when we load and apply the skybox textures.

```javascript
import { useThree } from "react-three-fiber";
import { CubeTextureLoader } from "three";

// Loads the skybox texture and applies it to the scene.
const SkyBox = () => {
  const { scene } = useThree();
  const loader = new CubeTextureLoader();
  // The CubeTextureLoader load method takes an array of urls representing all 6 sides of the cube.
  const texture = loader.load([
    "/images/front.jpg",
    "/images/back.jpg",
    "/images/top.jpg",
    "/images/bottom.jpg",
    "/images/left.jpg",
    "/images/right.jpg",
  ]);

  // Set the scene background property to the resulting texture.
  scene.background = texture;
  return null;
};

export default SkyBox;

```
To start we need to get a reference of our Three.JS scene and for that we use `useThree()` hook. Then we create an instance of the CubeTextureLoader and then call the load method with an array containing the six URLs of your images. This will return a CubeTexture. The CubeTexture we assign to the global `scene.background` which we get a reference to with `useThree()`, and that's it our skybox is finished.

### **Skybox Textures**
Also important to talk about Skybox textures creating. For this purpose i was using [Spacescape](http://alexcpeterson.com/spacescape/) program. This is a simple space landscape generator. You can use it or create assets in Photoshop or something. 

### **Camera Controls**
And the last thing about camera control. Here we are using [OrbitControls](https://threejs.org/docs/#examples/en/controls/OrbitControls), which allows the camera to rotate around the target.
```javascript
import React, { useRef } from "react";
import { extend, useThree, useFrame } from "react-three-fiber";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

extend({ OrbitControls });

const CameraControls = () => {
  const {
    camera,
    gl: { domElement },
  } = useThree();

  // Ref to the controls, so that we can update them on every frame with useFrame
  const controls = useRef();

  camera.position.z = 999;

  useFrame(() => controls.current.update());

  return (
    <orbitControls
      ref={controls}
      args={[camera, domElement]}
      autoRotate={false}
      enableZoom={false}
    />
  );
};

export default CameraControls;

```

### **Finish**
Now we can use all created components in to the App component:
```javascript
import React, { Suspense } from "react";
import { Canvas } from "react-three-fiber";
import "./styles.css";

import { CameraControls, Sphere, SkyBox } from "./components";

const App = () => {
  return (
    <>
      <Canvas className="canvas">
        <CameraControls />
        <directionalLight intensity={1} />
        <ambientLight intensity={0.6} />
        <Suspense fallback="loading">
          <Sphere />
        </Suspense>
        <SkyBox />
      </Canvas>
    </>
  );
};

export default App;

```
And also add Styles in to styles.css:
```css
* {
  box-sizing: border-box;
}

html,
body,
#root {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}
```
**Well that's all. Thanks for reading =)**