💭

React+TypeScriptなWebアプリで、R3Fのtutorial14。(影(Shadow)を設定する)

2023/12/25に公開

Abstract

今回の参考はここ(Shadows)
影(Shadow)は、出す/出さない、受ける/受けないの設定がある。

  • ambientLight(環境光源)はShadow属性はない。
  • directionalLight(指向性光源(太陽光))、pointLight(点光源)、spotLight(線光源)にはShadow属性をつけれる。
  • 影を受け付ける設定 ... receiveShadow
  • 影を出す設定 ... castShadow

結論

今回の成果物はココ↓
https://github.com/aaaa1597/react-r3f-tutorial014

前提

手順

1.プロジェクト生成 -> VSCodeで開く

めんどいから、このスケルトンコードから始める。react-r3f-tutorial004
で、下記コマンドでフォルダ名とか整備する。

フォルダリネームとか
$ BaseProject=react-r3f-tutorial004
$ NewProject=react-r3f-tutorial014
$ 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

.eslintrc.js

ビルドエラー回避の設定

.eslintrc.js
     "rules": {
-        "react/no-unknown-property": ['error', { ignore: ['css', "args", 'wireframe'] }],
+        "react/no-unknown-property": ['error', { ignore: ['css', "args", 'wireframe', 'visible', 'intensity', 'position', 'castShadow', 'castShadow', 'receiveShadow', 'rotation-x']}],
     }

App.tsx

まず全体。

App.tsx
import React, {useRef} from 'react';
import './App.css';
import { Canvas, MeshProps, useFrame } from '@react-three/fiber'
import * as THREE from 'three'
+import { Stats, OrbitControls } from '@react-three/drei'
+import { useControls } from 'leva'

+const Lights = () => {
+  const ambientCtl = useControls('Ambient Light', {
+                      visible: false,
+                      intensity : {value: 1.0, min: 0, max: 1.0, step: 0.1}
+                    })
+  const directionalCtl = useControls('Directional Light', {
+                      visible: true,
+                      position : {x: 3.3, y: 1.0, z: 4.4},
+                      castShadow: true,
+                    })
+  const pointCtl = useControls('Point Light', {
+                      visible: false,
+                      position : {x: 2, y: 0, z: 0},
+                      castShadow: true,
+                    })
+  const spotCtl = useControls('Spot Light', {
+                      visible: false,
+                      position : {x: 3, y: 2.5, z: 1},
+                      castShadow: true,
+                    })
+
+  return (
+    <>
+      <ambientLight     visible={    ambientCtl.visible} intensity={ambientCtl.intensity}/>
+      <directionalLight visible={directionalCtl.visible} position ={[directionalCtl.position.x, directionalCtl.position.y, directionalCtl.position.z]} castShadow={directionalCtl.castShadow}/>
+      <pointLight       visible={      pointCtl.visible} position ={[      pointCtl.position.x,       pointCtl.position.y,       pointCtl.position.z]} castShadow={      pointCtl.castShadow}/>
+      <spotLight        visible={       spotCtl.visible} position ={[       spotCtl.position.x,        spotCtl.position.y,        spotCtl.position.z]} castShadow={       spotCtl.castShadow}/>
+    </>
+  )
+}

const Box = (props: MeshProps) => {
  const ref = useRef<THREE.Mesh>(null!)

  useFrame((_, delta) => {
    ref.current!.rotation.x += 1 * delta
    ref.current!.rotation.y += 1 * delta
  })
  
  return (
-    <mesh {...props} ref={ref}>
-      <boxGeometry />
-      <meshBasicMaterial color={0x00ff00} wireframe />
+   <mesh {...props} ref={ref} castShadow receiveShadow>
+     <icosahedronGeometry  args={[1, 1]} />
    </mesh>
  )
}

+const Floor = () => {
+  return (
+    <mesh rotation-x={-Math.PI / 2} receiveShadow>
+      <circleGeometry args={[10]} />
+      <meshStandardMaterial />
+    </mesh>
+  )
+}

const App = () => {
  return (
    <div style={{ width: "75vw", height: "75vh" }}>
      <Canvas camera={{ position: [4, 4, 1.5] }}>
+       <Lights />
-       <Box position={[0.75, 0, 0]} name="A" />
-       <Box position={[0.75, 0, 0]} name="B" />
+       <Box name="meshBasicMaterial"    position={[-2, 2, 0]} material={new THREE.MeshBasicMaterial   ({ color: 'yellow' })} />
+       <Box name="meshNormalMaterial"   position={[ 2, 2, 0]} material={new THREE.MeshNormalMaterial  ({ flatShading: true })} />
+       <Box name="meshPhongMaterial"    position={[-2, 0, 0]} material={new THREE.MeshPhongMaterial   ({ color: 'lime', flatShading: true })} />
+       <Box name="meshStandardMaterial" position={[ 2, 0, 0]} material={new THREE.MeshStandardMaterial({ color: 0xff0033, flatShading: true })} />
+       <Floor />
+       <OrbitControls target={[2, 2, 0]} />
+       <axesHelper args={[5]} />
+       <Stats />
      </Canvas>
    </div>
  );
}

export default App;

で、実行。


出来た!!

ポイント

光源にcastShadowの属性をつける.

directionalLight(指向性光源(太陽光))、pointLight(点光源)、spotLight(線光源)にShadow属性をつける。

App.tsx
<directionalLight castShadow/>
<pointLight castShadow>
<spotLight castShadow=/>

物体の方にreceiveShadowとcastShadowをつける。

  • 影を受け付ける設定 ... receiveShadow
  • 影を出す設定 ... castShadow

そんなにムズくはないかな。


React+TypeScriptなWebアプリで、R3Fのtutorial13。(光源)


React+TypeScriptなWebアプリで、R3Fのtutorial15。(useLoaderでテクスチャ読込み)

Discussion