
声明:本文涉及图文和模型素材仅用于个人学习、研究和欣赏,请勿二次修改、非法传播、转载、出版、商用、及进行其他获利行为。
不知不觉,掘金关注者人数已经超过 1000 人,因此特地做了这个页面纪念一下,感谢大家关注 ?,希望博客园的粉丝也涨涨。后续也将继续努力,持续输出一些有价值的文章。本文内容涉及的技术栈为 React + Three.js + Stulus,本文中主要包含的知识点包括:圆锥几何体 ConeGeometry、圆柱几何体 CylinderGeometry、材质捕捉纹理材质 MeshMatcapMaterial、文字创建和修饰的 FontLoader 和 TextGeometry、使用 Gsap 和它的插件 Physics2DPlugin 创建一些动画、rotateOnAxis 方法实现绕轴自转等。
对了,后续我专门新建了一个专门针对 Three.js 系列的专栏【Three.js 奥德赛进阶之旅】,是掘金签约的专栏 ?。从基础入门开始,全方位了解 Three.js 的各种特性,并结合和应用对应特性,实现令人眼前一亮的 Web 创意页面,进而逐步挖掘 Three.js 和 WebGL 深层次的知识。在这里推广一下,大家感兴趣的话可以关注一波 ?。
页面 ? 主体内容主要由四部分组成,分别是:文字 1000!、文字 THANK YOU、掘金三维 Logo、以及 纸片礼花 ?。其中文字各自具有翻转动画,掘金 Logo 有自转动画效果,当用 ? 鼠标点击屏幕时,会出现 *★,°*:.☆( ̄▽ ̄)/$:*.°★* 。 撒花效果。

打开以下链接中的任意一个可以在线预览效果。本页面适配PC端和移动端,大屏访问效果更佳。
?? 在线预览地址1:https://3d-eosin.vercel.app/#/fans?? 在线预览地址2:https://dragonir.github.io/3d/#/fans
? 资源引入首先在顶部引入开发必备的资源,除了基础的 React 和样式表之外,THREE 是 Three.js 库;OrbitControls 用于镜头轨道控制,可以使用鼠标移动或旋转模型;Text 是用于创建文字模型的一个类;Confetti 是一个用于创建礼花效果的类,在后面内容中会做详细介绍。
import './index.styl';
import React from 'react';
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Text from '@/assets/utils/Text';
import Confetti from '@/assets/utils/Confetti';
? 页面结构页面主要结构非常简单,其中 .webgl 用于渲染 3D 元素;.logo 是页面上的一些图标装饰,.github 是存放本项目的 Github 链接地址。
<div className='fans_page'>
<canvas className='webgl'></canvas>
<i className='logo'></i>
<i className='logo click'></i>
<a className='github' href='https://github.com/dragonir/3d' target='_blank'></a>
</div>
Logo创建 Logo 时,先创建一个 Group,然后将 Logo 的各个部分添加到 Group 中,这样有利于对 Logo 整体调整位置和添加动画,也有利于页面加载性能。接着,通过以下步骤创建 Logo 模型的三部分:
MeshMatcapMaterial,Logo 模型的所有组成网格都将使用这种材质;ConeGeometry 创建顶部的 四棱锥,并应用材质;CylinderGeometry 创建中间的 四棱台,并应用材质;CylinderGeometry 创建底部的 四棱台,并应用材质;Group 中,并调整整体的位置、大小,并设置倾斜角度以便获得更好的页面视觉效果。
?在实际开发中,应用了ConeBufferGeometry、CylinderBufferGeometry代替ConeGeometry和CylinderGeometry,以便获得更好的性能。

本示例中模型的计算参数如上图所示,顶部四棱柱的四个面都是边长为 4 的等边三角形,其余两个棱台的侧边长也是 4,其他边的长度参数都可以通过勾股定理以及三角函数计算得出,本文中不做详细计算。(PS:模型示意图是用 Windows 画图工具画的,有点丑 ?)
const logo = new THREE.Group();
// 材质捕捉纹理材质
const logoMaterial = new THREE.MeshMatcapMaterial({
matcap: this.matcaps.logoMatcap,
side: THREE.DoubleSide,
});
// 顶部四棱锥
const cone = new THREE.Mesh(new THREE.ConeGeometry(4, 4, 4), logoMaterial);
logo.add(cone);
// 中间四棱台
const cylinder = new THREE.Mesh(new THREE.CylinderGeometry(6, 10, 4, 4, 1), logoMaterial);
cylinder.position.y = -6
logo.add(cylinder);
// 底部四棱台
const cylinder2 = new THREE.Mesh(new THREE.CylinderGeometry(12, 16, 4, 4, 1), logoMaterial);
cylinder2.position.y = -12
logo.add(cylinder2);
logo.position.set(0, 0, 0);
logo.scale.set(11, 11, 11);
// 设置倾斜角度
logo.rotateY(Math.PI * 0.2);
logo.rotateZ(Math.PI * 0.1);
scene.add(logo);

