Creating a React 360 App for Visualizing 3D models

Andy Flatiron
8 min readNov 11, 2020

Exploring the React 360 Framework and Visualizing 3D models

Thanks for reading…

To get started let’s go ahead and set up React and Download the necessary frameworks —

npm install -g react-360-cli

Great, now that you have the latest version of React 360 installed on your machine we can now create a new project on our system.

Make sure you CD into the proper directory

CD Blogposts 

Once you’re in the proper folder execute

react-360 init My3DProject

After the init statement you can name your project anything. This command will create a folder named “My 3D Project” and place the foundation of React 360 into the necessary sub-directories.

Once that’s finished installing you can go ahead and enter that directory

cd My3DProject

Exploring the Code

If you run

NPM Start

And then route to Localhost:8081/Index.html. This starts the React Native Package Manager and hosts the initial “hello world” view

If you are properly set up you should see the following screen displayed on your server

React 360 Baseline Homepage

Pretty Cool Already, Isn’t It?

This page allows you to experience React 360 off the bat, you can scroll around with your mouse to view the 3D environment. Before we add a model and change the background Image, let’s first understand what is going on here.

Go ahead and open up the folder in VSCode or another text editor. First we’ll check out the Index.JS folder.

import React from 'react';import {AppRegistry,StyleSheet,Text,View,} from 'react-360';export default class My3DProject extends React.Component {render() {return (<View style={styles.panel}><View style={styles.greetingBox}><Text style={styles.greeting}>Welcome to React 360</Text></View></View>);}};const styles = StyleSheet.create({panel: {// Fill the entire surfacewidth: 1000,height: 600,backgroundColor: 'rgba(255, 255, 255, 0.4)',justifyContent: 'center',alignItems: 'center',},greetingBox: {padding: 20,backgroundColor: '#000000',borderColor: '#639dda',borderWidth: 2,},greeting: {fontSize: 30,},});AppRegistry.registerComponent('My3DProject', () => My3DProject);

The structure looks pretty similar to what we are used to seeing in React. At the top we are important components that will be used throughout the document.

App Registry allows us to connect components of the Index page to the ./Client.JS, which is the runtime and the code that actually displays the code onto the screen. React separated the runtime in order to make the code run quicker and more efficiently as it already takes lots of CPU.

StyleSheet gives us the ability to customize our Views and Text within the Index.js document so we don’t need to work with an external stylesheet.

View allows us to create a 2D surface, it also functions as a DIV container. So always make sure to surround the React documents with Views. The functions are similar to React Native. Also, just like a Div, you can style the View component by specifying its size, background color, content justification, etc. All of this can be done through the Stylesheet component

Text allows us to add text to 3D space. Text is typically nestled within a view component. It can also be styled in the Stylesheet.

Under the Render and Return functions you can see a standard React Layout with “View” instantiating the hierarchy instead of the typical Div Structure. You can see we have a parent View styled by Panel giving it a width of 1000 and a height of 600. The panel also specifies the color and opacity levels. We have other Views and text nestled within, all styled individually.

Under the Styles Panel (which on it’s own is very similar to CSS, so I assume you’re comfortable with it) we have the following line

AppRegistry.registerComponent('My3DProject', () => My3DProject);

From what I under this line is registering the Class ‘My3DProject’ and instantiating it to be accessible from the runtime, client.js. If we remove this line the entire class will disappear from the screen. Although we created a styled this view, the runtime actually places it in space.

This naturally leads us to the client.js document

If you open Client.js you will see the following

import {ReactInstance} from 'react-360-web';function init(bundle, parent, options = {}) {const r360 = new ReactInstance(bundle, parent, {// Add custom options herefullScreen: true,...options,});// Render your app content to the default cylinder surfacer360.renderToSurface(r360.createRoot('My3DProject', { /* initial props */ }),r360.getDefaultSurface());// Load the initial environmentr360.compositor.setBackground(r360.getAssetURL('360_world.jpg'));}window.React360 = {init};

I want to focus on the renderToSurface() function.

r360.renderToSurface(r360.createRoot('My3DProject', { /* initial props */ }),r360.getDefaultSurface()
);

Remember the App Registry we set up in the index.js? Well, this is where it connects. When you create a class intended for 2D, you need to create a surface in the runtime and connect the Registered Class to the component. You then run getDefaultSurface so you don’t need to specify any more information regarding the location of the surface and its position in space.

Modifying the document

Under the function, you will see the following line

r360.compositor.setBackground(r360.getAssetURL('360_world.jpg'));

This line here sets the background property, let’s start modifying our project by editing this photo. If you take a look at the react documentation there are multiple different ways to set the background and many different formats you can use as an image. The background can also be set in Index.js, but that is only necessary if the background is switching multiple times in an app. We are going to use a 360 Mono Equirectangular formatted image.

This can be easily sourced on the web, just search for it.

On Google, you might want to specify the Size to “Large for enhanced” visual clarity when landing on the site.

I found this nice photo of an Airplane Hanger

Now we just need to upload the photo to the static_assets folder of our project. If you look at Index.HTML, you can see that the source folder is already configured to “static_assets” so we don’t need to reference it every time.

Once it’s uploaded, change the compositor/setbackground function to search for the “‘Airplane.jpg’” image you just uploaded. If you refresh the page, you should see your image.

Now let’s go ahead and modify the Index.js container to change the styles of the Wrapper Container, make it smaller, and change the text to say Come Hang in My Hanger!”

If you look at my styles you can see I adjusted the height of the wrapper View, adjusted the font size, and border color.

/index.jsconst styles = StyleSheet.create({panel: {// Fill the entire surfacewidth: 1000,height: 200,backgroundColor: 'rgba(255, 255, 255, 0.4)',justifyContent: 'center',alignItems: 'center',},greetingBox: {padding: 20,backgroundColor: 'rgba(255, 255, 255, 0.1)',borderColor: '#00B0FF',borderWidth: 2,},greeting: {fontSize: 80,},});

Let’s go ahead and add an airplane 3D model under the header.

In order to do that, let’s first start by sourcing a 3D model online. React 360 only supports GLTF2 and OBJ files. I typically start by visiting Google Poly for the models as they have an array of objects offered in different formats.

So, I checked out the site, searched for a plane, and found a low-poly jet that looks pretty cool.

Now how do we add it to the scene?

First, download the Obj Files and add both the OBJ and MTL files to the static-assets folder

Next, React 360 has a component type called Entity which allows us to render 3D objects to the scene. So let’s create a new file called “plane.js” and start creating our entity

import {asset, Entity} from 'react-360'

Since we are importing an Asset into an Entity component we need to import both asset and Entity from React 360. Now let’s create the class and add the Entity. We create a View container and within the view, we’ll create an Entity component pointing to the source files of our object

<Entitysource={{obj: asset('Plane.obj'),mtl: asset('Plane.mtl')}}
/>

Next, we can style the entity, let’s start by transforming it’s scale, so it’s not overwhelming when we see it first on the page. We can do this by adding the style attributes to the entity itself. Your final Plane class should look like this

import React from 'React'import {asset, Entity} from 'react-360'export default class Plane extends React.Component{render(){return(<View><Entitysource={{obj: asset('Plane.obj'),mtl: asset('Plane.mtl')}}style={{transform:[{scaleX: 0.05 },{ scaleY: 0.05 },{ scaleZ: 0.05 },]}}/></View>)}}

Now, we just need to link the model up with Index.JS by importing the file

import Plane from './entities/Plane'

Awesome, now you’re all linked up, but why is the plane not showing?

Don’t you have to render it within Index.Js?

No, we actually need to first Register the component and then register it in Client.JS. So add this line to the bottom of your index.js file

AppRegistry.registerComponent('Plane', () => Plane);

We’re not done yet…let’s shift back over to the Client.js and place the object in the scene.

In order to place a 3D object to a scene we need to render it to a location, different from rendering a surface, we need to start by importing the Location Component from React 360 and then setting the coordinates of the component

client.js
const location = new Location([0, -1, -2]);

This location is one step down from the user and two back, so it should be easily viewable upon page load.

And now we’ll render the plane to the location using the following function and attached the registered class to the Root

const location = new Location([0, -1, -2]);r360.renderToLocation(r360.createRoot(‘Plane’),location,);

Upon page load, you should now see the 3D model of the plane in your environment next to your views.

With that, I’m going to end off today’s blog! In the next one, I’ll be focusing on interacting with the 3D objects and turning our space into an interactive environment!

You can view the code for this project on my Github!

--

--