

HTML5 网页 3D 场景制作之 Three.js 初体验 - 制作 3D 字体
source link: https://blog.51cto.com/micai01/5845062
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

HTML5 网页 3D 场景制作之 Three.js 初体验 - 制作 3D 字体
精选 原创在学习Three.js之前,我们先来了解WebGL,因为WebGL是Three.js的基础和规范.
那什么是WebGL呢?
WebGL(全写Web Graphics Library)是一种3D绘图协议,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。
WebGL(图形库是一个JavaScript API)在任何连接的WebGL中渲染图形的API,Web3D和Web3D的图形应用程序,可以单独使用一个WebGL通过引入与OpenGL 2.0一致的浏览器来使用WebGL 2.0
WebGL完美地解决了现有的Web交互式三维动画的两个问题:
第一,它通过HTML脚本本身实现Web交互式三维动画的制作,无需任何浏览器插件的支持;
第二,它利用底层的图形硬件加速功能进行的图形渲染,是通过统一的、标准的、跨平台的OpenGL接口实现的。
WebGL的使用条件
WebGL 使得在支持 HTML 的 canvas 标签的浏览器中
支持 WebGL 的浏览器
支持 WebGL 的浏览器有:Firefox 4+、Google Chrome 9+、Opera 12+、Safari 5.1+ 、 Internet Explorer 11+(当然IE已经退出历史舞台) 和Microsoft Edge build 10240+;然而,WebGL 的一些特性目前也需要用户的硬件设备支持。
WebGL 2 API 引入了对光源的 OpenGL ES 3.0 功能集的支持;它是通过WebGL2RenderingContext界面提供的。
<canvas> 元素也被 Canvas API 用于在网页上进行 2D 图形处理。
举个入门的例子:
准备 3D 渲染
为了使用 WebGL 进行 3D 渲染,你首先需要一个 canvas 元素。下面的 HTML 片段用来建立一个 canvas 元素并设置一个 onload 事件处理程序来初始化我们的 WebGL 上下文 。
#检测浏览器是否支持webGL
<canvas id="glcanvas" width="640" height="480">
你的浏览器似乎不支持或者禁用了 HTML5 <code><canvas></code> 元素。
</canvas>
</body>
如果页面空白没有提示说明你的浏览器支持WebGL
准备 WebGL 上下文
JavaScript 代码中的 main()
函数将会在文档加载完成之后被调用。它的任务是设置 WebGL 上下文并开始渲染内容。
<head>
<title>webgl测试</title>
</head>
<body onload="main()">
<canvas id="glcanvas" width="640" height="480">
你的浏览器似乎不支持或者禁用了 HTML5 <code><canvas></code> 元素。
</canvas>
<script>
// 从这里开始
function main() {
const canvas = document.querySelector("#glcanvas");
// 初始化 WebGL 上下文
const gl = canvas.getContext("webgl");
// 确认 WebGL 支持性
if (!gl) {
alert("无法初始化 WebGL,你的浏览器、操作系统或硬件等可能不支持 WebGL。");
return;
}
// 使用完全不透明的浅黄色清除所有图像
gl.clearColor(255, 70.0, 0.0, 1.0);
// 用上面指定的颜色清除缓冲区
gl.clear(gl.COLOR_BUFFER_BIT);
}
</script>
</body>
</html>

1.获取 canvas 的引用,把它保存在 ‘canvas’ 变量里。
2.获取到 canvas 之后,我们会调用getContext 函数并向它传递"webgl"
参数,来尝试获取WebGLRenderingContext。如果浏览器不支持 webgl,getContext
将会返回null
,我们就可以显示一条消息给用户然后退出。
3.如果 WebGL 上下文成功初始化,变量 ‘gl’ 会用来引用该上下文。在这个例子中,我们用浅黄色清除上下文内已有的元素。(用背景颜色重绘 canvas)。
Three.js入门
使用WebGL原生的API来书写3D程序是一件非常痛苦且艰难的事.调用原生的API需要考虑解决各平台之间的差异产生的兼容问题,这时候很多大佬看到问题所在,封装了THREE.js和BABYLON.js等很多框架封装了 WebGL,提供了各个平台之间的兼容性。使用这些框架而非原生的 WebGL 可以更容易地开发 3D 应用和游戏。
Three.js也是我开发3D场景最常用的一个框架,一般运用于各种动画场景,3D街景展示,3D地图展示等.
创建一个WebGL程序,你基本上需要4个步骤:
- 初始化WebGL绘图上下文
- 初始化着色器程序
- 建立模型和数据缓存
- 完成绘制和动画
这基本是一种过程式编程,而Three.js则不尽相同,其使用面向对象的方式来构建程序,包含3个基本对象: 场景(scene), 相机(camera), 以及一个渲染器(renderer)。 拿电影来类比的话,场景对应于整个布景空间,相机是拍摄镜头,渲染器用来把拍摄好的场景转换成胶卷(对于网页来讲,是电脑屏幕)。 场景和相机代表了3D观察空间和数据模型,渲染器则包含了WebGL绘图上下文和着色器。
我们从一个例子入手:
<head>
<title>我的第一个three.js app</title>
<style> body { margin: 0; } canvas { width: 100%; height: 100% } </style>
</head>
<body>
<script src="./three.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
var animate = function() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
</script>
</body>
</html>
本段代码渲染效果如下:一个3D旋转的正方体