? 知识点 圆锥几何体ConeGeometry圆锥几何体 ConeGeometry,是一个用于生成圆锥几何体的类,侧面分段数越多则越圆,本例中分段数为 4,所以看起来是个四棱锥。
构造函数:
ConeGeometry(radius: Float, height: Float, radialSegments: Integer, heightSegments: Integer, openEnded: Boolean, thetaStart: Float, thetaLength: Float);
参数说明:
radius:圆锥底部的半径,默认值为 1。height:圆锥的高度,默认值为 1。radialSegments:圆锥侧面周围的分段数,默认为 8。heightSegments:圆锥侧面沿着其高度的分段数,默认值为 1。openEnded:一个 Boolean 值,指明该圆锥的底面是开放的还是封顶的。默认值为 false,即其底面默认是封顶的。thetaStart:第一个分段的起始角度,默认为 0。thetaLength:圆锥底面圆扇区的中心角,通常被称为 θ。默认值是 2*PI,这使其成为一个完整的圆锥。? 知识点 圆柱几何体CylinderGeometry圆柱几何体 CylinderGeometry,是一个用于生成圆柱几何体的类。本文中 Logo 的中间和底部就由此类生成。
构造函数:
CylinderGeometry(radiusTop: Float, radiusBottom: Float, height: Float, radialSegments: Integer, heightSegments: Integer, openEnded : Boolean, thetaStart: Float, thetaLength: Float)
参数说明:
radiusTop:圆柱的顶部半径,默认值是 1。radiusBottom:圆柱的底部半径,默认值是 1。height:圆柱的高度,默认值是 1。radialSegments:圆柱侧面周围的分段数,默认为 8。heightSegments:圆柱侧面沿着其高度的分段数,默认值为 1。openEnded:一个 Boolean值,指明该圆锥的底面是开放的还是封顶的。默认值为 false,即其底面默认是封顶的。thetaStart:第一个分段的起始角度,默认为 0。thetaLength:圆柱底面圆扇区的中心角,通常被称为 θ。默认值是 2*PI,这使其成为一个完整的圆柱。? 知识点 材质捕捉纹理材质MeshMatcapMaterialMeshMatcapMaterial 由一个材质捕捉 MatCap或光照球 纹理所定义,其编码了材质的颜色与明暗。由于 mapcap 图像文件编码了烘焙过的光照,因此MeshMatcapMaterial不对灯光作出反应。它可以投射阴影到一个接受阴影的物体上,但不会产生自身阴影或是接收阴影。
构造函数:
MeshMatcapMaterial(parameters: Object)
parameters:可选,用于定义材质外观的对象,具有一个或多个属性,材质的任何属性都可以从此处传入,包括从 Material 继承的任何属性。
.color[Color]:材质的颜色,默认值为白色 0xffffff。.matcap[Texture]:matcap 贴图,默认为 null。MeshMatcapMaterial 是一种非常好用的材质,简单使用这种材质就能实现复杂的纹理效果,如本文中 Logo 的光泽效果,以及后续文字的金属效果以及透明玻璃效果,选择合适的材质,可以实现各种各样的神奇效果。下面这张图就是本文中所有元素的材质贴图,可以看出它们是一个个光照球体样式。

除了在 Blender、Photoshop等设计软件中生成 MeshMatcapMaterial 之外,下面几个网站可以免费下载各种好看的材质,并且具有在线实时预览功能,大家可以根据页面元素内容和自身需求找到合适的材质图片,感兴趣的话可以亲手试试看 ?。

?https://observablehq.com/@makio135/matcaps?ui=classic?https://github.com/nidorx/matcaps

?http://jeanmoreno.com/unity/matcap/http://jeanmoreno.com/unity/matcap/
1000!接着,来创建文字,此时需要引入 FontLoader,用于加载字体文件,它返回一个字体实例,然后使用 TextGeometry 创建文字网格,将它添加到场景中就可以了。
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';
fontLoader.load('fontface.json', font => {
textMesh.geometry = new TextGeometry('1000!', {
font: font,
size: 100,
height: 40
});
scene.add(textMesh);
});

看起来非常普通对不对,此时可以对 TextGeometry 进行对字符的厚度、斜角大小等参数的调整,我们可以按类似下面这种稍微优化一下,直至调整到自己满意的结果为止。
textMesh.geometry = new TextGeometry('1000!', {
font: font,
size: 100,
height: 40,
curveSegments: 100,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 10,
bevelOffset: 2,
bevelSegments: 10
});
看看优化后的效果,瞬间高大上了有木有 ✨!

THANK YOU使用同样的方法添加 THANK YOU 文字网格到场景中,并为它设置半透明玻璃效果的 MeshMatcapMaterial 和文字厚度斜角样式。

