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 = new
THREE.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,
//该属性指定镜面高光部分的亮度。默认值: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的精灵模型对象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>