基本3个步骤:
1.创建场景
2场景中添加展示物体
3.渲染场景(这里如果不使用render渲染场景,页面不会有任何展示)
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
上面的代码构建了scene, camera 和 renderer。Three.js的架构支持多种camera,这里使用最常见的远景相机(PerspectiveCamera),也就是类似于人眼观察的方式。第一个属性75设置的是视角(field of view)。
第二个属性设置的是相机拍摄面的长宽比(aspect ratio)。我们几乎总是会使用元素的宽除以高,否则会出现挤压变形。
接下来的2个属性是近裁剪面(near clipping plane) 和 远裁剪面(far clipping plane)。下面这张图可以帮助你理解:

这几个参数所限定的绿色3D空间被称之为视椎体(View Frustum),用来裁剪视图,在该视锥体以外的物体将不会被渲染。我们暂时可以先不管,但你需要了解这个空间和渲染性能有关。
接下来是渲染器,所有魔法效果都在这里产生。除了我们这里使用的WebGLRenderer,three.js还支持一些其它渲染器,基本上只是用来回退处理那些不支持WebGL的旧式用户浏览器。
除了创建renderer实例,我们还需要设置渲染空间的尺寸,一般就使用目标屏幕的宽高(window.innerWidth和window.innerHeight),也可以给定一个小尺寸。
如果你想保持渲染空间的尺寸,但使用一个较低的分辨率,你可以在调用setSize的时候设置参数updateStyle为false,比如 setSize(window.innerWidth/2, window.innerHeight/2, false) 将使用1/2分辨率来绘制你的应用程序,假定<canvas>为100%的宽高。
最后,我们把 renderer 元素添加到HTML文档中。这里是一个 <canvas> 元素,渲染器用来显示场景。
在场景中添加展示物体
上面的都是准备工作,电影布景都好了,演员还没进场。接下来我们添加“演员”(3D立方体)。
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
渲染场景(Rendering the scene)
我们需要一个 渲染循环(render loop)才能让他场景展示
这将创建一个循环,以每秒60次的频率来绘制场景,且使用 cube.rotation为场景中的物体添加动画
requestAnimationFrame( render );
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
3D字体制作
需要引入的js库
<script src="GeometryUtils.js"></script>
<script src="OrbitControls.js"></script>
<script src="stats.min.js"></script>
<script src="dat.gui.min.js"></script>
GeometryUtils.js是几何体类库,Geometry类库是api中所有几何要素的类的父类或者基类,构造函数为new THREE.Geometry()。在3D当中,物体都是由网格构成的,而网格的组织规则是通过几何体(Geometry)来定义。在three.js中,有两类几何体,我把它们叫做基本几何体和buffer几何体。基本几何体的顶点位置,缩放,旋转角,颜色,法线信息都是保存在特定的类里面,比如顶点位置使用Vector3,颜色信息使用Color。three.js中基本上是每个基本几何体都有一个buffer几何体与之对应,而且两者的创建方式和参数基本一致.
dat.gui.min.js是three.js调试的利器,该工具类为你调试three.js的各项参数提供可视化操作,你可以声明一个对象,对象内包括所有需要修改的属性,比如:
lightY:30, //灯光y轴的位置
sphereX:0, //球的x轴的位置
sphereZ:0, //球的z轴的位置
cubeX:25, //立方体的x轴位置
cubeZ:-5 //立方体的z轴的位置
};
接着就可以实例化GUI对象:
//将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)
datGui.add(gui,"lightY",0,100);
datGui.add(gui,"sphereX",-30,30);
datGui.add(gui,"sphereZ",-30,30);
datGui.add(gui,"cubeX",0,60);
datGui.add(gui,"cubeZ",-30,30);
按照下面的方式就可以修改控制相关参数的变化
light.position.y = gui.lightY;
sphere.position.x = gui.sphereX;
sphere.position.z = gui.sphereZ;
cube.position.x = gui.cubeX;
cube.position.z = gui.cubeZ;
它最常用的方法就是添加控件add(),监听控件listen()
stats.min.js是three.js的性能监测插件.我们可以通过stats知道实时的FPS信息,从而更好地监测动画渲染效果,具体的使用在下面例子中展现
OrbitControls是相机控件,通过OrbitControls.js可以对Three.js的三维场景进行缩放、平移、旋转操作,本质上改变的并不是场景,而是相机的参数,相机的位置角度不同,同一个场景的渲染效果是不一样,比如一个相机绕着一个场景旋转,就像场景旋转一样。它的源码在Three.js\examples\js\controls
目录下的OrbitControls.js
文件
了解了相关插件的作用,接下来进入实操:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ThreeJS的3D文字场景</title>
<script src="https://johnson2heng.github.io/three.js-demo/lib/three.js"></script>
<!--几何体类库-->
<script src="https://johnson2heng.github.io/three.js-demo/lib/js/utils/GeometryUtils.js"></script>
<!--相机控件-->
<script src="https://johnson2heng.github.io/three.js-demo/lib/js/controls/OrbitControls.js"></script>
<!--性能控件-->
<script src="https://johnson2heng.github.io/three.js-demo/lib/js/libs/stats.min.js"></script>
<!--可视化调试-->
<script src="https://johnson2heng.github.io/three.js-demo/lib/js/libs/dat.gui.min.js"></script>
<style type="text/css">
html, body {
margin: 0;
height: 100%;
}
canvas {
display: block;
}
</style>
</head>
<body onload="draw();">
</body>
<script>
var renderer;
function initRender() {
renderer = new THREE.WebGLRenderer({antialias: true});
//renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0)); //设置背景颜色
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
var camera;
function initCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 200, 500);
}
var scene;
function initScene() {
scene = new THREE.Scene();
}
var light;
function initLight() {
scene.add(new THREE.AmbientLight(0x404040));
light = new THREE.DirectionalLight(0xffffff);
light.position.set(1, 1, 1);
scene.add(light);
}
function initModel() {
//轴辅助 (每一个轴的长度)
object = new THREE.AxesHelper(50);
scene.add(object);
}
//生成模型
function createMesh(geom) {
//设置当前的模型矩阵沿xy轴偏移,让图片处于显示中心
geom.applyMatrix(new THREE.Matrix4().makeTranslation(-250, -100, 0));
// 创建法向量纹理
var meshMaterial = new THREE.MeshNormalMaterial({
flatShading: THREE.FlatShading,
transparent: true,
opacity: 0.9
});
// 创建一个线框纹理
var wireFrameMat = new THREE.MeshBasicMaterial();
wireFrameMat.wireframe = true;
// 创建模型
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]);
return mesh;
}
//初始化性能插件
var stats;
function initStats() {
stats = new Stats();
document.body.appendChild(stats.dom);
}
//用户交互插件 鼠标左键按住旋转,右键按住平移,滚轮缩放
var controls;
function initControls() {
controls = new THREE.OrbitControls(camera, renderer.domElement);
// 如果使用animate方法时,将此函数删除
//controls.addEventListener( 'change', render );
// 使动画循环使用时阻尼或自转 意思是否有惯性
controls.enableDamping = true;
//动态阻尼系数 就是鼠标拖拽旋转灵敏度
//controls.dampingFactor = 0.25;
//是否可以缩放
controls.enableZoom = true;
//是否自动旋转
controls.autoRotate = false;
//设置相机距离原点的最远距离
controls.minDistance = 20;
//设置相机距离原点的最远距离
controls.maxDistance = 10000;
//是否开启右键拖拽
controls.enablePan = true;
}
//生成gui设置配置项
var gui;
var text1,text2;
function initGui() {
//声明一个保存需求修改的相关数据的对象
gui = {
size: 90,
height: 90,
bevelThickness: 2,
bevelSize: 0.5,
bevelEnabled: true,
bevelSegments: 3,
curveSegments: 12,
steps: 1,
fontName: "helvetiker",
fontWeight:"bold",
weight: "normal",
font:null,
style:"italics",
changeFont:function () {
//创建loader进行字体加载,供后面的模型使用
var loader = new THREE.FontLoader();
loader.load( './3d/js/Microsoft YaHei_Regular.json', function ( response ) {
gui.font = response;
gui.asGeom();
} );
},
asGeom: function () {
// 删除掉原来的旧模型
scene.remove(text1);
scene.remove(text2);
// 重新创建模型
var options = {
size: gui.size,
height: gui.height,
weight: gui.weight,
font: gui.font,
bevelThickness: gui.bevelThickness,
bevelSize: gui.bevelSize,
bevelSegments: gui.bevelSegments,
bevelEnabled: gui.bevelEnabled,
curveSegments: gui.curveSegments,
steps: gui.steps
};
text1 = createMesh(new THREE.TextGeometry("InfoQ 15周年庆!", options));
text1.position.z = -100;
text1.position.y = 100;
scene.add(text1);
text2 = createMesh(new THREE.TextGeometry("\n无限生长\n未来可期!", options));
scene.add(text2);
}
};
var datGui = new dat.GUI();
//将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)
datGui.add(gui, 'size', 0, 200).onChange(gui.asGeom);
datGui.add(gui, 'height', 0, 200).onChange(gui.asGeom);
datGui.add(gui, 'fontName', ['gentilis', 'helvetiker', 'optimer']).onChange(gui.changeFont);
datGui.add(gui, 'fontWeight', ['regular', 'bold']).onChange(gui.changeFont);
datGui.add(gui, 'bevelThickness', 0, 10).onChange(gui.asGeom);
datGui.add(gui, 'bevelSize', 0, 10).onChange(gui.asGeom);
datGui.add(gui, 'bevelSegments', 0, 30).step(1).onChange(gui.asGeom);
datGui.add(gui, 'bevelEnabled').onChange(gui.asGeom);
datGui.add(gui, 'curveSegments', 1, 30).step(1).onChange(gui.asGeom);
datGui.add(gui, 'steps', 1, 5).step(1).onChange(gui.asGeom);
//调用生成一次图形
gui.changeFont();
}
function render() {
renderer.render(scene, camera);
}
//窗口变动触发的函数
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
render();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
//更新控制器
controls.update();
render();
//更新性能插件
stats.update();
requestAnimationFrame(animate);
}
//渲染到页面
function draw() {
initRender();
initScene();
initCamera();
initLight();
initModel();
initControls();
initStats();
initGui();
animate();
window.onresize = onWindowResize;
}
</script>
</html>
实例当中所用到的字体可通过 http://gero3.github.io/facetype.js/转换
效果如下:


