(1)React Native(Expo)で3D表示
普段はソーシャルワーカーとして障がいをお持ちの方の支援をしています。ReactやReact Nativeでアプリ作成を楽しんでおり、最近は3D表示に関心がありThree.jsなどを使っています。ただ、バージョン違いで動作しない、ライブラリが更新されていないなどReact Nativeでの3D表示の情報はまだ少ないため、簡単なコードを書いておこうと思います。
(2)一人称視点で3D空間を前後左右に動く
今回のコードはただ一人称視点で動くだけなのですが、Three.jsは様々な機能があり本格的な3Dアプリの作成もできそうです。GIFが少しカクついているのはタップ連打で移動しているからです💦
(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)コード
読み込みまーす
```ts 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が人気ですねー。EASの無料化でより使いやすくなったExpo、来年はReact Nativeも盛り上がりそうですね