💬
React+TypeScriptなWebアプリで、R3Fのtutorial13。(光源(lights)を設定)
Abstract
今回の参考はここ(Lights)。
光源の下記4つを、全部実装してみた。
- ambientLight ... 環境光源
- directionalLight ... 指向性光源(太陽光)
- pointLight ... 点光源
- spotLight ... 線光源
結論
今回の成果物はココ↓
前提
- React+Typescriptの開発環境は構築済 Ubuntu22.04+VSCode+React+TypeScriptの開発環境を構築してみた。
- このスケルトンコードから始める。react-r3f-tutorial012
手順
1.プロジェクト生成 -> VSCodeで開く
めんどいから、このスケルトンコードから始める。react-r3f-tutorial012
で、下記コマンドでフォルダ名とか整備する。
フォルダリネームとか
$ BaseProject=react-r3f-tutorial012
$ NewProject=react-r3f-tutorial013
$ 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 = (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)
- },
- },
- })
+const Lights = () => {
+ const ambientRef = useRef<THREE.AmbientLight>(null!)
+ const directionalRef = useRef<THREE.DirectionalLight>(null!)
+ const pointRef = useRef<THREE.PointLight>(null!)
+ const spotRef = useRef<THREE.SpotLight>(null!)
+
+ useControls('Ambient Light', {
+ visible: {
+ onChange: (v) => {
+ ambientRef.current.visible = v
+ },
+ color: {
+ value: 'white',
+ onChange: (v) => {
+ ambientRef.current.color = new THREE.Color(v)
+ },
+ },
+ });
+
+ useControls('Directional Light', {
+ visible: {
+ directionalRef.current.visible = v
+ },
+ },
+ position: {
+ value: [1,1,1],
+ onChange: (v) => {
+ directionalRef.current.position.x = v[0]
+ directionalRef.current.position.y = v[1]
+ directionalRef.current.position.z = v[2]
+ value: 'white',
+ directionalRef.current.color = new THREE.Color(v)
+ });
+
+ useControls('Point Light', {
+ visible: {
+ value: false,
+ onChange: (v) => {
+ pointRef.current.visible = v
+ },
+ },
+ position: {
+ value: [3,0,0],
+ onChange: (v) => {
+ pointRef.current.position.x = v[0]
+ pointRef.current.position.y = v[1]
+ pointRef.current.position.z = v[2]
+ },
+ },
+ color: {
+ value: 'white',
+ onChange: (v) => {
+ pointRef.current.color = new THREE.Color(v)
+ },
+ },
+ })
+
+ useControls('Spot Light', {
+ visible: {
+ value: false,
+ onChange: (v) => {
+ spotRef.current.visible = v
+ },
+ },
+ position: {
+ value: [3,3,3],
+ onChange: (v) => {
+ spotRef.current.position.x = v[0]
+ spotRef.current.position.x = v[1]
+ spotRef.current.position.x = v[2]
+ },
+ },
+ color: {
+ value: 'white',
+ onChange: (v) => {
+ spotRef.current.color = new THREE.Color(v)
+ },
+ },
+ })
return (
<mesh {...boxprops.props} ref={ref}>
<icosahedronGeometry args={[1, 1]} />
</mesh>
)
}
const Lights = () => {
const ambientRef = useRef<THREE.AmbientLight>(null!)
const directionalRef = useRef<THREE.DirectionalLight>(null!)
const pointRef = useRef<THREE.PointLight>(null!)
const spotRef = useRef<THREE.SpotLight>(null!)
useControls('Ambient Light', {
visible: {
value: false,
onChange: (v) => {
ambientRef.current.visible = v
},
},
color: {
value: 'white',
onChange: (v) => {
ambientRef.current.color = new THREE.Color(v)
},
},
});
useControls('Directional Light', {
visible: {
value: true,
onChange: (v: boolean) => {
directionalRef.current.visible = v
},
},
position: {
value: [1,1,1],
onChange: (v) => {
directionalRef.current.position.x = v[0]
directionalRef.current.position.y = v[1]
directionalRef.current.position.z = v[2]
},
},
color: {
value: 'white',
onChange: (v: string) => {
directionalRef.current.color = new THREE.Color(v)
},
},
});
useControls('Point Light', {
visible: {
value: false,
onChange: (v) => {
pointRef.current.visible = v
},
},
position: {
value: [3,0,0],
onChange: (v) => {
pointRef.current.position.x = v[0]
pointRef.current.position.y = v[1]
pointRef.current.position.z = v[2]
},
},
color: {
value: 'white',
onChange: (v) => {
pointRef.current.color = new THREE.Color(v)
},
},
})
useControls('Spot Light', {
visible: {
value: false,
onChange: (v) => {
spotRef.current.visible = v
},
},
position: {
value: [3,3,3],
onChange: (v) => {
spotRef.current.position.x = v[0]
spotRef.current.position.x = v[1]
spotRef.current.position.x = v[2]
},
},
color: {
value: 'white',
onChange: (v) => {
spotRef.current.color = new THREE.Color(v)
},
},
})
return (
<>
<ambientLight ref={ambientRef} />
<directionalLight ref={directionalRef} />
<pointLight ref={pointRef} />
<spotLight ref={spotRef} />
</>
)
}
const App = () => {
return (
<div style={{ width: "75vw", height: "75vh" }}>
<Canvas camera={{ position: [3, 1, 2] }}>
+ <Lights />
<Box props={{position:[-1, 0, 0], name:"meshBasicMaterial", material: new THREE.MeshBasicMaterial({ color: 'yellow'})}}/>
<Box props={{position:[ 1, 0, 0], name:"meshNormalMaterial", material: new THREE.MeshNormalMaterial({ flatShading: true })}}/>
<Box props={{position:[-1, 2, 0], name:"meshPhongMaterial", material: new THREE.MeshPhongMaterial({ color: 'lime', flatShading: true })}}/>
<Box props={{position:[ 1, 2, 0], name:"meshStandardMaterial", material: new THREE.MeshStandardMaterial({ color: 0xff0033, flatShading: true })}}/>
- <OrbitControls />
<OrbitControls target={[2, 2, 0]} />
<axesHelper args={[5]} />
<gridHelper />
<Stats />
</Canvas>
</div>
);
}
export default App;
で、実行
出来た!!
まとめ
変更点は、すごい量だけど、実際には、ambientLight(環境光源)、directionalLight(指向性光源(太陽光))、pointLight(点光源)、spotLight(線光源)の4行が重要なところ。
ambientLight(環境光源)
要は、<ambientLight/> を設定するだけ。
directionalLight(指向性光源)
<directionalLight/> を設定するだけ。
pointLight(点光源)
<pointLight/> を設定するだけ。
spotLight(線光源)
<spotLight/> を設定するだけ。
また、TypeScriptにしたことで、ビルドが通らんのには苦しんだ。
React+TypeScriptなWebアプリで、R3Fのtutorial12。(Materials)
Discussion