?关于文字网格的详细应用可以看看我的这篇文章 《使用Three.js实现神奇的3D文字悬浮效果》,本文中不再赘述了。
文字创建完成后,可以给它们添加一些文字翻转动画效果。动画效果是通过 Gsap 实现的,本文中给1000! 文字添加了一个缩放并翻转的动画效果,给 THANK YOU 添加了一个上下翻转的动画效果,可以参考如下方法来实现。
import gsap from 'gsap';
// 上下翻转动画
zoomAndFlip() {
gsap.timeline({
repeat: -1,
defaults: {
duration: 2,
ease: 'elastic.out(1.2, 1)',
stagger: 0.1,
},
})
.to(this.meshesPosition, { z: this.meshesPosition[0].z + 100 }, 'start')
.to(this.meshesRotation, { duration: 2, y: Math.PI * 2 }, 'start')
.to(this.meshesRotation, { duration: 2, y: Math.PI * 4 }, 'end')
.to(this.meshesPosition, { z: this.meshesPosition[0].z }, 'end');
}
?页面每次打开以及点击屏幕时,可以产生礼花效果。其中礼花中的每个小碎片使用了面基础缓冲模型 PlaneBufferGeometry 以及 MeshBasicMaterial 基础材质构成,在场景中创建三束礼花,每束礼花内的碎片位置和大小随机,并在一段时间后自动消失。同样,礼花的动画效果也是使用了 Gsap,并且使用了它的插件 Physics2DPlugin 来实现,Physics2DPlugin 插件可以模拟物理动画效果包括重力、速度、加速度、摩擦力动画等,有了它就能更好地实现礼花爆炸和散落效果。可以像本文中这样使用它们:
import gsap from 'gsap';
const physics2D = require('./physics2D');
gsap.registerPlugin(physics2D.Physics2DPlugin);
// 对每一片礼花应用动画效果
gsap.to(this.confettiSprites[id], DECAY, {
physics2D: {
velocity,
angle,
gravity,
friction,
},
ease: 'power4.easeIn',
onComplete: () => {
_.pull(this.confettiSpriteIds, id);
this.parent.remove(this.meshes[id]);
this.meshes[id].material.dispose();
delete this.confettiSprites[id];
},
});
? 知识点 Physics2DPluginPhysics2DPlugin 设置二维物理动画抛物线效果可选参数:
velocity:初始速度angle:角度gravity:重力acceleration:加速度accelerationAngle:加速度角度friction:摩擦力点击页面时触发动画
window.addEventListener('pointerdown', e => {
e.preventDefault();
this.confetti && this.confetti.pop();
});

?文字和礼花效果在实际中实现,其实是分别封装了两个类,方便从外部调用,具体实现详细代码可以访问文末提供的源码链接。
添加页面缩放适配和重绘动画来更新相机和轨道控制器等。在重绘动画中,给 Logo 添加了一个绕自身 Y轴 旋转的效果,可以通过 rotateOnAxis 实现。
window.addEventListener('resize', () => {
this.width = window.innerWidth;
this.height = window.innerHeight;
this.camera.aspect = this.width / this.height;
this.camera.updateProjectionMatrix();
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
this.renderer.setSize(this.width, this.height);
}, {
passive: true
});
const animate = () => {
requestAnimationFrame(animate);
controls && controls.update();
// 旋转动画
logo && logo.rotateOnAxis(axis, Math.PI / 400);
renderer.render(scene, camera);
}
❓大家可以亲自动手试试rotateOnAxis和rotateY实现的旋转效果有何不同来区分两者。
? 知识点 rotateOnAxis.rotateOnAxis 是 Three.js 中三维物体基类 Object3D 的一个方法,它可以在局部空间中绕着该物体的轴来旋转一个物体,假设这个轴已被标准化,它的使用方法如下所示。
.rotateOnAxis(axis: Vector3, angle: Float)
axis:一个在局部空间中的标准化向量。angle:角度,以弧度来表示。到这一步,页面的功能已经全部完成了 ?,最后可以装饰一下页面,如将 renderer 设置为透明,然后在 CSS 中使用一张好看的科技感图片作为页面背景,最后加上几个角落里的图片装饰物和 Github 图标链接,加一点点 CSS 动画,页面整体视觉效果就得到了不错的提升 ?。最后再次感谢大家关注!? 谢谢、栓Q、阿里嘎多

?源码地址:https://github.com/dragonir/3d/tree/master/src/containers/Fans
本文包含的知识点主要包括:
ConeGeometryCylinderGeometryMeshMatcapMaterialFontLoader 和 TextGeometryGsap 和它的插件 Physics2DPlugin 创建一些动画rotateOnAxis 方法实现绕轴自转想了解其他前端知识或其他未在本文中详细描述的
Web 3D开发技术相关知识,可阅读我往期的文章。转载请注明原文地址和作者。如果觉得文章对你有帮助,不要忘了一键三连哦 ?。
......本文作者:dragonir 本文地址:https://www.cnblogs.com/dragonir/p/16691845.html
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po