1
0
hugo/content/blog/2024-08-01-react.md
2024-12-21 21:03:10 +09:00

218 lines
5.4 KiB
Markdown

+++
date = "2024-08-01"
tags = ["react", "vrm"]
title = "react-threeを使ってglbを表示する"
+++
今回はreactの`tsx`で書きます。
```sh
$ npx create-react-app galaxy --template typescript
```
これで準備はできましたが、設定ファイルを見てみます。
```json:tsconfig.json
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}
```
`es5`, `react-jsx`を使っているようです。
buildなどはwebpackではなく`react-scripts`ですね。
```json:package.json
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
```
```ts:src/App.tsx
import React from 'react';
import './App.css';
import { ThreeFiberGalaxy } from './pages/galaxy';
function App() {
return <ThreeFiberGalaxy />
}
export default App;
```
今回はこれを改造していきます。
[package.json](https://git.syui.ai/ai/star/src/branch/main/galaxy-react/package.json)
```ts:src/pages/galaxy.tsx
// https://gist.github.com/artokun/fb7f0c68a01ba5d9813abb3ccce254c4
import * as THREE from 'three'
import { Points, useGLTF } from '@react-three/drei'
import { GLTF } from 'three-stdlib'
import { useFrame, Canvas } from '@react-three/fiber'
import { useMemo, useRef } from 'react'
import { EffectComposer, SelectiveBloom } from '@react-three/postprocessing'
type GLTFResult = GLTF & {
nodes: {
Object_2: THREE.Mesh
}
materials: {
['Scene_-_Root']: THREE.PointsMaterial
}
}
export function Galaxy(props: JSX.IntrinsicElements['group']) {
const ref = useRef<THREE.Group>(null!)
const galaxyCenterLightRef = useRef<THREE.PointLight>(null!)
const { nodes } = useGLTF('./models/galaxy.glb') as GLTFResult
const [positions, colors] = useMemo(() => {
nodes.Object_2.geometry.center()
const positions = new Float32Array(
nodes.Object_2.geometry.attributes.position.array.buffer
)
const colors = new Float32Array(positions.length)
const getDistanceToCenter = (x: number, y: number, z: number) =>
Math.sqrt(x * x + y * y + z * z)
// make colors closer to 0,0,0 be more reddish and colors further away be more blueish
const color = new THREE.Color()
for (let i = 0; i < positions.length; i += 3) {
const x = positions[i]
const y = positions[i + 1]
const z = positions[i + 2]
const distanceToCenter = getDistanceToCenter(x, y, z)
const normalizedDistanceToCenter = distanceToCenter / 100
// make colors closer to 0,0,0 be more reddish and colors further away be more blueish (do not use hsl)
// color.setHSL(
// (0.15 * (0.21 + Math.cos(distanceToCenter * 0.02))) / 2,
// 0.75,
// 0.6
// )
color.setRGB(
Math.cos(normalizedDistanceToCenter),
THREE.MathUtils.randFloat(0, 0.8),
Math.sin(normalizedDistanceToCenter)
)
color.toArray(colors, i)
}
return [positions, colors]
}, [nodes])
//const starTexture = useLoader(THREE.TextureLoader, '/star.png')
// slowly rotate the galaxy
useFrame(({ clock }) => {
ref.current.rotation.z = clock.getElapsedTime() / 5
// zoom in and out
// ref.current.scale.setScalar(Math.sin(clock.getElapsedTime() / 2) + 1.5)
})
// make particles glow
return (
<group {...props} dispose={null} ref={ref}>
<pointLight
position={[0, 0, 0]}
ref={galaxyCenterLightRef}
intensity={0.5}
/>
<Points scale={0.05} positions={positions} colors={colors}>
<pointsMaterial
//map={starTexture}
transparent
depthWrite={false}
vertexColors
opacity={0.4}
depthTest
size={0.01}
/>
</Points>
<EffectComposer autoClear={false}>
<SelectiveBloom
intensity={2}
luminanceThreshold={0.001}
luminanceSmoothing={0.225}
lights={[galaxyCenterLightRef]}
/>
</EffectComposer>
</group>
)
}
useGLTF.preload('./models/galaxy.glb')
```
`App.tsx`で読み込むため以下を追記します。
```ts:src/pages/galaxy.tsx
export const ThreeFiberGalaxy = () => {
return (
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Galaxy position={[0, 0, 0]} />
</Canvas>
)
}
```
`public/models/galaxy.glb`を置いてください。とりあえずこれで完了です。
```sh
$ npm run start
```
controlを追加します。
```sh
import { Points, useGLTF, OrbitControls } from '@react-three/drei'
export const ThreeFiberGalaxy = () => {
return (
<Canvas>
<OrbitControls />
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Galaxy position={[0, 0, 0]} />
</Canvas>
)
}
```
できましたね。大体はこんな感じになります。
他のカスタマイズについては`perplexity.ai`にでも聞いてみてください。
<iframe src="https://yui.syui.ai/pkg/galaxy2" scrolling="no" width="100%" height="450px" allowfullscreen></iframe>