怎么用Three.js+React实现3D文字悬浮效果

怎么用Three.js+React实现3D文字悬浮效果

本篇内容介绍了“怎么用Three.js+React实现3D文字悬浮效果”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

    背景

    Three.js Journey课程示例中,提供了一个使用Three.js内置方法实现的3D文字悬浮效果的例子,本文使用React + Three.js技术栈,参照示例实现类似的效果。本文中涉及到的知识点主要包括:CSS网格背景、MeshNormalMaterial法向材质、FontLoader字体加载器、TextGeometry文本缓冲几何体、TorusBufferGeometry圆环缓冲几何体、ConeBufferGeometry圆锥缓冲几何体、OctahedronBufferGeometry八面缓冲几何体、Three.js后期渲染、GlitchPass通道、Element.requestFullscreenDocument.exitFullscreen等。

    效果

    实现效果如banner图所示,页面主体由位于中心的文字网格模型以及四周的圆环面、圆锥以及八面体构成。随着鼠标在页面上移动或点击,模型也随之移动。页面右上角提供了2个按钮,可以切换页面背景色和切换故障风格后期特效。双击屏幕可以进入或退出全屏。

    在线预览:https://3d-dragonir.vercel.app/#/floating

    或https://dragonir.github.io/3d/#/floating

    已适配:

    • PC端

    • 移动端

    实现

    资源引入

    首先引入开发所需要的模块资源,其中FontLoader用于加载字体文件,TextGeometry用于创建3D字体网格,EffectComposerRenderPassGlitchPass用于后期特效渲染。

    import*asTHREEfrom"three";import{FontLoader}from"three/examples/jsm/loaders/FontLoader";import{TextGeometry}from'three/examples/jsm/geometries/TextGeometry';import{EffectComposer}from'three/examples/jsm/postprocessing/EffectComposer.js';import{RenderPass}from'three/examples/jsm/postprocessing/RenderPass.js';import{GlitchPass}from'three/examples/jsm/postprocessing/GlitchPass.js';

    DOM结构

    页面DOM结构非常简单,容器#canvas用于场景渲染,.color_pick用于切换页面背景颜色,.pass_button用于切换故障风格后期渲染。

    <divclassName='floating_page'style={{backgroundColor:this.state.backgroundColor}}><divid="canvas"></div><inputclassName='color_pick'type="color"onChange={this.handleInputChange}value={this.state.backgroundColor}/><buttonclassName='pass_button'onClick={this.handleRenderChange}>特效<spanclassName='highlight'>{this.state.renderGlithPass?'开':'关'}</span></button></div>

    设置状态

    backgroundColor表示当前页面背景色,renderGlithPass表示是否开启后期状态。自测发现在iOS Safari浏览器中,故障风格后期渲染会导致模型产生穿模问题,因此使用该参数控制手机端默认关闭后期效果、pc端默认开启。

    state={backgroundColor:'#164CCA',renderGlithPass:!(window.navigator.userAgent.toLowerCase().indexOf('mobile')>0)}

    网格背景

    使用纯CSS属性linear-gradient实现网格背景来美化页面。

    background-image:linear-gradient(rgba(3,192,60,.3)1px,transparent1px),linear-gradient(90deg,rgba(3,192,60,.3)1px,transparent1px);background-size:1em1em;

    场景初始化

    初始化渲染容器、场景、摄像机,摄像机的位置可根据自身所需调整。render开启alpha并设置.setClearAlpha(0)可将背景色设置为透明。

    canvas=document.getElementById('canvas');renderer=newTHREE.WebGLRenderer({antialias:true,alpha:true});renderer.setPixelRatio(Math.min(2,window.devicePixelRatio));renderer.setSize(window.innerWidth,window.innerHeight);renderer.setClearAlpha(0);canvas.appendChild(renderer.domElement);scene=newTHREE.Scene();camera=newTHREE.PerspectiveCamera(70,window.innerWidth/window.innerHeight,.1,10000);camera.position.set(-2*10000,0,780);

    创建材质

    本文中所有网格模型都将使用同一种材质MeshNormalMaterial,应用它的特性,可以使网格模型产生彩色渐变。全局创建一次,后续开发不需要重复创建,有利于页面性能提升。

    constmaterial=newTHREE.MeshNormalMaterial();

    MeshNormalMaterial 法向材质

    是一种把法向量映射到RGB颜色的材质,可以通过观察模型表面渐变颜色是否连续来检测模型表面是否平整

    构造函数

    MeshNormalMaterial(parameters:Object)

    parameters:可选,用于定义材质外观的对象,具有一个或多个属性。

    特殊属性

    • .normalMap[Texture]:用于创建法线贴图纹理,RGB值会影响每个像素片段的曲面法线,并更改颜色照亮的方式。

    • .normalMapType[Integer]:法线贴图的类型,选项为THREE.TangentSpaceNormalMap(默认)和THREE.ObjectSpaceNormalMap

    • .normalScale[Vector2]:法线贴图对材质的影响程度。范围是0-1,默认值是Vector2设置为(1, 1)

    • .flatShading[Boolean]:定义材质是否使用平面着色进行渲染,默认值为false

    • .morphNormals[Boolean]:定义是否使用morphNormals。设置为true可将morphNormal属性从geometry传递到shader。默认值为false

    • .morphTargets[Boolean]:定义材质是否使用morphTargets,默认值为false

    创建文字模型

    使用FontLoader加载fontface字体JSON文件,并用TextGeometry创建文字几何体模型。

    constloader=newFontLoader();loader.load('./fonts/helvetiker_regular.typeface.json',font=>{textMesh.geometry=newTextGeometry('@dragonir\nfantastic\nthree.js\nartwork',{font:font,size:100,height:40,curveSegments:12,bevelEnabled:true,bevelThickness:30,bevelSize:8,bevelOffset:1,bevelSegments:12});textMesh.material=material;scene.add(textMesh);});

    FontLoader 字体加载器

    使用JSON格式中加载字体的一个类,返回Font, 返回值是表示字体的Shape类型的数组,其内部使用FileLoader来加载文件。

    构造函数

    FontLoader(manager:LoadingManager)

    • manager:加载器所使用的loadingManager,默认值为THREE.DefaultLoadingManager

    方法:

    .loadURL中进行加载,并将被加载的texture传递给onLoad

    • .load(url: String, onLoad: Function, onProgress: Function, onError: Function): null

    • url:文件的URL或者路径,也可以为Data URI

    • onLoad:加载完成时将调用。回调参数是将要被加载的texture

    • onProgress:将在加载过程中进行调用。参数为XMLHttpRequest实例,包含totalloaded字节。

    • onError:加载错误时被调用。

    .parseJSON格式进行解析,并返回一个Font

    • .parse (json: Object ): Font

    • json:用于解析的JSON结构。

    TextGeometry 文本几何体

    用于将文本生成单一几何体的类,它是由一串给定的文本,以及由加载的Font字体和该几何体ExtrudeGeometry父类中的设置所组成的参数构造的。

    构造函数

    TextGeometry(text:String,parameters:Object)

    text:将要显示的文本。

    parameters

    • font[Font]THREE.Font实例。

    • size[Float]:字体大小,默认值为100

    • height[Float]:挤出文本的厚度,默认值为50

    • curveSegments[Integer]:表示文本的曲线上点的数量,默认值为12

    • bevelEnabled[Boolean]:是否开启斜角,默认为false

    • bevelThickness[Float]:文本斜角的深度,默认值为20

    • bevelSize[Float]:斜角与原始文本轮廓之间的延伸距离,默认值为8

    • bevelSegments[Integer]:斜角的分段数,默认值为3

    可以使用facetype.js在线转换Three.js支持的字体。

    创建几何体模型

    使用其他3种内置几何体模型圆环、圆锥和八面体来装饰页面。装饰几何体的数量比较多,为了有效提升页面性能,需要注意以下两点:

    • 使用THREE.Group管理所有几何体。

    • 创建几何体时使用BufferAttribute, 如使用ConeBufferGeometry而不是ConeGeometry,这样可以更有效地将数据传递到GPU

    //批量创建模型方法generateRandomMesh=(geometry,material,count)=>{for(leti=0;i<count;i++){letmesh=newTHREE.Mesh(geometry,material);letdist=farDist/3;letdistDouble=dist*2;//设置随机的位置和旋转角度mesh.position.x=Math.random()*distDouble-dist;mesh.position.y=Math.random()*distDouble-dist;mesh.position.z=Math.random()*distDouble-dist;mesh.rotation.x=Math.random()*2*Math.PI;mesh.rotation.y=Math.random()*2*Math.PI;mesh.rotation.z=Math.random()*2*Math.PI;//手动控制何时重新计算3D变换以获得更好的性能mesh.matrixAutoUpdate=false;mesh.updateMatrix();group.add(mesh);}}//创建100个八面体constoctahedronGeometry=newTHREE.OctahedronBufferGeometry(80);generateRandomMesh(octahedronGeometry,material,100);//创建200个圆环面consttorusGeometry=newTHREE.TorusBufferGeometry(40,25,16,40);generateRandomMesh(torusGeometry,material,200);//创建100个圆锥constconeGeometry=newTHREE.ConeBufferGeometry(40,80,80);generateRandomMesh(coneGeometry,material,100);scene.add(group);

    TorusBufferGeometry 圆环缓冲几何体

    用于生成圆环几何体的类。

    构造函数

    TorusBufferGeometry(radius:Float,tube:Float,radialSegments:Integer,tubularSegments:Integer,arc:Float)

    • radius:圆环的半径,从圆环的中心到管道横截面的中心,默认值是1

    • tube:管道的半径,默认值为0.4

    • radialSegments:圆环的分段数,默认值为8

    • tubularSegments:管道的分段数,默认值为6

    • arc:圆环的圆心角,单位是弧度,默认值为Math.PI * 2

    ConeBufferGeometry 圆锥缓冲几何体

    用于生成圆锥几何体的类。

    构造函数

    ConeBufferGeometry(radius:Float,height:Float,radialSegments:Integer,heightSegments:Integer,openEnded:Boolean,thetaStart:Float,thetaLength:Float)

    • radius:圆锥底部的半径,默认值为1

    • height:圆锥的高度,默认值为1

    • radialSegments:圆锥侧面周围的分段数,默认为8

    • heightSegments:圆锥侧面沿着其高度的分段数,默认值为1

    • openEnded:指明该圆锥的底面是开放的还是封顶的。默认值为false,即其底面默认是封顶的。

    • thetaStart:第一个分段的起始角度,默认为0

    • thetaLength:圆锥底面圆扇区的中心角,通常被称为&theta;。默认值是2*PI,使其成为一个完整的圆锥。

    OctahedronBufferGeometry 八面缓冲几何体

    用于创建八面体的类。

    构造函数

    OctahedronBufferGeometry(radius:Float,detail:Integer)

    • radius:八面体的半径,默认值为1

    • detail:默认值为0,将这个值设为一个大于0的数将会为它增加一些顶点,使其不再是一个八面体。

    鼠标事件监听

    通过对鼠标移动坐标和模型坐标的相互转换来添加鼠标移动和触摸移动事件的监听方法。

    constmouseFX={windowHalfX:window.innerWidth/2,windowHalfY:window.innerHeight/2,coordinates:(coordX,coordY)=>{mouseX=(coordX-mouseFX.windowHalfX)*5;mouseY=(coordY-mouseFX.windowHalfY)*5;},onMouseMove:e=>{mouseFX.coordinates(e.clientX,e.clientY)},onTouchMove:e=>{mouseFX.coordinates(e.changedTouches[0].clientX,e.changedTouches[0].clientY)}};document.addEventListener('mousemove',mouseFX.onMouseMove,false);document.addEventListener('touchmove',mouseFX.onTouchMove,false);

    背景色切换

    使用一个input[type='color']标签来实现背景色切换。

    handleInputChange=e=>{this.setState({backgroundColor:e.target.value});}

    后期渲染

    为了更具有冲击感的视觉效果,我添加了一个故障风格后期渲染特效,并使用一个按钮开关来控制开启和关闭该特效。

    composer=newEffectComposer(renderer);composer.addPass(newRenderPass(scene,camera));glitchPass=newGlitchPass();composer.addPass(glitchPass);

    handleRenderChange=()=>{this.setState({renderGlithPass:!this.state.renderGlithPass});}

    后期渲染

    Three.js后期渲染处理,是通过叠加渲染通道达到预期视觉效果的过程。实现流程如下:

    • 创建效果组合器:效果组合器是各种处理通道的入口,使用EffectComposer对象创建一个效果组合器。

    • 添加通道:添加RenderPass通道 它将在指定的场景和相机的基础上渲染出一个新的场景。

    • 组合器更新:在动画循环中,调用效果组合器的render方法,通道生成效果将在场景中输出。

    GlitchPass 故障风格通道

    GlitchPass通道产生模拟故障风格效果,它只有一个可选配置参数:

    goWild该属性接收一个布尔值,指定是否持续产生电磁风暴效果。

    Three.js提供了很多后期处理的通道,可以直接使用。同时提供了ShaderPass通道,它支持使用自定义Shader,可以创建高级的自定义后期处理通道。

    动画

    requestAnimationFrame中更新场景、相机、和后期渲染通道。

    functionanimate(){requestAnimationFrame(animate);camera.position.x+=(mouseX-camera.position.x)*0.05;camera.position.y+=(mouseY*-1-camera.position.y)*0.05;camera.lookAt(scene.position);//给场景中的立方体网格和字体网格添加自转动画constt=Date.now()*0.001;constrx=Math.sin(t*0.7)*0.5;constry=Math.sin(t*0.3)*0.5;constrz=Math.sin(t*0.2)*0.5;group.rotation.x=rx;group.rotation.y=ry;group.rotation.z=rz;textMesh.rotation.x=rx;textMesh.rotation.y=ry;textMesh.rotation.z=rx;renderer.render(scene,camera);//更新后期渲染通道composer.render();}

    缩放适配

    renderercomposer大小要同时调整。

    window.addEventListener('resize',()=>{camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);composer.setSize(window.innerWidth,window.innerHeight);},false);

    双击全屏

    监听页面鼠标双击dblclick事件,通过调用requestFullscreenexitFullscreen进入或退出全屏状态。

    window.addEventListener('dblclick',()=>{letfullscreenElement=document.fullscreenElement||document.webkitFullscreenElement;if(!fullscreenElement){if(canvas.requestFullscreen){canvas.requestFullscreen();}elseif(canvas.webkitRequestFullscreen){canvas.webkitRequestFullscreen();}console.log('进入全屏')}else{if(document.exitFullscreen){document.exitFullscreen();}elseif(document.webkitExitFullscreen){document.webkitExitFullscreen();}console.log('退出全屏')}})

    Element.requestFullscreen

    Element.requestFullscreen方法用于发出异步请求使元素进入全屏模式。调用此API并不能保证元素一定能够进入全屏模式。如果元素被允许进入全屏幕模式,返回的Promiseresolve,并且该元素会收到一个fullscreenchange事件,通知它已经进入全屏模式。如果全屏请求被拒绝,返回的promise会变成rejected并且该元素会收到一个fullscreenerror事件。如果该元素已经从原来的文档中分离,那么该文档将会收到这些事件。

    语法

    varPromise=Element.requestFullscreen(options);

    options:可选,一个FullscreenOptions对象提供切换到全屏模式的控制选项。

    这个方法只能在用户交互或者设备方向改变的时候调用,否则将会失败。FullscreenOptions目前唯一的选项是navigationUI,这控制了是否在元素处于全屏模式时显示导航条UI。默认值是auto,表明这将由浏览器来决定是否显示导航条。

    Document.exitFullscreen

    Document.exitFullscreen方法用于让当前文档退出全屏模式。调用这个方法会让文档回退到上一个调用Element.requestFullscreen方法进入全屏模式之前的状态。

    语法

    document.exitFullscreen();

    “怎么用Three.js+React实现3D文字悬浮效果”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注恰卡编程网网站,小编将为大家输出更多高质量的实用文章!

    发布于 2022-03-09 22:51:12
    收藏
    分享
    海报
    0 条评论
    32
    上一篇:pytorch中的hook机制是什么 下一篇:JavaScript怎么实现简单抽奖系统
    目录

      0 条评论

      本站已关闭游客评论,请登录或者注册后再评论吧~

      忘记密码?

      图形验证码