はじめに
Paul氏とR3Fコミュニティに感謝します。
R3F(ReactThreeFiber)はThree.jsをReactで簡単に使えるようにしたライブラリです。
R3Fのコミュニティは、毎日のように面白いプロジェクトやリソースが公開されます。
その中で、今回は先月OffscreenCanvasに対応されたということなので早速使ってみます。
Offscreenとは、WebGLでのレンダリングをメインスレッド外、つまりはWebWorkerで実行し、
メインスレッドの処理に依存せずに描画できるため、パフォーマンスの向上が狙えます。
このライブラリのすごいところは、WebWorkerを意識することなく、実装できることです。
サンプルの実装
# Create: ReactApp
npx create-react-app oscreen --template typescript
# install
npm install three @types/three @react-three/fiber @react-three/drei @react-three/offscreen
# 実行
npm start
ディレクトリ構成
oscreen
└ src
┝ App.tsx
┝ Scene.tsx
└ worker.jsx
ソースコード
App.tsx
import React, { lazy } from 'react';
import { Canvas } from "@react-three/offscreen"
const Scene = lazy(() => import("./Scene"))
const worker = new Worker(new URL("./worker.jsx", import.meta.url), { type: "module" })
function App() {
return (
<div style={{ height: "100vh" }}>
<Canvas
dpr={[1, 1.5]}
camera={{ position: [0, 0, 10], fov: 25 }}
worker={worker}
fallback={<Scene />}
/>
</div>
);
}
export default App;
Scene.tsx
import React, { useRef, useState } from 'react'
import { useFrame } from '@react-three/fiber'
import { useGLTF, Center, ContactShadows, Environment, CameraControls } from '@react-three/drei'
const Scene = () => {
const mesh = useRef<any>()
const { nodes, materials } = useGLTF('/pmndrs.glb') as any;
const [hovered, setHover] = useState(false)
const [active, setActive] = useState(false)
const color = hovered ? 'hotpink' : 'orange'
useFrame((state, delta) => {
mesh.current.rotation.x += delta / 2
mesh.current.rotation.y += delta / 2
})
return (
<>
<Center ref={mesh}>
<mesh
geometry={nodes.cube.geometry}
material={materials.base}
material-color={color}
scale={active ? 0.3 : 0.25}
onClick={(e) => (e.stopPropagation(), setActive(!active))}
onPointerOver={(e) => (e.stopPropagation(), setHover(true))}
onPointerOut={(e) => setHover(false)}
/>
</Center>
<ContactShadows color={color} position={[0, -1.5, 0]} blur={3} opacity={0.75} />
<ambientLight />
<pointLight position={[10, 10, 5]} />
<Environment preset="city">
</Environment>
<CameraControls minPolarAngle={Math.PI / 2} maxPolarAngle={Math.PI / 2} />
</>
)
}
export default Scene;
worker.jsx
import React from 'react'
import { render } from '@react-three/offscreen'
import Scene from './Scene'
render(<Scene />)
実行結果
ReactのStateやそのほかのdreiリソース、
fiberのuseFrameなどを利用できることを確認しました。
その他のpmndrsのリソースが使えるかどうか
- PostProcessing/Shaderは使えるか?
- WebXRは使えるか?
これらを確認していきます
PostProcessing/Shaderは使えるか?
Scene.tsx
import React, { useRef, useState, useMemo, useEffect } from 'react'
import { useFrame, applyProps, useLoader } from '@react-three/fiber'
import { useGLTF, Center, ContactShadows, Environment, Float, OrbitControls, Lightformer, MeshReflectorMaterial } from '@react-three/drei'
import { EffectComposer, SSR, Bloom, LUT } from "@react-three/postprocessing";
import { Mesh, MeshPhysicalMaterial, Texture } from 'three';
import { LUTCubeLoader } from 'postprocessing'
const Scene = () => {
return (
<>
<color attach="background" args={['#15151a']} />
<Lambo rotation={[0, Math.PI / 1.5, 0]} scale={0.015} />
<hemisphereLight intensity={0.5} />
<ContactShadows resolution={1024} frames={1} position={[0, -1.16, 0]} scale={15} blur={0.5} opacity={1} far={20} />
<mesh scale={4} position={[3, -1.161, -1.5]} rotation={[-Math.PI / 2, 0, Math.PI / 2.5]}>
<ringGeometry args={[0.9, 1, 4, 1]} />
<meshStandardMaterial color="red" roughness={0.75} />
</mesh>
<mesh scale={4} position={[-3, -1.161, -1]} rotation={[-Math.PI / 2, 0, Math.PI / 2.5]}>
<ringGeometry args={[0.9, 1, 3, 1]} />
<meshStandardMaterial color="gold" roughness={0.75} />
</mesh>
<mesh rotation={[-Math.PI/2, 0, 0]} position={[0, -1.162, 0]} >
<planeBufferGeometry args={[32, 32]}/>
<MeshReflectorMaterial mirror={1} resolution={1024} />
</mesh>
<Environment resolution={512} preset='city' frames={Infinity}>
{/* Ceiling */}
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, -9]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, -6]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, -3]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 0]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 3]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 6]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 9]} scale={[10, 1, 1]} />
{/* Sides */}
<Lightformer intensity={2} rotation-y={Math.PI / 2} position={[-50, 2, 0]} scale={[100, 2, 1]} />
<Lightformer intensity={2} rotation-y={-Math.PI / 2} position={[50, 2, 0]} scale={[100, 2, 1]} />
<Lightformer rotation-y={-Math.PI / 2} position={[10, 1, 0]} scale={[20, 1, 1]} />
{/* Accent (gold) */}
<Float speed={5} floatIntensity={2} rotationIntensity={2}>
<Lightformer form="ring" color="gold" intensity={1} scale={10} position={[-15, 4, -18]} target={[0, 0, 0]} />
</Float>
{/* Key */}
<Lightformer form="ring" color="gold" intensity={10} scale={2} position={[10, 5, 10]} onUpdate={(self) => self.lookAt(0, 0, 0)} />
</Environment>
<OrbitControls enablePan={false} minPolarAngle={Math.PI / 2.2} maxPolarAngle={Math.PI / 2.2} autoRotate autoRotateSpeed={0.4} />
<PostProcess />
</>
)
}
const Lambo = (props: any) => {
const { scene, nodes, materials } = useGLTF('/lambo.glb') as any;
useMemo(() => {
// ⬇⬇⬇ All this is probably better fixed in Blender ...
Object.values(nodes).forEach((node) => {
if (node instanceof Mesh && node.isMesh) {
// Fix glas, normals look messed up in the original, most likely deformed meshes bc of compression :/
if (node.name.startsWith('glass')) node.geometry.computeVertexNormals()
// Fix logo, too dark
if (node.name === 'silver_001_BreakDiscs_0') node.material = applyProps(materials.BreakDiscs.clone(), { color: '#ddd' })
}
})
// Fix windows, they have to be inset some more
nodes['glass_003'].scale.setScalar(2.7)
// Fix inner frame, too light
applyProps(materials.FrameBlack, { metalness: 0.75, roughness: 0, color: 'black' })
// Wheels, change color from chrome to black matte
applyProps(materials.Chrome, { metalness: 1, roughness: 0, color: '#333' })
applyProps(materials.BreakDiscs, { metalness: 0.2, roughness: 0.2, color: '#555' })
applyProps(materials.TiresGum, { metalness: 0, roughness: 0.4, color: '#181818' })
applyProps(materials.GreyElements, { metalness: 0, color: '#292929' })
// Make front and tail LEDs emit light
applyProps(materials.emitbrake, { emissiveIntensity: 3, toneMapped: false })
applyProps(materials.LightsFrontLed, { emissiveIntensity: 3, toneMapped: false })
// Paint, from yellow to black
nodes.yellow_WhiteCar_0.material = new MeshPhysicalMaterial({
roughness: 0.3,
metalness: 0.05,
color: '#820000',
envMapIntensity: 0.75,
clearcoatRoughness: 0,
clearcoat: 1
})
}, [nodes, materials])
return <primitive object={scene} {...props} />
}
const PostProcess = () => {
const [texture, setTexture] = useState<Texture>();
useEffect(() => {
const loader = new LUTCubeLoader();
loader.load('/F-6800-STD.cube', (loadedTexture: Texture) => {
setTexture(loadedTexture);
});
}, []);
let lut: JSX.Element = (<></>);
if (texture){
lut = <LUT lut={texture} />
}
return (
<EffectComposer disableNormalPass>
<Bloom luminanceThreshold={0.2} mipmapBlur luminanceSmoothing={0} intensity={1.45} />
{lut}
</EffectComposer>
)
}
export default Scene;
実行結果
ちゃんと使えそうでした。
WebXRは使えるか
import React, { useRef, useState, useMemo, useEffect } from 'react'
import { useFrame, applyProps, useLoader } from '@react-three/fiber'
import { useGLTF, useFont, Text3D, ContactShadows, Environment, Float, OrbitControls, Lightformer, MeshReflectorMaterial } from '@react-three/drei'
import { EffectComposer, Bloom, LUT } from "@react-three/postprocessing";
import { Mesh, MeshPhysicalMaterial, Texture } from 'three';
import { LUTCubeLoader } from 'postprocessing';
import { XR, startSession } from "@react-three/xr";
const Scene = () => {
const font = useFont("/MPLUS.json");
const fontdata = font.data;
const startXR = () => {
startSession("immersive-vr", undefined);
}
return (
<XR>
<Text3D font={fontdata} rotation={[0, Math.PI / 1.5, 0]} position={[-1.25, 3, 3.5]} onClick={startXR}>
XRで実行
</Text3D>
<color attach="background" args={['#15151a']} />
<Lambo rotation={[0, Math.PI / 1.5, 0]} scale={0.015} />
<hemisphereLight intensity={0.5} />
<ContactShadows resolution={1024} frames={1} position={[0, -1.16, 0]} scale={15} blur={0.5} opacity={1} far={20} />
<mesh scale={4} position={[3, -1.161, -1.5]} rotation={[-Math.PI / 2, 0, Math.PI / 2.5]}>
<ringGeometry args={[0.9, 1, 4, 1]} />
<meshStandardMaterial color="red" roughness={0.75} />
</mesh>
<mesh scale={4} position={[-3, -1.161, -1]} rotation={[-Math.PI / 2, 0, Math.PI / 2.5]}>
<ringGeometry args={[0.9, 1, 3, 1]} />
<meshStandardMaterial color="gold" roughness={0.75} />
</mesh>
<mesh rotation={[-Math.PI/2, 0, 0]} position={[0, -1.162, 0]} >
<planeBufferGeometry args={[32, 32]}/>
<MeshReflectorMaterial mirror={1} resolution={1024} />
</mesh>
<Environment resolution={512} preset='city' frames={Infinity}>
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, -9]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, -6]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, -3]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 0]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 3]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 6]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 9]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-y={Math.PI / 2} position={[-50, 2, 0]} scale={[100, 2, 1]} />
<Lightformer intensity={2} rotation-y={-Math.PI / 2} position={[50, 2, 0]} scale={[100, 2, 1]} />
<Lightformer rotation-y={-Math.PI / 2} position={[10, 1, 0]} scale={[20, 1, 1]} />
<Float speed={5} floatIntensity={2} rotationIntensity={2}>
<Lightformer form="ring" color="gold" intensity={1} scale={10} position={[-15, 4, -18]} target={[0, 0, 0]} />
</Float>
<Lightformer form="ring" color="gold" intensity={10} scale={2} position={[10, 5, 10]} onUpdate={(self) => self.lookAt(0, 0, 0)} />
</Environment>
<OrbitControls enablePan={false} minPolarAngle={Math.PI / 2.2} maxPolarAngle={Math.PI / 2.2} autoRotate autoRotateSpeed={0.4} />
<PostProcess />
</XR>
)
}
const Lambo = (props: any) => {
const { scene, nodes, materials } = useGLTF('/lambo.glb') as any;
useMemo(() => {
// ⬇⬇⬇ All this is probably better fixed in Blender ...
Object.values(nodes).forEach((node) => {
if (node instanceof Mesh && node.isMesh) {
// Fix glas, normals look messed up in the original, most likely deformed meshes bc of compression :/
if (node.name.startsWith('glass')) node.geometry.computeVertexNormals()
// Fix logo, too dark
if (node.name === 'silver_001_BreakDiscs_0') node.material = applyProps(materials.BreakDiscs.clone(), { color: '#ddd' })
}
})
// Fix windows, they have to be inset some more
nodes['glass_003'].scale.setScalar(2.7)
// Fix inner frame, too light
applyProps(materials.FrameBlack, { metalness: 0.75, roughness: 0, color: 'black' })
// Wheels, change color from chrome to black matte
applyProps(materials.Chrome, { metalness: 1, roughness: 0, color: '#333' })
applyProps(materials.BreakDiscs, { metalness: 0.2, roughness: 0.2, color: '#555' })
applyProps(materials.TiresGum, { metalness: 0, roughness: 0.4, color: '#181818' })
applyProps(materials.GreyElements, { metalness: 0, color: '#292929' })
// Make front and tail LEDs emit light
applyProps(materials.emitbrake, { emissiveIntensity: 3, toneMapped: false })
applyProps(materials.LightsFrontLed, { emissiveIntensity: 3, toneMapped: false })
// Paint, from yellow to black
nodes.yellow_WhiteCar_0.material = new MeshPhysicalMaterial({
roughness: 0.3,
metalness: 0.05,
color: '#820000',
envMapIntensity: 0.75,
clearcoatRoughness: 0,
clearcoat: 1
})
}, [nodes, materials])
return <primitive object={scene} {...props} />
}
const PostProcess = () => {
const [texture, setTexture] = useState<Texture>();
useEffect(() => {
const loader = new LUTCubeLoader();
loader.load('/F-6800-STD.cube', (loadedTexture: Texture) => {
setTexture(loadedTexture);
});
}, []);
let lut: JSX.Element = (<></>);
if (texture){
lut = <LUT lut={texture} />
}
return (
<EffectComposer disableNormalPass>
<Bloom luminanceThreshold={0.2} mipmapBlur luminanceSmoothing={0} intensity={1.45} />
{lut}
</EffectComposer>
)
}
export default Scene;
重くて表示はできないようですが、XRも実行可能のようです。
![画像1.png](https://qiita-image-store.s3.ap-northeast-
1.amazonaws.com/0/493888/2844b8f4-3c0d-8f98-cecb-852a544b74e2.png)
最後にパフォーマンス比較
動くBoxをさらに500個おいて比較しました。
通常:30~45FPS
OScreen:40~50FPS
単純な比較のみでも効果があった。
この上に通常のReactのHTMLレンダリング等でプロジェクトを作りこむと、この差は大きくなるんだと思います。
比較ソースコード
import React, { lazy } from 'react';
// import { Canvas } from "@react-three/offscreen"
import { Canvas } from "@react-three/fiber";
const Scene = lazy(() => import("./Scene"))
const worker = new Worker(new URL("./worker.jsx", import.meta.url), { type: "module" })
function App() {
return (
<div style={{ height: "100vh" }}>
{/* <Canvas
gl={{ logarithmicDepthBuffer: true, antialias: false }}
dpr={[1, 1.5]}
camera={{ position: [0, 0, -16], fov: 25 }}
worker={worker}
fallback={<Scene />}
/> */}
<Canvas
gl={{ logarithmicDepthBuffer: true, antialias: false }}
dpr={[1, 1.5]}
camera={{ position: [0, 0, -16], fov: 25 }}
>
<Scene/>
</Canvas>
</div>
);
}
import React, { lazy } from 'react';
import { Canvas } from "@react-three/offscreen"
// import { Canvas } from "@react-three/fiber";
const Scene = lazy(() => import("./Scene"))
const worker = new Worker(new URL("./worker.jsx", import.meta.url), { type: "module" })
function App() {
return (
<div style={{ height: "100vh" }}>
<Canvas
gl={{ logarithmicDepthBuffer: true, antialias: false }}
dpr={[1, 1.5]}
camera={{ position: [0, 0, -16], fov: 25 }}
worker={worker}
fallback={<Scene />}
/>
{/* <Canvas
gl={{ logarithmicDepthBuffer: true, antialias: false }}
dpr={[1, 1.5]}
camera={{ position: [0, 0, -16], fov: 25 }}
>
<Scene/>
</Canvas> */}
</div>
);
}
export default App;
import React, { useRef, useState, useMemo, useEffect, Suspense } from 'react'
import { useFrame, applyProps, useLoader } from '@react-three/fiber'
import { useGLTF, useFont, Text3D, ContactShadows, Environment, Float, OrbitControls, Lightformer, MeshReflectorMaterial } from '@react-three/drei'
import { EffectComposer, Bloom, LUT } from "@react-three/postprocessing";
import { Color, Mesh, MeshPhysicalMaterial, Texture, Vector3 } from 'three';
import { LUTCubeLoader } from 'postprocessing';
import { XR, startSession } from "@react-three/xr";
import { Perf } from "r3f-perf";
const Scene = () => {
const font = useFont("/MPLUS.json");
const fontdata = font.data;
const startXR = () => {
startSession("immersive-vr", undefined);
}
return (
<XR>
<Text3D font={fontdata} rotation={[0, Math.PI / 1.5, 0]} position={[0, 2.5, 3.5]} onClick={startXR}>
ピッカピカ
</Text3D>
<Text3D font={fontdata} size={0.45} rotation={[0, Math.PI / 1.5, 0]} position={[0, 1.5, 1.75]}>
R3Fは楽しい
</Text3D>
<color attach="background" args={['#15151a']} />
<Lambo rotation={[0, Math.PI / 1.5, 0]} scale={0.015} />
<hemisphereLight intensity={0.5} />
<ContactShadows resolution={1024} frames={1} position={[0, -1.16, 0]} scale={15} blur={0.5} opacity={1} far={20} />
<mesh scale={4} position={[3, -1.161, -1.5]} rotation={[-Math.PI / 2, 0, Math.PI / 2.5]}>
<ringGeometry args={[0.9, 1, 4, 1]} />
<meshStandardMaterial color="red" roughness={0.75} />
</mesh>
<mesh scale={4} position={[-3, -1.161, -1]} rotation={[-Math.PI / 2, 0, Math.PI / 2.5]}>
<ringGeometry args={[0.9, 1, 3, 1]} />
<meshStandardMaterial color="gold" roughness={0.75} />
</mesh>
<mesh rotation={[-Math.PI/2, 0, 0]} position={[0, -1.162, 0]} >
<planeBufferGeometry args={[32, 32]}/>
<MeshReflectorMaterial mirror={1} resolution={1024} />
</mesh>
<Environment resolution={512} preset='city' frames={Infinity}>
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, -9]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, -6]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, -3]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 0]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 3]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 6]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-x={Math.PI / 2} position={[0, 4, 9]} scale={[10, 1, 1]} />
<Lightformer intensity={2} rotation-y={Math.PI / 2} position={[-50, 2, 0]} scale={[100, 2, 1]} />
<Lightformer intensity={2} rotation-y={-Math.PI / 2} position={[50, 2, 0]} scale={[100, 2, 1]} />
<Lightformer rotation-y={-Math.PI / 2} position={[10, 1, 0]} scale={[20, 1, 1]} />
<Float speed={5} floatIntensity={2} rotationIntensity={2}>
<Lightformer form="ring" color="gold" intensity={1} scale={10} position={[-15, 4, -18]} target={[0, 0, 0]} />
</Float>
<Lightformer form="ring" color="gold" intensity={10} scale={2} position={[10, 5, 10]} onUpdate={(self) => self.lookAt(0, 0, 0)} />
</Environment>
<OrbitControls enablePan={false} minPolarAngle={Math.PI / 2.2} maxPolarAngle={Math.PI / 2.2} autoRotate autoRotateSpeed={0.4} />
<PostProcess />
{[...Array(1000)].map((_, i) => (
<AnimationBox key={i} />
))}
<Perf position={"bottom-right"} />
</XR>
)
}
const Lambo = (props: any) => {
const { scene, nodes, materials } = useGLTF('/lambo.glb') as any;
useMemo(() => {
// ⬇⬇⬇ All this is probably better fixed in Blender ...
Object.values(nodes).forEach((node) => {
if (node instanceof Mesh && node.isMesh) {
// Fix glas, normals look messed up in the original, most likely deformed meshes bc of compression :/
if (node.name.startsWith('glass')) node.geometry.computeVertexNormals()
// Fix logo, too dark
if (node.name === 'silver_001_BreakDiscs_0') node.material = applyProps(materials.BreakDiscs.clone(), { color: '#ddd' })
}
})
// Fix windows, they have to be inset some more
nodes['glass_003'].scale.setScalar(2.7)
// Fix inner frame, too light
applyProps(materials.FrameBlack, { metalness: 0.75, roughness: 0, color: 'black' })
// Wheels, change color from chrome to black matte
applyProps(materials.Chrome, { metalness: 1, roughness: 0, color: '#333' })
applyProps(materials.BreakDiscs, { metalness: 0.2, roughness: 0.2, color: '#555' })
applyProps(materials.TiresGum, { metalness: 0, roughness: 0.4, color: '#181818' })
applyProps(materials.GreyElements, { metalness: 0, color: '#292929' })
// Make front and tail LEDs emit light
applyProps(materials.emitbrake, { emissiveIntensity: 3, toneMapped: false })
applyProps(materials.LightsFrontLed, { emissiveIntensity: 3, toneMapped: false })
// Paint, from yellow to black
nodes.yellow_WhiteCar_0.material = new MeshPhysicalMaterial({
roughness: 0.3,
metalness: 0.05,
color: '#820000',
envMapIntensity: 0.75,
clearcoatRoughness: 0,
clearcoat: 1
})
}, [nodes, materials])
return <primitive object={scene} {...props} />
}
const AnimationBox = () => {
const ref = useRef<any>();
const [speed] = useState(Math.random() * 0.05 + 0.01);
const p = new Vector3(
Math.random() * 30 - 15,
Math.random() * 3,
Math.random() * 30 - 15
);
const size = 0.25;
const reverse = Math.random() > 0.5? true: false;
const color = useMemo(() => {
return new Color().setHSL(Math.random(), 1.0, 0.5);
}, []);
useFrame((state) => {
if (ref.current) {
if (reverse){
ref.current.position.y -= Math.sin(state.clock.getElapsedTime()) * speed;
}
else{
ref.current.position.y += Math.sin(state.clock.getElapsedTime()) * speed;
}
}
});
return (
<mesh ref={ref} position={p} castShadow receiveShadow>
<boxBufferGeometry attach="geometry" args={[size, size, size]} />
<meshStandardMaterial attach="material" color={color} />
</mesh>
);
}
const PostProcess = () => {
const [texture, setTexture] = useState<Texture>();
useEffect(() => {
const loader = new LUTCubeLoader();
loader.load('/F-6800-STD.cube', (loadedTexture: Texture) => {
setTexture(loadedTexture);
});
}, []);
let lut: JSX.Element = (<></>);
if (texture){
lut = <LUT lut={texture} />
}
return (
<EffectComposer disableNormalPass>
<Bloom luminanceThreshold={0.2} mipmapBlur luminanceSmoothing={0} intensity={1.45} />
{lut}
</EffectComposer>
)
}
export default Scene;
最後に
R3Fの海外コミュニティでは毎日のように効率化リソースが公開され、Web3などの新しいプロジェクトがでてきて毎日楽しいです。
次はWebGPUが実装されるんでしょうか。楽しみです。
おわり。