先上效果图
在很久以前,自学c4d的时候,见过一个类似时空隧道的一个案例,样子大概是这样
然后就突发奇想,做一个隧道加文字破碎效果的场景出来
第一步:初始化场景
初始化项目和必要依赖同第一天相同
app.tsx
import { Canvas } from "@react-three/fiber";
import "./App.css";
import Render from "./Render";
function App() {
return (
<>
<Canvas>
<Render />
</Canvas>
</>
);
}
export default App;
render.tsx
const Render = () => {
return (
<>
<mesh>
<boxGeometry />
<meshBasicMaterial color={'red'} />
</mesh>
</>
);
};
export default Render;
如果上述代码正常的话,我们的页面会得到如下的显示结果
第二步:导入隧道模型和碎片模型
- 制作模型(暂时先不介绍,敢兴趣在单独开一个建模篇)
- 将隧道模型导入到项目中
- 将ware.gltf文件放到项目的public目录下
- 将studio_small_09_4k.exr环境贴图放到public目录下
- 将隧道模型导入到场景
render.tsx import { useGLTF } from "@react-three/drei" import { BackSide } from "three" const Ware = () => { const { nodes } = useGLTF('/ware.gltf'); return ( <mesh geometry={(nodes.yz).geometry}> <meshBasicMaterial color={'red'} side={BackSide} /> </mesh> ); }; const Render = () => { return ( <> <Ware /> </> ); }; export default Render;
这个时候我们可以看到我们的模型已经成功到导入到场景中
- 给隧道添加物理材质MeshPhysicalMaterial
render.tsx
...
const Ware = () => {
const { nodes } = useGLTF('/ware.gltf');
return (
<mesh geometry={(nodes.yz).geometry}>
// 这里添加物理材质粗糙度和颜色可以自行调整
// 由于物理材质需要灯光才可以被看见,此时我们的模型会呈现一片黑色
<meshPhysicalMaterial color={'white'} side={BackSide} roughness={0.4} />
</mesh>
);
};
...
app.tsx
...
import { Environment } from "@react-three/drei";
function App() {
return (
<>
<Canvas>
<Render />
// 添加环境光照
<Environment
files={'/studio_small_09_4k.exr'}
environmentRotation={[Math.PI / 2, 0, 0]}
environmentIntensity={0.12}
></Environment>
</Canvas>
</>
);
}
...
这时我们的隧道会有如下的效果
4.将碎片模型导入到场景中并添加玻璃材质
render.tsx
const TextCom = () => {
const { nodes } = useGLTF('/sp1.glb');
return (
<group>
<mesh
geometry={(nodes.sp).geometry}
position={[0, 0, 16]}
scale={0.8}
>
// 玻璃材质
<MeshTransmissionMaterial
backsideThickness={5}
thickness={2}
side={BackSide}
reflectivity={1.52}
envMapIntensity={1}
ior={1.72}
roughness={0}
/>
</mesh>
<mesh
geometry={(nodes.text).geometry}
scale={1}
position={[0, 0, 16]}
>
// 玻璃材质
<MeshTransmissionMaterial
backsideThickness={5}
thickness={2}
side={BackSide}
reflectivity={1.52}
roughness={0.8}
/>
</mesh>
<mesh
geometry={(nodes.text).geometry}
scale={0.96}
position={[0, 0, 16]}
>
// 红色材质
<meshBasicMaterial color={'red'} />
</mesh>
</group>
);
};
const Render = () => {
return (
<>
<Ware />
<TextCom />
</>
);
};
app.tsx
...
// 设置摄像机的位置
<Canvas camera={{ position: [0, 0, 120] }}>
<Render />
<Environment
files={'/studio_small_09_4k.exr'}
environmentRotation={[Math.PI / 2, 0, 0]}
environmentIntensity={0.12}
></Environment>
</Canvas>
...
这个时候我们得到如下效果
5.现在的隧道看着比较灰暗,我们在隧道里面加上灯光
render.tsx
// 灯光颜色、位置和强度可以自己调节
const Light = () => {
return (
<>
<pointLight
distance={4000}
intensity={50000}
color={'white'}
position={[0, 0, -250]}
/>
<pointLight
distance={4000}
intensity={50000}
color={'white'}
position={[0, 0, -150]}
/>
<pointLight
distance={1000}
intensity={50000}
color={'orange'}
position={[0, 0, -100]}
/>
<pointLight
distance={1000}
intensity={40000}
color={'red'}
position={[0, 0, 0]}
/>
<pointLight
distance={1000}
intensity={50000}
color={'red'}
position={[0, 0, 100]}
/>
</>
);
};
const Render = () => {
return (
<>
<Ware />
<TextCom />
<Light />
</>
);
};
这个时候我们就可以得到下面的效果
6.最后一步就是给场景中添加交互和动画
render.tsx
import {
useGLTF,
MeshTransmissionMaterial,
Float,
useTexture
} from '@react-three/drei';
import { BackSide, Mesh } from 'three';
import { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import { easing } from 'maath';
const Ware = () => {
const wareRef = useRef<Mesh>(new Mesh());
const { nodes } = useGLTF('/ware.gltf');
useFrame(({ camera, pointer }, delta) => {
// 让相机沿z轴向前运动
if (camera.position.z > 50) {
camera.position.z -= 0.02;
}
// 设置相机的视角,跟随鼠标的位置移动
easing.damp3(
camera.position,
[-pointer.x, -pointer.y, camera.position.z],
0.2,
delta
);
// 相机始终看到原点
camera.lookAt(0, 0, 0);
});
return (
<mesh geometry={(nodes.yz as Mesh).geometry} ref={wareRef}>
<meshPhysicalMaterial color={'white'} side={BackSide} roughness={0.4} />
</mesh>
);
};
const TextCom = () => {
const { nodes } = useGLTF('/sp1.glb');
const envMap = useTexture('/studio_small_09_4k.exr');
const spRef = useRef<Mesh>(new Mesh());
useFrame(() => {
// 碎片沿z轴旋转
spRef.current.rotation.z += 0.001;
});
return (
<group>
<mesh
geometry={(nodes.sp as Mesh).geometry}
position={[0, 0, 16]}
scale={0.8}
ref={spRef}
>
<MeshTransmissionMaterial
backsideThickness={5}
thickness={2}
side={BackSide}
reflectivity={1.52}
envMap={envMap}
envMapIntensity={1}
ior={1.72}
roughness={0}
/>
</mesh>
// 碎片上下摆动
<Float speed={10} rotationIntensity={1} floatIntensity={4} scale={0.8}>
<mesh
geometry={(nodes.text as Mesh).geometry}
scale={1}
position={[0, 0, 16]}
>
<MeshTransmissionMaterial
backsideThickness={5}
thickness={2}
side={BackSide}
reflectivity={1.52}
roughness={0.8}
/>
</mesh>
<mesh
geometry={(nodes.text as Mesh).geometry}
scale={0.96}
position={[0, 0, 16]}
>
<meshBasicMaterial color={'red'} />
</mesh>
</Float>
</group>
);
};
const Light = () => {
return (
<>
<pointLight
distance={4000}
intensity={50000}
color={'white'}
position={[0, 0, -250]}
/>
<pointLight
distance={4000}
intensity={50000}
color={'white'}
position={[0, 0, -150]}
/>
<pointLight
distance={1000}
intensity={50000}
color={'orange'}
position={[0, 0, -100]}
/>
<pointLight
distance={1000}
intensity={40000}
color={'red'}
position={[0, 0, 0]}
/>
<pointLight
distance={1000}
intensity={50000}
color={'red'}
position={[0, 0, 100]}
/>
</>
);
};
const Render = () => {
return (
<>
<Ware />
<TextCom />
<Light />
</>
);
};
export default Render;
最后的效果就是这样啦(风格可以自己控制喔)