这只是three.js的基本用法,想更好地掌握和运用three.js,创建更多炫酷的3D场景,需要拥有丰富的空间思维和空间想象力.three.js还有更多强大的3D场景待你发掘......
Recommend
-
124
Three.js 初探 - 微场景制作 2017年11月10日 01:18 · 阅读 13879 最近在...
-
58
网页中这10种字体的运用方式,不会让人觉得Low
-
16
酷炫的 HTML5 网页 PPT 2019/4月/15 20:07:39 发布在 技术博文...
-
12
by zhangxinxu from http://www.zhangxinxu.com/wordpress/?p=6220 本文可全文转载,但需得到原作者书面许可,同时保留原作者和出处,摘要引流则随...
-
9
从13年刚开始搭建博客的时候我就在关注中文的 webfont 解决方案了,可惜那时候几乎找不到一套成熟的跨平台字体设置方案,Google Fonts 和 Typekit 也远没有现在这么完善,Windows 下微软雅黑丑出天际,我们能做的无非就是老老实实设置好 fallback 来确保不同操...
-
10
网页安全字体 谢益辉 / 2017-07-03 所谓网页安全字体(web safe fonts),就是基本上能保证所有用户看见的是类似的字体,也就是说他们的操作系统里以很大概率自带了这些字体。
-
11
by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=2058
-
6
HTML5 Canvas在预加载完字体后绘图 作者:广树
-
6
网页的设计的样式都由css控制, 我们的css大小单位,一般用 px,或rem,或vw,vh. 由px控制的大小是固定的,不具有响度式的. 响应式设计一般由两种方案实现. 一.rem方案. 实现方法 : 1.head中加
-
7
如何制作简易的HTML5幻灯片本文摘自 勾三股四 更早时期的 不老歌 博客。在此贴上本人在
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK