vlambda博客
学习文章列表

threejs:如何在场景中创建立体文字,认识精灵模型

发现喜欢上自己慢慢写文章了,白天工作, 晚上正好写下总结,我会一直坚持下去的。我不是只发three的,只是现在工作到了这里必须学了,也欢迎各位友友一起讨论,一起加油。如果我的文章对你有帮助,麻烦关注+🌟更好得看到小D,欢迎转发分享让更多人看多,感谢threejs:如何在场景中创建立体文字,认识精灵模型

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格式的。

threejs:如何在场景中创建立体文字,认识精灵模型

threejs:如何在场景中创建立体文字,认识精灵模型


字体转换网站:https://gero3.github.io/facetype.js/

threejs:如何在场景中创建立体文字,认识精灵模型

threejs:如何在场景中创建立体文字,认识精灵模型

上个成品:

threejs:如何在场景中创建立体文字,认识精灵模型

接下来给大家布上完整的代码:

<!DOCTYPE html><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, //该属性指定镜面高光部分的亮度。默认值:30 shininess: 30, //着色方式THREE.SmoothShading(默认值,这个将产生一个平滑的对象,看不到单个面) //THREE.NoShading //THREE.FlatShading shading: 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(); }); } // start function threeStart() { initThree(); createText(); animate(); } // resize function 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的精灵模型对象SpriteThreejs的网格模型Mesh一样都是模型对象,基类都是Object3D,关于精灵模型对象 Sprite 的方法和属性除了可以查看文档Sprite,也可以查看基类Object3D

SpriteSpriteMaterial

通过 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(10101); // 只需要设置x、y两个分量就可以

.scale .position

精灵模型对象和网格模型 Mesh 对一样基类都是 Object3D ,自然精灵模型也有缩放属性 .scale 和位置属性 .position ,一般设置精灵模型的大小是通过 .scale 属性实现,而精灵模型的位置通过属性 .position 实现,精灵模型和普通模型一样,可以改变它在三维场景中的位置,区别在于精灵模型的正面一直平行于canvas画布。在使用透视投影相机对象的时候,精灵模型对象显示的大小和网格模型一样受距离相机的距离影响,也就是距离越远,显示效果越小。

Sprite 用途

说到精灵模型对象,这种情况下你肯定关心它的用途,关于用途,你可以在三维场景中把精灵模型作为一个模型的标签,标签上可以显示一个写模型的信息,你可以通过足够多的精灵模型对象,构建一个粒子系统,来模拟一个下雨、森林、或下雪的场景效果。大家可以慢慢摸索。

上成品:

布代码:

<!DOCTYPE html><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>