2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

React-Three-Fiber でアイコンをグリングリン回したい

Last updated at Posted at 2022-05-06

react-three-fiber でアイコンをクルクルする

したいよね?
なので、cubeGeometry に png画像を貼り付けてグルグルさせてみました。

準備

Typescript 版の React プロジェクト作成
react-three/fiber のインストール

  % npx create-react-app cube-icon
  % cd cube-icon
  % npm install three @react-three/fiber

アイコン用ファイル( icon.png )を cube-icon/public 以下に配置します。

今回は以下の画像ファイルを使用しました。
大人気 AppleWatch アプリの 男は読経!女も読経! 用に作ったアイコンです。

アートですねぇ...

icon.png

コード

App.js, App.css の2ファイル、Index.jsは省略

App.css

この設定がないと表示が小さくなってしまう

App.css
.App {
  width: 100vw;
  height: 100vh;
}

App.js

function IconBoard 内で 1x1x0.05の薄い板を作って
マテリアルのマップにテキスチャを貼り付けてます。

IconBoard の引数でテキスチャとポジションを指定できるようにしてます。

useFrame() 内に
マウスが mesh の上に乗るとアイコンが捻り回転、離れると戻る。
クリックされると縦回転、一回転すると止まる。
の処理を記述。

App.js
import { useState, useRef } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { TextureLoader } from 'three';
import './App.css';

function IconBoard(props) {
  const iconRef = useRef();
  const [hover, setHover] = useState(false);
  const [click, setClick] = useState(false);

  const maxRad = Math.PI*2;

  useFrame(()=>{
    const rotZ = iconRef.current.rotation.z;
    if (hover) {
      iconRef.current.rotation.z = rotZ < maxRad? rotZ + 0.03: maxRad;
    } else {
      iconRef.current.rotation.z = rotZ > 0.0? rotZ - 0.05: 0.0;
    }
    if (click) {
      iconRef.current.rotation.y += 0.04;
      if (iconRef.current.rotation.y > maxRad) {
        iconRef.current.rotation.y = 0;
        setClick(false);
      }
    }
  });

  return (
        <mesh 
        position={props.position}
        ref={iconRef} 
        onPointerOver={()=>setHover(true)} 
        onPointerLeave={()=>setHover(false)}
        onClick={()=>setClick(true)}
        >
          <boxGeometry args={[1,1,0.05]} />
          <meshBasicMaterial map={props.map} />
        </mesh>
  );
}

function App() {
  const texture = new TextureLoader().load("./icon.png");
  return (
    <div className="App">
      <Canvas>
        <IconBoard map={texture} position={[0,0,0]}/>
      </Canvas>
    </div>
  );
}

export default App;

実行画面

神々しいですね
スクリーンショット 0004-05-06 21.11.18.png

クリックすると回ります
スクリーンショット 0004-05-06 21.12.38.png

複数表示

function App() 内で '< IconBoard />' を並べると複数のアイコンボードを表示できます。

App
function App() {
  const texture = new TextureLoader().load("./icon.png");
  return (
    <div className="App">
      <Canvas>
        {[...Array(3)].map((_,x)=><IconBoard map={texture} position={[(x-1)*1.5,1.5,0]}/>)}
        <IconBoard map={texture} position={[0,0,0]}/>
        {[...Array(3)].map((_,x)=><IconBoard map={texture} position={[(x-1)*1.5,-1.5,0]}/>)}
      </Canvas>
    </div>
  );
}

こんな感じで、さらに神々しさが増しました。

スクリーンショット 0004-05-06 21.20.40.png

最後に

今年のGWは、Three.js と React-Three で苦手な3Dの勉強を頑張りましたよ。
まだまだ最低限の機能しか使えないけど、なかなか楽しく学べたのでヨシ!

2
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?