概要
Morphとは、メッシュの形状を流動的に変更することを指します。
React Three Fiberのみでこれを実現させようとすると、頂点の座標設定など煩雑なコーディングが必要です。
一方、BlenderでShape Keyを設定したモデルをインポートすることで、簡単にMorphを表現することができます。
サンプル
実際に動くものを触ってみたい方はこちら。
※ この記事とは扱ってるモデルが少し異なります。
Shape Keyの設定
Blenderを使用してShape Keyを設定します。
Shape Keyの追加
[+]を押すことで、キーを追加します。
- 最初のBasisは、基準となる形状です。形状を変更していくのはKey 1です。
形状の変更
Key 1を選択した状態で、メッシュの形状を[編集モード]で変更します。
ここで注意点として、
メッシュの頂点数を変更すると、Morphできなくなります。
Cubeの頂点数は8なので、この頂点数8を変えないように形状変更します。
- 上図では、Cubeの上面の頂点を重ねているだけなので、頂点数は8のままです。
Shape Keyの確認
編集モードで形状の変更ができたら、オブジェクトモードに戻ります。
オブジェクトモードに戻ると、メッシュの形状はBasisの状態(変更前の状態)になります。
Key 1の値(Value)を変更することで、メッシュをMorphさせることができます。
値の範囲は、0~1です。
ブレンド
Shape Keyで変更される形状は、複数を組み合わせることができます。
例えば、Keyをもうひとつ追加します。
Key 1とKey 2の値をそれぞれ1にすると、形状がブレンドされることがわかります。
glbエクスポート
作成したモデルをglbファイルとしてエクスポートします。
この例では、morph.glbという名前で保存しました。
React Three Fiberへのインポート
Morph.tsx
Canvasコンポーネントを生成するためのファイル(Morph.tsx)を作成します。
import React, { Suspense, VFC } from 'react';
import { OrbitControls, Stats } from '@react-three/drei';
import { Canvas } from '@react-three/fiber';
import { MorphModel } from './MorphModel';
export const Morph: VFC = () => {
return (
<Canvas
camera={{
position: [0, 5, 10],
fov: 50,
aspect: window.innerWidth / window.innerHeight,
near: 0.1,
far: 2000
}}
dpr={window.devicePixelRatio}
shadows>
{/* background */}
<color attach="background" args={['#1e1e1e']} />
{/* fps */}
<Stats />
{/* control */}
<OrbitControls />
{/* light */}
<directionalLight position={[0, 5, 5]} />
<ambientLight intensity={0.1} />
{/* mesh */}
<Suspense fallback={null}>
<MorphModel />
</Suspense>
</Canvas>
)
}
- backgroundでは、Canvasの背景色を設定しています。
- fpsでは、画面左上にFPSチェッカーを追加しています。
- controlでは、カメラのコントローラーを追加しています。マウス操作によりカメラを移動することができます。
- lightでは、シーンのライティングをしています。
- meshでは、glbファイルを読み込みを行っています。glbファイルを読み込む場合は必ずSuspenseで囲う必要があります。MorphModelは別ファイルに定義しています。
MorphModel.tsx
glbファイルのインポートファイル(MorphModel.tsx)を作成します。
雛形コードの生成
まず、雛形となるコードを生成します。
以下のサイトに、glbエクスポートをしたmorph.glbをドロップすると、glbファイルをインポートするためのコードの雛形が自動で生成されます。
画面右上のコントローラーから、必要な項目を設定します。
特に、TypeScriptでコーディングしている場合は、typesにチェックを入れましょう。
ここで、morphTargetプロパティがあれば、設定したShape Keyがちゃんとエクスポートされています。
最後に、**[copy to clipboard]**でコピーします。
雛形ファイルは、コマンドから生成することもできます。
glbファイルの容量の大きく上記のサイトで表示が遅い場合は、こちらが使えます。
glbファイルの追加
プロジェクトにエクスポートしたmorph.glbを追加します。
この例では、以下に配置しました。
public/assets/morph.glb
インポートファイルの作成
コピーしたひな形を元に読み込みファイルを作成します。
/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
*/
import { useControls } from 'leva';
import React, { useRef, VFC } from 'react';
import * as THREE from 'three';
import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
import { useGLTF } from '@react-three/drei';
type GLTFResult = GLTF & {
nodes: {
Cube: THREE.Mesh
}
materials: {
Material: THREE.MeshStandardMaterial
}
}
const ModelPath = '/assets/morph.glb'
export const MorphModel: VFC = (props: JSX.IntrinsicElements['group']) => {
const group = useRef<THREE.Group>()
const { nodes, materials } = useGLTF(ModelPath) as GLTFResult
// コントローラーの追加
const datas = useControls({
key1: {
value: 0,
min: 0,
max: 1,
step: 0.01
},
key2: {
value: 0,
min: 0,
max: 1,
step: 0.01
}
})
console.log(nodes.Cube.morphTargetDictionary)
console.log(nodes.Cube.morphTargetInfluences)
return (
<group ref={group} {...props} dispose={null}>
<mesh
name="Cube"
castShadow
receiveShadow
geometry={nodes.Cube.geometry}
material={materials.Material}
morphTargetDictionary={nodes.Cube.morphTargetDictionary}
// morphTargetInfluences={nodes.Cube.morphTargetInfluences}
morphTargetInfluences={[datas.key1, datas.key2]}
/>
</group>
)
}
useGLTF.preload(ModelPath)
- ModelPathは、morph.glbへのパスを定義しています。
const ModelPath = '/assets/morph.glb'
- console.logで、morphTargetDictionaryとmorphTargetInfluencesに何が入っているか確認します。
console.log(nodes.Cube.morphTargetDictionary)
console.log(nodes.Cube.morphTargetInfluences)
morphTargetDictionary
には、Blenderで設定したShape Keyの名前と定義の順番がオブジェクトで格納されています。
morphTargetInfluences
には、Shape Keyそれぞれに対する、morphの値が配列で格納されています。この格納順が定義の順番にあたります。初期値は0になっているので、読み込んだメッシュは変形していません。配列の値を0~1まで変化させることで、Morphingさせることができます。
- コントローラーを追加して、値を変更できるようにします。
const datas = useControls({
key1: {
value: 0,
min: 0,
max: 1,
step: 0.01
},
key2: {
value: 0,
min: 0,
max: 1,
step: 0.01
}
})
// morphTargetInfluences={nodes.Cube.morphTargetInfluences}
morphTargetInfluences={[datas.key1, datas.key2]}

コントローラーには、levaパッケージを使用しています。levaについて詳しく知りたい方は、以下を参照してください。
Tips
glbエクスポートの仕様
React Three Fiberの記事
過去に投稿した記事です。ご参考までに。
投稿日 | タイトル・リンク |
---|---|
2021.10.23 | 【React】react-three-fibarで3D表現をする(オブジェクトのClippingと断面) |
2021.09.22 | 【React】react-three-fibarで3D表現をする(Mixamoを使ったアニメーションモデル) |
2021.09.18 | 【React】react-three-fibarで3D表現をする(Blenderで作成したモデルの読み込み) |
2021.09.18 | 【React】react-three-fibarで3D表現をする(文字表示) |
2021.09.17 | 【React】react-three-fibarで3D表現をする |
2021.06.11 | 【React × Three.js】Blenderで作成したモデルをReactプロジェクトに読み込む |