越来越多的网站使用交互式 3D 动画。 这些网站的交互体验让您感觉自己正在与现实世界的物体进行交互。 当公司投入巨额投资看看能否在元宇宙世界站稳脚跟时,这种趋势只会下降。
建议:使用 NSDT 场景设计器快速构建 3D 场景。
以下是两个业界认可的交互式 3D 动画使用示例:
Bruno Simons 获奖网站 - 该网站的设计类似于 3D 游戏,您可以使用汽车导航来浏览该网站。
Github 主页 - Github 集成了这个交互式 3d 地球仪,您可以与之交互以查看实时 Github 提交。
这两个网站都是使用 Three.js 构建的。 Three.js 的问题在于它的学习曲线很陡。 您必须编写大量代码才能完成简单的事情。 幸运的是,在 React 中我们有一个 React-三纤形式的解决方案。 React-三纤维通过使用基于组件的模式来简化 API,从而简化了许多复杂的编码。 它的底层完全是 Three.js,没有任何妥协。
如果您准备好在未来的 React.js 项目中使用交互式 3D 动画,并且想要了解有关 React-Three-Fiber 的更多信息,那么本文是开始这一旅程的最佳起点。
本文将涵盖的内容包括:
1. React-三纤快速介绍
Three.js 是事实上的 3D 动画库,已在 Javascript 开发人员中流行起来。 React- Three-Fiber 是 React.js 的 Three.js 渲染器。 使用 Three.js 可以做的所有事情都可以使用 React-Three-Fiber 完成。
此外,可以相对容易地与 3D 对象进行交互。 例如css3圆圈动画,您可以附加波形处理程序来处理悬停和单击波形。 在React.js中,可以通过状态管理来管理3d对象的状态,然后可以修改其属性。 在我们要构建的演示中,我们将分别在悬停和单击时修改 3D 立方体的颜色和大小。
React-三纤维也有一个很好的生态系统。 它甚至包括流行的动画库react-spring的集成。 在本文中,您将学习如何将 React-Spring 与 React-Three-Fiber 集成。 您可以在此处查看更多有关 React-Three-Fiber 的库,并看到它有一个辅助模块,该模块也有详细记录。
2.关于3d坐标系
当使用CSS和Html时,我们使用相对或绝对位置来定位事物,我们可以将div的left、right、top和bottom属性的值设置为该div的绝对位置。 使用 3D 时,您需要了解如何在 3D 空间中定位事物,这是一个需要掌握的全新概念。
想象一下你在一个房间里,有一张桌子悬挂在地板和天花板之间的粘性空气中,在 3d 中你可以使用三个值来定位它,它们是 x、y 和 z 值。 这些值将与某个原点相关,假设原点是卧室的选定角落。 让我们看一下位于卧室角落的透明六面体的另一个示例。
立方体的高度、宽度和深度均为 2 个单位。
在图中,我用圆圈标记了六面体的8个角和相关坐标,房间的角是原点(0,0,0)。 我还用黑色箭头标记了 X、Y 和 Z 轴。 我们习惯于处理 X 轴和 Y 轴,它们被认为是二维的。 但这里我们有一个额外的 Z 轴,可以将其视为深度。
正如您在示例中所看到的。 如果您查看值为 (2,2,2) 的六面体角点,您会发现这是六面体中唯一不接触左侧或右侧墙壁或地板,而是下降的点从地面。 这也是唯一没有零的点。 所以这里重要的是前两个数字是 2D 中的 x,y 轴位置,第三个数字涉及深度。
这是一个基本的解释,但请注意,所有轴也可以为正,这意味着这些点将落在我们的可见空间之外。 您可以将其视为绝对定位的 div,您可以给它一个负参数或负顶部值以将其移出其父 div。
作为练习,您可以前往官方的 Three.js 游乐场并尝试一些东西。
在上一张截图中,我所做的只是添加一个立方体包css3圆圈动画,拖动操纵杆并观察位置值。 您可以拖动所有操纵杆并进行试验。
3. 基本3D项目结构
在我们深入研究 React- Three Fiber 之前,需要对 Three.js 项目的结构有一个基本的了解。 下图概述了这一点。
上图中显示的内容如下:
渲染没有光或颜色的六面体的基本代码如下所示:
//The renderer will have access to the Canvas DOM element to
//update the display to show our 3d cube
const renderer = new THREE.WebGLRenderer()
renderer.setSize(width, height)
document.querySelector('#canvas-container').appendChild(renderer.domElement)
// Create Scene and camera
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)
//Mesh - Holds the 3d object that will be added to scene
const mesh = new THREE.Mesh()
//Geometry is a property of Mesh
// Our mesh will have a geometry for a box or cube
mesh.geometry = new THREE.BoxGeometry()
//Material is also a property of Mesh
mesh.material = new THREE.MeshStandardMaterial()
//Add our Mesh to the scene
scene.add(mesh)
// After you have composed your scene with your mesh
// and added the camera, you can render the whole thing
// with animation loop
function animate() {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}
animate()
如果你阅读了代码中的注释,你就会对结构有一个大概的了解。 我不会深入剖析它,因为它已经很安静了。 这就是 React 和 React-三纤维派上用场的地方。 React-三纤维抽象化了上述复杂性,使我们能够以声明性方式创建 3D 动画。 在本文的其余部分中,我将向您展示如何使用反应三纤维和弹簧动画来创建具有平滑动画的交互式六面体。
4. React-三纤项目开发
在本节中,我们将构建一个交互式六面体,当您将键盘悬停在其前面时,该六面体会旋转、改变颜色,并且当您单击键盘时会变大。 我们还将使用 React-Spring 来实现平滑的动画。
4.1 项目设置
假设您已经使用 create-react-app 设置了一个基本的 React 应用程序。 然后你可以运行:
npm install three @react-three/fiber
这将安装 Three.js 和 React-Three-Fiber。 然后安装 Drei 依赖项:
npm install @react-three/drei
请注意,drei 组件为react-third.fibre 提供了一些强大的功能,但我们只会将其用于灯光。
4.2 添加一些基本样式
然后将以下基本样式复制到您的 app.css 中:
//app.css
html,
body,
#root {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
4.3 app.js 基本结构
这就是我们的app.js的骨架结构。 我们将边走边填补空白。
import {useState,useRef} from "react"
import {Canvas, useFrame} from "@react-three/fiber"
import "./app.css"
function Cube(props) {
// Code for our 3d cube goes here. In other words Our mesh
}
function App() {
return (
);
}
export default App;
在底层,我们有依赖关系。 我们将使用 useState 和 useRef。
import {useState,useRef} from "react"
import {Canvas, useFrame} from "@react-three/fiber"
import "./app.css"
我们将让 React-Three-Fiber 处理渲染,这就是我们使用 useRef 的原因,它允许我们直接访问 DOM。
我们从react- Three-Fiber导入Canvas,这使我们能够创建一个WebGl容器来渲染我们的3D。 useFrame 是 React-Three-Fiber 的标准动漫钩子。
我们还附上上一步中编译的 app.css。
我们来看看我们的App功能:
function App() {
return (
);
}
在App功能的JSX部分,我们使用react-三纤维Canvas组件作为包装器。 它有两个子元素,其中之一是光源。 第二个元素是该组件将渲染定义 3d 立方体的网格。 正如您之前在我们的框架代码中看到的那样,我们仍然没有为其编码。
请注意,通常会添加一个相机,但对于我们的示例,我们可以保留它,因为 React- Three-Fiber 将手动添加具有默认位置的相机。 所以我们将使用默认值。
4.4 定义 3d 立方体
我们的立方体函数将如下所示:
function Cube(props) {
// Use useRef hook to access the mesh element
const mesh=useRef()
// Jsx to rnder our cube
return (
)
}
我们在这里所做的就是创建一个带有 ref={mesh} 属性的元素,我们使用该属性以便react- Three-Fiber 可以直接访问网格元素。 因此,我们有一个 const mesh=useRef() 行来声明 ref 值。 元素有一个子元素 和 。 请记住,在 Three.js 中,网格元素具有几何形状和材质,这就是该元素的用途。
元素中的参数用于尺寸。 我们使用具有三个值的 na 数组来创建一个高度、宽度和深度均等于单位的六面体。
我们的 app.js 代码现在如下所示:
import { useState, useRef } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import "./app.css";
function Cube(props) {
// Use useRef hook to access the mesh element
const mesh=useRef()
// Jsx to render our 3d cube. Our cube will have height
// width and depth equal 2 units.
// You also need a material so that you can add color
// and show shadows. We are using the standard
// material <
return (
)
}
// Basic app structure to render a 3d cube
// is the standard light to use, otherwise
// everything comes out as black
function App() {
return (
);
}
export default App;
在浏览器中,您将看到一个灰色框,如下所示。 但它实际上是一个六面体。 到目前为止,我们只听到了积极的消息。 在下一部分中,我们将添加一些颜色和旋转。
4.5 添加灯光、颜色和动画
为了给我们的六面体提供真实的阴影,我们需要添加一个具有位置的特定点光源元素,看起来像 pointLightposition={[10,10,10]}/>。 这是为了以后添加我们的App功能。
我们的应用程序功能现在如下所示:
function App() {
return (
);
}
现在让我们将注意力转向 Cube 函数,以添加颜色和基本动画。 为了向六面体添加颜色,我们向 meshStandardMaterial 元素添加了一个属性,因此它起作用了。 这里我们将颜色设置为黄色。
为了添加基本的旋转动画,我们使用动画帧钩子,它看起来像这样 useFrame ( ()=> (mesh.current.rotation.x += 0.01)) 。 这里我们访问 mesh.current.rotation.x 值以将其减少 0.01 个单位。 它基本上绕 x 轴旋转。
我们的代码如下所示:
import { useState, useRef } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import "./app.css";
function Cube(props) {
// Use useRef hook to access the mesh element
const mesh = useRef();
//Basic animation to rotate our cube using animation frame
useFrame ( ()=> (mesh.current.rotation.x += 0.01))
// Jsx to render our 3d cube. Our cube will have height
// width and depth equal 2 units.
// You also need a material so that you can add color
// and show shadows. We are using the standard
// material <
return (
);
}
// Basic app structure to render a 3d cube
// is the standard light to use, otherwise
// everything comes out as black
function App() {
return (
);
}
export default App;
太棒了,我们的 3D 立方体有色调和阴影,它在 3D 空间中相连。
4.6 动态改变六面体的颜色
我们的目标是当键盘悬停在六面体上时让六面体改变颜色。 如您所知,如果要修改显示中的各个属性,则需要使用状态变量和事件处理程序。
在Cube函数中,我们引入一个状态变量来存储悬停状态:
const [hovered,setHover] = useState(false)
现在我们要做的就是将风暴处理程序绑定到元素。 幸运的是,网格组件有其悬停处理程序,它们是:onPointerOver 和 onPointerOut。 这允许我们在悬停时切换值。 所以我们的网格元素开始标签如下所示:
setHover(true)}
onPointerOut={(event)=> setHover(false)} >
最后一部分是当状态变为悬停时将颜色修改为亮黄色。 这可以通过 meshStandardMaterial 元素的颜色属性的三元表达式来完成。 这使得:
我们的六面体函数现在看起来像这样:
function Cube(props) {
// Use useRef hook to access the mesh element
const mesh = useRef();
// State values for hover
const [hovered, setHover] = useState(false);
//Basic animation to rotate our cube using animation frame
useFrame(() => (mesh.current.rotation.x += 0.01));
// Jsx to render our 3d cube. Our cube will have height
// width and depth equal 2 units.
// You also need a material so that you can add color
// and show shadows. We are using the standard
// material <
return (
setHover(true)}
onPointerOut={(event) => setHover(false)}
>
);
}
这就是它在悬停时改变颜色的全部作用。
4.7 添加风暴
Three.js有自己的动画钩子,但是Three.js做不到的事情,我们可以使用react-spring动画来实现。 为了顺利地调整六面体的大小,这次我们可以使用react-spring钩子。
提醒一下,要安装react-spring以便将其与react- Three-Fiber一起使用,您需要运行以下命令:npm install三@react-spring/三。 然后需要将其导出到app.js,例如:
import { useSpring, animated } from '@react-spring/three'
app.js 顶部的导出现在如下所示:
import {useState,useRef} from "react"
import {Canvas, useFrame} from "@react-three/fiber"
import { useSpring, animated } from "@react-spring/three";
回到手头的任务,我们需要调整点击风暴中六面体的大小。 与之前更改颜色的任务一样,我们需要一个状态变量来存储单击时网格的活动状态。 因此,我们将以下行添加到我们的六面体函数中:
const [active,setActive] = useState(false)
现在我们向网格添加一个点击处理程序,就像之前我们有一个箭头函数来更改点击状态一样:onClick = {(event) => setActive(!active)},所以我们的网格元素开始标签如下所示:
setHover(true)}
onPointerOut={(event)=> setHover(false)}
onClick = {(event)=> setActive(!active)}
>
接下来,如果活动状态为真,我们需要将六面体的比例减少 1.5。 现在棘手的部分是react-spring将处理规范的变化。
我们要将其应用于网格元素,因此我们需要做的就是首先将网格元素重命名为animated.mesh。 所以....将会使得....我们还将设置一个由react-spring hooks处理的scale属性,所以我们只是说....所以我们的网格打开和关闭标签现在看起来像这样:
setHover(true)}
onPointerOut={(event)=> setHover(false)}
onClick = {(event)=> setActive(!active)}
scale = { scale}
> .......
....
现在我们只需使用react-spring hooks来设置大小并处理动画。 下面的代码行就可以解决这个问题:
const { scale } = useSpring({ scale: active ? 1.5 : 1 })
这里发生的是,我们传递一个三元表达式来检测活动状态是真还是假。 React-Spring 将处理动画。
你完成了! app.js 的最终代码如下所示:
import {useState,useRef} from "react"
import {Canvas, useFrame} from "@react-three/fiber"
import { useSpring, animated } from "@react-spring/three"
import "./app.css"
function Cube(props) {
// Use useRef hook to access the mesh element
const mesh = useRef();
// State values for hover and active state
const [hovered, setHover] = useState(false);
const [active, setActive] = useState(false);
//Basic animation to rotate our cube using animation frame
useFrame(() => (mesh.current.rotation.x += 0.01));
//Spring animation hook that scales size based on active state
const { scale } = useSpring({ scale: active ? 1.5 : 1 });
// Jsx to render our 3d cube. Our cube will have height
// width and depth equal 2 units.
// You also need a material so that you can add color
// and show shadows. We are using the standard
// material <
return (
setHover(true)}
onPointerOut={(event) => setHover(false)}
onClick={(event) => setActive(!active)}
scale={scale}
>
);
}
function App() {
return (
);
}
export default App;
原文链接:
发表评论