threejs:如何在场景中创建立体文字,认识精灵模型
发现喜欢上自己慢慢写文章了,白天工作, 晚上正好写下总结,我会一直坚持下去的。我不是只发three的,只是现在工作到了这里必须学了,也欢迎各位友友一起讨论,一起加油。如果我的文章对你有帮助,麻烦关注+🌟更好得看到小D,欢迎转发分享让更多人看多,感谢!
1、通过TextTrue创建
THREE.js 封装了 TextGeometry 类可以很容易地生成三维文字
TextGeometry(text : String, parameters : Object)
参数说明:
text — The text that needs to be shown. (要显示的字符串)parameters — Object that can contains the following parameters.font — an instance of THREE.Font.(字体格式)size — Float. Size of the text. Default is 100.(字体大小)height — Float. Thickness to extrude text. Default is 50.(字体的深度)curveSegments — Integer. Number of points on the curves. Default is 12.(曲线控 制点数)bevelEnabled — Boolean. Turn on bevel. Default is False.(斜角)bevelThickness — Float. How deep into text bevel goes. Default is 10.(斜角的深 度)bevelSize — Float. How far from text outline is bevel. Default is 8.(斜角的大 小)bevelSegments — Integer. Number of bevel segments. Default is 3.(斜角段数)
var textLoad = newTHREE.FontLoader().load('fonts/helvetiker_regular.typeface.json',function(font){var txtGeo = new THREE.TextGeometry('hello world',{font: font,size: 0.8,height: 0.1,curveSegments: 12,bevelEnabled: true,bevelThickness: 0.1,bevelSize: 0.05,bevelSegments: 3});var txtMater = new THREE.MeshBasicMaterial({color: 0x0000ff})var txtMesh = new THREE.Mesh(txtGeo,txtMater);txtMesh.position.set(-2,2.3,-0.4);scene.add(txtMesh);});
俗话说得好,没事找麻木,有事找百度。
先去咱们无所不知无所不小的度娘去搜索ttf字体,随便点进去找一个自己喜欢的字体就好啦下载下来……
但是下载的格式得需要咱们转换一下,编程json格式的。
字体转换网站:https://gero3.github.io/facetype.js/
上个成品:
接下来给大家布上完整的代码:
<html lang="en"><head><meta charset="UTF-8"><title>Title</title><style type="text/css">* {margin: 0;padding: 0;}html {overflow: hidden;}</style><script src="../../lib/three.js"></script></head><body><script>var scene, camera, renderer;var ww = window.innerWidth;var wh = window.innerHeight;var aspect = ww / wh;function initThree() {// 创建场景scene = new THREE.Scene();// 创建相机camera = new THREE.PerspectiveCamera(70, aspect, 1, 2000);camera.position.set(0, 0, 100);// 创建渲染器(WebGL渲染器)renderer = new THREE.WebGLRenderer({antialias: true});renderer.setClearColor(0x000000, 1);renderer.setSize(ww, wh);document.body.appendChild(renderer.domElement);createPointLight();createDireLight();}// 创建点光源 需要照亮场景function createPointLight() {var light = new THREE.PointLight(0xffe502, 1, 1000);light.position.set(50, 50, 50);scene.add(light);}// 创建方向光 金属感强烈function createDireLight() {var direLight = new THREE.DirectionalLight(0xffe502, 1000);direLight.position.set(0, 500, 0);direLight.castShadow = true;scene.add(direLight);}// 执行动画function animate() {//TWEEN.update();renderer.render(scene, camera);requestAnimationFrame(animate)}// 创建文字function createText() {var text = new THREE.FontLoader().load('./fontChange.json', function(text) {var gem = new THREE.TextGeometry('Dawn的IT世界', {size: 20, //字号大小,一般为大写字母的高度height: 1, //文字的厚度weight: 'normal', //值为'normal'或'bold',表示是否加粗font: text, //字体,默认是'helvetiker',需对应引用的字体文件style: 'normal', //值为'normal'或'italics',表示是否斜体bevelThickness: 1, //倒角厚度bevelSize: 1, //倒角宽度curveSegments: 30,//弧线分段数,使得文字的曲线更加光滑bevelEnabled: true, //布尔值,是否使用倒角,意为在边缘处斜切});gem.center();var mat = new THREE.MeshPhongMaterial({color: 0xffe502,//该属性指定该材质的光亮程度及高光部分的颜色。如果将它设置成与 color 属性相同的颜色,将会得到一个更加类似金属的材质。如果将它设置成灰色(grey),材质将变得更像塑料。//specular: 0x009900,specular: 0x696969,//该属性指定镜面高光部分的亮度。默认值:30shininess: 30,//着色方式THREE.SmoothShading(默认值,这个将产生一个平滑的对象,看不到单个面)//THREE.NoShading//THREE.FlatShadingshading: THREE.FlatShading});var textObj = new THREE.Mesh(gem, mat);textObj.castShadow = true;scene.add(textObj);//new TWEEN.Tween(textObj.rotation).to({y: Math.PI * 2}, 2000).repeat(Infinity).yoyo(true).start();});}// startfunction threeStart() {initThree();createText();animate();}// resizefunction onResize() {ww = window.innerWidth;wh = window.innerHeight;camera.aspect = ww / wh;camera.updateProjectionMatrix();renderer.setSize(ww, wh);}window.addEventListener('load', threeStart, false);window.addEventListener('resize', onResize, false);</script></body></html>
2、通过精灵模型和Cavas画布
Three.js的精灵模型对象Sprite和Threejs的网格模型Mesh一样都是模型对象,基类都是Object3D,关于精灵模型对象 Sprite 的方法和属性除了可以查看文档Sprite,也可以查看基类Object3D。
Sprite和SpriteMaterial
通过 Sprite 创建精灵模型不需要几何体,只需要给构造函数 Sprite 的参数设置为一个精灵材质SpriteMaterial即可。精灵材质对象 SpriteMaterial 和普通的网格材质一样可以设置颜色 .color 、颜色贴图 .map 、开启透明 .transparent 、透明度 .opacity 等属性,精灵材质对象 SpriteMaterial 的基类是材质Material。精灵材质SpriteMaterial的属性除了和网格材质类似的属性和方法外,还有一些自己独特的方法和属性,比如 .rotation 旋转精灵模型,更多相关属性和方法可以查看threejs文档关于 SpriteMaterial 的介绍。
var texture = new THREE.TextureLoader().load("sprite.png"); // 创建精灵材质对象SpriteMaterial var spriteMaterial = new THREE.SpriteMaterial({ color:0xff00ff,//设置精灵矩形区域颜色rotation:Math.PI/4,//旋转精灵对象45度,弧度值map: texture,//设置精灵纹理贴图});// 创建精灵模型对象,不需要几何体geometry参数var sprite = new THREE.Sprite(spriteMaterial);scene.add(sprite); // 控制精灵大小,比如可视化中精灵大小表征数据大小sprite.scale.set(10, 10, 1); // 只需要设置x、y两个分量就可以
.scale 和.position
精灵模型对象和网格模型 Mesh 对一样基类都是 Object3D ,自然精灵模型也有缩放属性 .scale 和位置属性 .position ,一般设置精灵模型的大小是通过 .scale 属性实现,而精灵模型的位置通过属性 .position 实现,精灵模型和普通模型一样,可以改变它在三维场景中的位置,区别在于精灵模型的正面一直平行于canvas画布。在使用透视投影相机对象的时候,精灵模型对象显示的大小和网格模型一样受距离相机的距离影响,也就是距离越远,显示效果越小。
Sprite 用途
说到精灵模型对象,这种情况下你肯定关心它的用途,关于用途,你可以在三维场景中把精灵模型作为一个模型的标签,标签上可以显示一个写模型的信息,你可以通过足够多的精灵模型对象,构建一个粒子系统,来模拟一个下雨、森林、或下雪的场景效果。大家可以慢慢摸索。
上成品:
布代码:
<html lang="en"><head><meta charset="UTF-8"><title>Sprite 粒子(精灵)创建文字</title><style>body {margin: 0;overflow: hidden;/* 溢出隐藏 */}</style><script src="../../lib/three.js"></script><script src="../../lib/dat.gui.min.js"></script><script src="../../lib/stats.min.js"></script><script src="../../lib/OrbitControls.js"></script></head><body><script>var scene, camera, renderer, controls, points;var stats = initStats();/* 场景 */function initScene() {scene = new THREE.Scene();}/* 相机 */function initCamera() {camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100);camera.position.set(0, 10, 50);camera.lookAt(new THREE.Vector3(0, 0, 0));}/* 渲染器 */function initRender() {renderer = new THREE.WebGLRenderer({antialias: true});renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);}/* 灯光 */function initLight() {}/* 控制器 */function initControls() {controls = new THREE.OrbitControls(camera, renderer.domElement);/* 属性参数默认 */}/* 场景中的内容 */function initContent() {/* 原点 */var spriteOrigin = makeTextSprite( "dawniJAVA",{fontsize: 50,borderColor: 'rgba(255, 255, 255, 0)',/* 边框黑色 */backgroundColor: 'rgba(255, 255, 255, 0)'/* 背景颜色 */} );spriteOrigin.center = new THREE.Vector2(0, 0);scene.add( spriteOrigin );spriteOrigin.position.x=0;spriteOrigin.position.y=-4;spriteOrigin.position.z=0;// let axes = new THREE.AxisHelper(30);// scene.add(axes);}/* 创建字体精灵 */function makeTextSprite(message, parameters) {if ( parameters === undefined ) parameters = {};var fontface = parameters.hasOwnProperty("fontface") ?parameters["fontface"] : "Arial";/* 字体大小 */var fontsize = parameters.hasOwnProperty("fontsize") ?parameters["fontsize"] : 18;/* 边框厚度 */var borderThickness = parameters.hasOwnProperty("borderThickness") ?parameters["borderThickness"] : 4;/* 边框颜色 */var borderColor = parameters.hasOwnProperty("borderColor") ?parameters["borderColor"] : { r:0, g:0, b:0, a:1.0 };/* 背景颜色 */var backgroundColor = parameters.hasOwnProperty("backgroundColor") ?parameters["backgroundColor"] : { r:255, g:255, b:255, a:1.0 };/* 创建画布 */var canvas = document.createElement('canvas');var context = canvas.getContext('2d');/* 字体加粗 */context.font = "Bold " + fontsize + "px " + fontface;/* 获取文字的大小数据,高度取决于文字的大小 */var metrics = context.measureText( message );var textWidth = metrics.width;/* 背景颜色 */// context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + ","// + backgroundColor.b + "," + backgroundColor.a + ")";//context.fillStyle=backgroundColor;/* 边框的颜色 */// context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","// + borderColor.b + "," + borderColor.a + ")";//context.strokeStyle=borderColor;context.lineWidth = borderThickness;/* 绘制圆角矩形 */roundRect(context, borderThickness/2, borderThickness/2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);/* 字体颜色 */context.fillStyle = "#E9143B";context.fillText( message, borderThickness, fontsize + borderThickness);/* 画布内容用于纹理贴图 */var texture = new THREE.Texture(canvas);texture.needsUpdate = true;var spriteMaterial = new THREE.SpriteMaterial({ map: texture } );var sprite = new THREE.Sprite( spriteMaterial );console.log(sprite.spriteMaterial);/* 缩放比例 */sprite.scale.set(5,5,1);return sprite;}/* 绘制圆角矩形 */function roundRect(ctx, x, y, w, h, r) {ctx.beginPath();// 画笔移动到起始位置ctx.moveTo(x + r, y);// 绘制右上角的圆角ctx.arcTo(x + w, y, x + w, y + h, r);// 绘制右下角的圆角ctx.arcTo(x + w, y + h, x, y + h, r);// 画三角形轮廓// 绘制到三角形起点的位置ctx.lineTo(x + w, y + h);// 绘制三角形的起点到顶点的线段ctx.lineTo(x + w / 2 + 10, y + h);// 绘制顶点到三角形另一边的线段ctx.lineTo(x + w / 2, y + h+r);// 绘制三角形结束点到左下方的圆角起始处ctx.lineTo(x + w / 2 - 10, y + h );// 绘制左下角的圆角ctx.arcTo(x, y + h, x, y, r);// 绘制左上角的圆角ctx.arcTo(x, y, x + w, y, r);// 设置阴影ctx.shadowColor = 'rgba(0, 0, 0, 0.2)'; // 颜色ctx.shadowBlur = 5; // 模糊尺寸ctx.shadowOffsetX = 2; // 阴影Y轴偏移ctx.shadowOffsetY = 2; // 阴影X轴偏移// 关闭,形成一个闭合的回路---->轮廓ctx.closePath();// 填充ctx.fill();}/* 性能插件 */function initStats() {var stats = new Stats();document.body.appendChild(stats.domElement);return stats;}/* 窗口变动触发 */function onWindowResize() {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);}/* 数据更新 */function update() {stats.update();}/* 初始化 */function init() {initScene();initCamera();initRender();initLight();initControls();initContent();/* 监听事件 */window.addEventListener('resize', onWindowResize, false);}/* 循环渲染 */function animate() {requestAnimationFrame(animate);renderer.render(scene, camera);update();}/* 初始加载 */(function () {console.log("three init start...");init();animate();console.log("three init send...");})();</script></body></html>
