Learn React VR (Chapter 5 | Star Wars Modeling)

Prerequisites

Chapter 1 | Hello Virtual World
Chapter 2 | Panoramic Road Trip
Chapter 3 | Outdoor Movie Theater
Chapter 4 | Transitions and Animations

Browser Note

At the time this chapter was released, Mozilla Nightly started having all sorts of issues rendering my VR apps. I have switched to using an experimental build of Chrome. You can learn more about that here.

Scope of This Chapter

So far, we have only been rendering 2D text and buttons within our virtual world. In this chapter, we are going to cover rendering 3D models within our virtual world.

To be more specific, we are going to start off focusing on how to render pre-existing 3D models and properties that we can control.

Then, we will look into how to do animation with 3D models.

Finally, we are going to look into how you can create your own 3D models from scratch. As a heads up, 3D modeling is a big topic and could be its own separate book. Therefore, I will be writing more along the lines of pointing you in the right direction than an in-depth tutorial.

I think this chapter will be a ton of fun and of great value so let’s get right to it!

Rendering Pre-existing 3D Models

Creating a New Project

Let’s create a new project for our exploration with 3D modeling and call it StarWarsModeling.

Change directories to wherever you want to save this project and run:

react-vr init StarWarsModeling

Once this finishes, open up the project in your code editor.

Updating the Panoramic

The final thing to do before we get into the 3D modeling is to update the panoramic photo.

Download this photo at the highest resolution.

Let’s keep it simple and rename this Space.jpg.

Make sure to add this in your static_assets folder.

Finally, let’s update the Pano component in index.vr.js like so:

<Pano source={asset('Space.jpg')}/>

Also, go ahead and remove the Text component.

cd into the new project from command line, run npm start , and we should see our new virtual world:

Retrieving 3D Models

If we are going to look into rendering pre-existing 3D models, then we need to look at our options for how to retrieve a 3D model to use.

The best library for free 3D models that I have found is Clara.io. Clara.io has a wide variety of 3D models and formats for exporting the 3D models.

Clara.io

Head over there and as you can guess by the name of our project, we will be looking for Star Wars models to add to our virtual world.

Search Star Wars and let the fun begin!

Instantly, we can see some cool choices:

Let’s click on the Death Star.

Click on Download and select Wavefront OBJ (.obj):

Currently, this is the file format that React VR supports.

Clara will package a zip folder for us to download:

Go ahead and download this.

Extract this zip folder into the static_assets folder.

We can now see two new files:

The file ending in .mtl refers to the material of the model.

The file ending in .obj refers to the object of the model.

I like to think of .obj files as the container and .mtl as the fill.

Here’s a visualization:

Seeing the Object

Since you might be curious to see this difference even more clearly, we can actually render just the object with no material.

In index.vr.js, let’s import model:

import {
AppRegistry,
asset,
Pano,
Text,
View,
Model
} from 'react-vr';

Next, we can render the death-star.obj like so:

<View>
<Pano source={asset('Space.jpg')}/>
<Model
source={{
obj: asset('death-star.obj'),
}}
/>
</View>

If you save and refresh the local host, we will see a massive death star object:

Let’s apply some inline style with a transform so it places this further in the distance:

<Model
source={{
obj: asset('death-star.obj'),
}}
style={{
transform: [{translate: [0, 0, -2]}]
}}
/>

In the code above, we are placing this object 2 meters back from the starting point.

To better see the object, we can also make it a wireframe by adding the following property:

<Model
source={{
obj: asset('death-star.obj')
}}
style={{
transform: [
{translate: [0, 0, -2]}
]
}}
wireframe={true}
/>

Now, we should see the following:

Awesome!

Now, we need to apply the material and set wireframe to false like so:

<Model
wireframe={false}
source={{
obj: asset('death-star.obj'),
mtl: asset('death-star.mtl')
}}
style={{
transform: [
{translate: [0, 0, -2]}
]
}}
/>

Edit: The generated death-star.mtl file is supposed to be applying the screenshot texture (that is also in static_assets) to the model. Despite several efforts, I could not get this file to work. Fortunately, there is a texture property where we can specify an http address for a texture image in place of using the .mtl file.

You can update your code to the following:

<Model
source={{
obj: asset('death-star.obj'),
//mtl: asset('death-star.mtl')
}}
style={{
transform: [
{translate: [0, 0, -2]}
]
}}
texture={"https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/death-star.png"}
wireframe={false}
/>

Refresh and we can now see the Death Star with the material applied:

So cool!

Let’s quickly add a slight rotation along the Y axis to see the front:

style={{
transform: [
{translate: [0, 0, -2]},
{rotateY: '110deg'}
]
}}

Animating 3D Models

Pretty cool, huh? You know what would make this even cooler? If we could apply some animation…like making the Death Star rotate!

Let’s give this a shot.

In order to do this, we have to import Animated (let’s also import Easing):

import {
AppRegistry,
asset,
Pano,
Text,
View,
Model,
Animated
} from 'react-vr';
import { Easing } from 'react-native';

Then, let’s add a local state that will have an Animated.Value called rotation:

export default class StarWarsModeling extends React.Component {
constructor() {
super();
this.state = { spin: new Animated.Value(0) };
}
//more stuff
}

Next, we bind some inline styling for a rotateZ transformation to this:

style={{
transform: [
{translate: [0, 0, -8]},
{rotate: this.state.spin})
]
}}

Additionally, we do a timing animation within a componentDidMount lifecycle so the rotation value goes from 0 to 1 in 3 seconds:

componentDidMount() {
Animated.timing(
this.state.spin,
{
toValue: 1,
duration: 3000,
easing: Easing.ease
}
).start();
}

Wait…that won’t work. Why?

rotate transformations have to be strings according to the React VR official documentation:

We need the change from 0 to 1 in the rotation value to be reinterpreted as a string of “0deg” to “360deg”. See if you can think of what we need here.

We can achieve this using interpolate like so:

style={{
transform: [
{translate: [0, 0, -8]},
{rotate: this.state.spin.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
})
}]
}}

To make this a bit cleaner, let’s store the this.state.spin… into a variable above the return:

render() {
const spin = this.state.spin.interpolate({
inputRange: [0, 360],
outputRange: ['0deg', '360deg']
})
//return
}

Then, we can update the inline styling so it uses this variable:

style={{
transform: [
{translate: [0, 0, -8]},
{rotate: spin}
]
}}

There’s one final step remaining. We need to make the model component compatible with the Animated API.

Recall, the Animated API only works with Text, View, and Image. Therefore, we were able to directly do the following in the previous chapter:

<Animated.Text>

If we tried to do Animated.Model , we would break our code.

There is a solution, however. We can use createAnimatedComponent.

This can be used to turn a component into an Animated component.

First, we add the following:

render() {
const spin = this.state.spin.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
});
    const AnimatedModel = Animated.createAnimatedComponent(Model);
    //more stuff
}

Then, we use AnimatedModel in place of Model in the tag:

<AnimatedModel
source={{
obj: asset('death-star.obj'),
//mtl: asset('death-star.mtl')
}}
style={{
transform: [
{translate: [0, 0, -2]},
{rotateY: spin}
]
}}
texture={"https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/death-star.png"}
wireframe={false}
/>

Refresh and let’s see if this worked!

Super cool!

Looping Animations

The Death Star rotates fully and then stops animating. We want to have it loop. We did not cover this in the previous chapter so let’s explore.

In order to loop our animation, let’s remove the animation from the lifecycle and place it in a separate function:

componentDidMount() {

}
spinAnimation() {
Animated.timing(
this.state.spin,
{
toValue: 1,
duration: 3000,
easing: Easing.linear
}
).start();
}

Then, we want to call this spinAnimation function from the lifecycle:

componentDidMount() {
this.spinAnimation();
}

Next, we will have a call back in the start function of our spin animation that will cal the animation again:

.start( () => this.spinAnimation() );

The final piece of the puzzle is have the Animated.Value of spin be reset at the start of the animation:

spinAnimation() {
this.state.spin.setValue(0);
Animated.timing(
this.state.spin,
{
toValue: 1,
duration: 3000,
easing: Easing.linear
}
).start( () => this.spinAnimation() );
}

I also have updated the easing function to linear for styling preference.

Let’s see if this worked:

Neat!

Creating Custom Models

As you can guess, creating 3D models is a crucial step in VR development. However, it is no small task. Exploring the depths of 3D modeling takes a lot of time and practice on top of working with React VR.

Personally, I have focused all of my illustration efforts in the 2D realm and 3D modeling seems pretty intimidating. For this reason, I am just going to put you in the right direction for further exploration.


There’s a whole host of 3D modeling tools. You can explore these options for yourself but I would start with Tinkercad and then move on to Blender.

Tinkercad is a good place to start because it requires no installations and has a really simple interface.

Tinkercad removes a ton of features and complexities of 3D modeling and allows you to get a taste of working with 3D shapes on a plane.

After you play around, you can export models in the .obj file format for use in React VR.

It even provides some tutorials for getting started.

While there are other options for more complex 3D modeling, I recommend moving from Tinkercad to Blender.

Blender is open-source and has a strong community behind it.

It has all the features and tools for professional use.

With that being said, the user interface is probably the most overwhelming part:

However, you will have no issues finding tutorials and video courses to get started with Blender as a beginner. Here’s a beginner course suggested from the Blender site.

In Blender, you will be able to export 3D models in the .obj format for use in React VR.

Final Code

Code available on GitHub.

Concluding Thoughts

In this chapter, we have been able to learn everything we need to know to start implementing 3D models with animation in React VR. At this point, you should have enough knowledge if you wish to do further exploration on your own. If you do so, try to also organize this project as we did in Chapter 3.

In the next chapter, we will put 3D concepts aside and look into creating useful scalable vector graphics (SVG) for use in React VR.

Chapter 6

Chapter 6 is now available.

Support the Author

If you would like to support me as I write this book, you can purchase the book here.

The book is published through a platform called LeanPub which allows me to update my book as it progresses. Each time a chapter is added, you will be notified via email. The book will be free to read on Medium, however, purchasing it through LeanPub allows you to download the ebook as a PDF, EPUB, or MOBI file and helps support me financially.

Additionally, I have created a special package that will provide you with a secret link to a Discord server where you will be able to help influence how I write this book.

So go ahead and purchase this book on LeanPub if you would be so kind.


Cheers,
Mike Mangialardi
Founder of Coding Artist