[Electron] Vite+Electron+React+Three.js 2 (静的アセット・シェーダーファイルの読み込み)
この記事は[Electron] Vite+Electron+React+Three.js 1 (環境構築)の続きです。
Vite+Electron+React+Three.jsで、アセット(画像ファイル、3Dモデル)やシェーダーファイルを読み込む方法を解説します。
サンプルプロジェクト
https://github.com/yasuhirohoshino/Electron_Examples/tree/main/Electron_R3F
実行環境
Windows 10 Pro 22H2
静的アセットの配置・読み込み
src/renderer
ディレクトリ以下に、public
ディレクトリを作成し、アセットファイルを配置します。
public
ディレクトリ以下のファイルは、./
からの相対パスで読み込むことができます。
...
import { useTexture } from '@react-three/drei'
function Img() {
const colorMap = useTexture('./images/img_1.jpg')
return (
<mesh>
<planeGeometry args={[2, 2]} />
<meshBasicMaterial map={colorMap} side={THREE.DoubleSide} />
</mesh>
)
}
...
glTFやFBXなども、同様に読み込めます。
import { AnimationMixer, Mesh } from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
function FBXModel() {
const obj = useLoader(FBXLoader, './models/man_walking.fbx')
const [mixer] = useState(() => new AnimationMixer(obj))
const action = mixer.clipAction(obj.animations[0])
action.play()
obj.traverse((child) => {
if (child instanceof Mesh) {
child.castShadow = true
child.receiveShadow = true
}
})
useFrame((_state, delta) => {
mixer.update(delta)
})
return (
<mesh>
<primitive object={obj} />
</mesh>
)
}
function GLTFModel() {
const gltf = useLoader(GLTFLoader, './models/gltf/alarm_clock_01_1k.gltf')
gltf.scene.traverse((child) => {
child.castShadow = true
child.receiveShadow = true
})
return (
<mesh>
<primitive object={gltf.scene} />
</mesh>
)
}
ただし、glbファイルを読み込む場合は、エラーが発生するため、HTML内のmetaタグで、Content-Security-Policy
のconnect-src
にblob:
を追加する必要があります。
<meta
http-equiv="Content-Security-Policy"
content="worker-src blob: ; connect-src 'self' https://market-assets.fra1.cdn.digitaloceanspaces.com/ https://fonts.gstatic.com/ blob:; default-src 'self'; script-src 'self' blob:; style-src 'self' 'unsafe-inline'"
/>
シェーダーファイルの配置・読み込み
src/renderer/src
以下に任意のディレクトリを作成し、シェーダーファイルを配置します。
また、以下のような.d.ts
ファイルを作成し、src/renderer/src
以下に配置します。
declare module '*.vert' {
const value: string
export default value
}
declare module '*.frag' {
const value: string
export default value
}
declare module '*.glsl' {
const value: string
export default value
}
シェーダーのコード内で#pragma include
を用い別のシェーダーファイルを読み込みたい場合、npm i -D vite-plugin-glsl
でvite-plugin-glslをインストールし、electron.vite.config.ts
に以下の設定を追加します。
...
import glsl from 'vite-plugin-glsl';
export default defineConfig({
...
renderer: {
...
plugins: [react(), glsl()],
}
})
以下はRenderer内でシェーダーを読み込んだ際のサンプルコードです。
import testShader_vert from './shaders/test.vert'
import testShader_frag from './shaders/test.frag'
function ShaderMesh(props) {
const matRef = useRef<THREE.ShaderMaterial>(null!)
useFrame((state) => {
const { clock } = state
matRef.current.uniforms.time = { value: clock.getElapsedTime() * 0.1 }
})
return (
<group {...props}>
<mesh position={[0.0, 1.0, 0.0]}>
<planeGeometry args={[2, 2]} />
<shaderMaterial
ref={matRef}
vertexShader={testShader_vert}
fragmentShader={testShader_frag}
side={THREE.DoubleSide}
alphaTest={0.5}
/>
</mesh>
<Caption>GLSL</Caption>
</group>
)
}