💬
React+TypeScriptなWebアプリで、R3Fのtutorial12。(Materials)
Abstract
今回の参考はここ(Materials)。
meshの下記4つを、全部実装してみた。
- MeshBasicMaterial
- MeshNormalMaterial
- MeshPhongMaterial
- MeshStandardMaterial
結論
今回の成果物はココ↓
前提
- React+Typescriptの開発環境は構築済 Ubuntu22.04+VSCode+React+TypeScriptの開発環境を構築してみた。
- このスケルトンコードから始める。react-r3f-tutorial010
手順
1.プロジェクト生成 -> VSCodeで開く
めんどいから、このスケルトンコードから始める。react-r3f-tutorial010
で、下記コマンドでフォルダ名とか整備する。
フォルダリネームとか
$ BaseProject=react-r3f-tutorial010
$ NewProject=react-r3f-tutorial012
$ cd ~
$ rm -rf ${BaseProject}
$ git clone https://github.com/aaaa1597/${BaseProject}.git
$ rm -rf ${BaseProject}/.git
$ mv ${BaseProject} ${NewProject}
$ cd ${NewProject}
準備
$ npm install --save three
$ npm install --save @types/three
$ npm install --save @react-three/fiber
$ npm install --save @react-three/drei
$ npm install --save-dev leva
App.tsx
まず全体。
App.tsx
import React, {useRef} from 'react';
import './App.css';
import { Canvas, useFrame, MeshProps } from '@react-three/fiber'
import * as THREE from 'three'
import { Stats, OrbitControls } from '@react-three/drei'
+import { useControls } from 'leva'
+type BoxProps = {
+ props: MeshProps;
+ wireframe?: boolean;
+}
-const Box = (props: MeshProps) => {
+const Box = (boxprops: BoxProps) => {
const ref = useRef<THREE.Mesh>(null!)
useFrame((_, delta) => {
ref.current.rotation!.x += 1 * delta
ref.current.rotation!.y += 0.5 * delta
})
+ useControls(boxprops.props.name!, {
+ wireframe: {
+ value: false,
+ onChange: (v: boolean) => {
+ if(boxprops.props.name == "meshBasicMaterial")
+ (ref.current.material as THREE.MeshBasicMaterial).wireframe = v
+ else if(boxprops.props.name == "meshNormalMaterial")
+ (ref.current.material as THREE.MeshNormalMaterial).wireframe = v
+ else if(boxprops.props.name == "meshPhongMaterial")
+ (ref.current.material as THREE.MeshPhongMaterial).wireframe = v
+ else if(boxprops.props.name == "meshStandardMaterial")
+ (ref.current.material as THREE.MeshStandardMaterial).wireframe = v
+ }
+ },
+ flatShading: {
+ value: true,
+ onChange: (v: boolean) => {
+ if(boxprops.props.name == "meshBasicMaterial")
+ {/* (ref.current.material as THREE.MeshBasicMaterial)!.flatShading = v*/}
+ else if(boxprops.props.name == "meshNormalMaterial")
+ (ref.current.material as THREE.MeshNormalMaterial)!.flatShading = v;
+ else if(boxprops.props.name == "meshPhongMaterial")
+ (ref.current.material as THREE.MeshPhongMaterial)!.flatShading = v;
+ else if(boxprops.props.name == "meshStandardMaterial")
+ (ref.current.material as THREE.MeshStandardMaterial)!.flatShading = v;
+ (ref.current.material as THREE.MeshBasicMaterial)!.needsUpdate = true;
+ },
+ },
+ color: {
+ value: 'lime',
+ onChange: (v: string) => {
+ if(boxprops.props.name == "meshBasicMaterial")
+ (ref.current.material as THREE.MeshBasicMaterial)!.color = new THREE.Color(v)
+ else if(boxprops.props.name == "meshNormalMaterial")
+ {/*(ref.current.material as THREE.MeshNormalMaterial)!.color = new THREE.Color(v)*/}
+ else if(boxprops.props.name == "meshPhongMaterial")
+ (ref.current.material as THREE.MeshPhongMaterial)!.color = new THREE.Color(v)
+ else if(boxprops.props.name == "meshStandardMaterial")
+ (ref.current.material as THREE.MeshStandardMaterial)!.color = new THREE.Color(v)
+ },
+ },
+ })
return (
- <mesh {...props} ref={ref}>
+ <mesh {...boxprops.props} ref={ref}>
- <boxGeometry />
+ <icosahedronGeometry args={[1, 1]} />
</mesh>
)
}
const App = () => {
return (
<div style={{ width: "75vw", height: "75vh" }}>
<Canvas camera={{ position: [3, 1, 2] }}>
<ambientLight />
<directionalLight />
- <Box position={[-0.75, 0, 0]} name="A" />
- <Box position={[ 0.75, 0, 0]} name="B" />
- <Box position={[-0.75, 2, 0]} name="C" />
- <Box position={[ 0.75, 2, 0]} name="D" />
+ <Box props={{position:[-1, 0, 0], name:"meshBasicMaterial", material: new THREE.MeshBasicMaterial()}}/>
+ <Box props={{position:[ 1, 0, 0], name:"meshNormalMaterial", material: new THREE.MeshNormalMaterial()}}/>
+ <Box props={{position:[-1, 2, 0], name:"meshPhongMaterial", material: new THREE.MeshPhongMaterial()}}/>
+ <Box props={{position:[ 1, 2, 0], name:"meshStandardMaterial", material: new THREE.MeshStandardMaterial()}}/>
<OrbitControls />
<axesHelper args={[5]} />
<gridHelper />
<Stats />
</Canvas>
</div>
);
}
export default App;
で、実行。
出来た。
まとめ
特段、理解のムズいとこはなかったけど、TypeScriptに置き換えると、ホントにビルドが通らんかったのが苦しかった。
type BoxPropsを作成した
元のHPでは、wireframeプロパティを普通に使ってるけど、TypeScriptだと通らん。
BoxPropsを作って、MeshPropsをラップした。
useControls::onChangeの引数には型指定が必要。
TypeScriptだと当然なんやけど、気づいてなかった。ハマった~。
materialには、wireframe、flatShading、colorプロパティがない。
まさか、materialに上記のプロパティがないって思わなくって、原因判明に丸一日費やした。
結果的は、個別にキャストしたんだけど、もう少し、スマートな実装があると思う。
ムズかった~。
React+TypeScriptなWebアプリで、R3Fのtutorial11。(パラメータを設定できるやつ。Leva)
Discussion