LoginSignup
7
1

More than 1 year has passed since last update.

React Nativeで3D表示してみよう

Last updated at Posted at 2021-12-04

(1)React Native(Expo)で3D表示

普段はソーシャルワーカーとして障がいをお持ちの方の支援をしています。ReactやReact Nativeでアプリ作成を楽しんでおり、最近は3D表示に関心がありThree.jsなどを使っています。ただ、バージョン違いで動作しない、ライブラリが更新されていないなどReact Nativeでの3D表示の情報はまだ少ないため、簡単なコードを書いておこうと思います。

(2)一人称視点で3D空間を前後左右に動く

今回のコードはただ一人称視点で動くだけなのですが、Three.jsは様々な機能があり本格的な3Dアプリの作成もできそうです。GIFが少しカクついているのはタップ連打で移動しているからです💦

hocIof9TNq7pkVk4y2bc1638630612-1638630637.gif

Three.js公式

Expo公式 GLView

(3)使った技術

・react-native
・expo 42.0.1
・expo-gl 10.4.2
・expo-three 6.0.1
・gsap 3.6.0
・three 0.134.0

(4)コード

読み込みまーす

import React from "react";
import { View, Pressable, Text } from "react-native";
import { GLView } from "expo-gl";
import { Renderer } from "expo-three";
import { TweenMax } from "gsap";
import {
  PointLight,
  GridHelper,
  Mesh,
  PerspectiveCamera,
  Scene,
  BoxGeometry,
  MeshLambertMaterial,
} from "three";

可能な限りコメントしました


export default function App() {
  const camera = new PerspectiveCamera(30, 1, 1, 100); // カメラが映し出す設定(視野角, アスペクト比, near, far)

  // カメラの初期座標
  let cameraInitialPositionX = 0;
  let cameraInitialPositionY = 2;
  let cameraInitialPositionZ = 7;

  // TweenMax.to(何が, 何秒で, { z軸に distance 分移動 })
  const moveUd = (distance) => {
    TweenMax.to(camera.position, 0.2, {
      z: camera.position.z + distance,
    });
  };

  //TweenMax.to(何が, 何秒で, { x軸に distance 分移動 })
  const moveLr = (distance) => {
    TweenMax.to(camera.position, 0.2, {
      x: camera.position.x + distance,
    });
  };

  return (
    <View style={{ flex: 1 }}>
      <GLView
        style={{ flex: 1 }}
        onContextCreate={async (gl) => {
          // 3D空間の準備
          const { drawingBufferWidth: width, drawingBufferHeight: height } = gl;
          const renderer = new Renderer({ gl }); // レンダラーの準備
          renderer.setSize(width, height); // 3D空間の幅と高さ
          renderer.setClearColor("white"); // 3D空間の配色
          const scene = new Scene(); // これが3D空間
          scene.add(new GridHelper(10, 10)); //グリッドを表示

          // 配置するオブジェクト
          const geometry = new BoxGeometry(2, 2, 2); // 四角い物体
          const material = new MeshLambertMaterial({ color: "blue" }); // 物体に光を反射させ色や影を表現する
          cube = new Mesh(geometry, material); // geometryとmaterialでオブジェクト完成
          cube.position.set(0, 0, 0); // 配置される座標 (x,y,z)
          scene.add(cube); // 3D空間に追加

          // 3D空間の光!
          const pointLight = new PointLight(0xffffff, 2, 1000, 1); //一点からあらゆる方向への光源(色, 光の強さ, 距離, 光の減衰率)
          pointLight.position.set(0, 200, 200); //配置される座標 (x,y,z)
          scene.add(pointLight); //3D空間に追加

          // カメラの座標 = 一人称視点
          camera.position.set(
            cameraInitialPositionX,
            cameraInitialPositionY,
            cameraInitialPositionZ
          );

          const render = () => {
            requestAnimationFrame(render); // アニメーション moveUd関数、moveLr関数でカメラ座標が移動
            renderer.render(scene, camera); // レンダリング
            gl.endFrameEXP(); // 現在のフレームを表示する準備ができていることをコンテキストに通知するpresent (Expo公式)
          };
          render();
        }}
      />

画面表示部分です Pressable タグを使いこなせると幅が広がりそう

      <View>
        <Pressable onPress={() => moveUd(-0.2)}>
          <Text
            style={{
              fontSize: 36,
              color: "red",
              textAlign: "center",
            }}
          >
            前へ
          </Text>
        </Pressable>
        <Pressable onPress={() => moveUd(0.2)}>
          <Text
            style={{
              fontSize: 36,
              color: "red",
              textAlign: "center",
            }}
          >
            後へ
          </Text>
        </Pressable>
        <Pressable onPress={() => moveLr(-0.2)}>
          <Text
            style={{
              fontSize: 36,
              color: "red",
              textAlign: "center",
            }}
          >
            左へ
          </Text>
        </Pressable>
        <Pressable onPress={() => moveLr(0.2)}>
          <Text
            style={{
              fontSize: 36,
              color: "red",
              textAlign: "center",
            }}
          >
            右へ
          </Text>
        </Pressable>
      </View>
   </View>
  );
}

(5)終わりに

Advent Calendarに初めて参加してみました!モバイルカテゴリーだとFlutterが人気ですねー:blush:。EASの無料化でより使いやすくなったExpo、来年はReact Nativeも盛り上がりそうですね:raised_hands:

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1