three.js 06-06 之 TextGeometry 几何体

本文介绍如何在Three.js中创建三维文本效果,包括字体加载、TextGeometry配置及示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    今天我们来看看在 three.js 中,如何快速的创建三维文本效果。在 three.js 中渲染文本非常简单,你所要做的只是指定想用的字体,以及基本的拉伸属性(基本上就是 ExtrudeGeometry 上提到的那些属性,极个别的除外)。我们先看看具体都有哪些属性,如下表所示:

属性描述
font可选。此属性指定要用的字体,它是一个 THREE.Font 对象
size可选。此属性指定字体的大小,它是一个 float 型,默认值是 100
height可选。此属性指定拉伸的高度,它是一个 float 型,默认值是 50
curveSegments可选。此属性指定文字图形中,曲线部分的分段数,默认值是 12
bevelEnabled可选。此属性指定文字图形是否启用斜角效果,默认值是 false
bevelThickness可选。此属性指定文字图形的斜角深度,它是一个 float 型,默认值是 10
bevelSize可选。此属性指定从文字图形的轮廓到斜角有多远,它是一个 float 型,默认值是 8
bevelSegments可选。此属性指定文字图形的斜角分段数,默认值是 3
    在 three.js 的发布包 examples/fonts 里包含了以下几种字体:

  • helvetiker
  • optimer
  • gentilis
  • droid sans
  • droid serif

要想创建一个三维文本图形,就需要加载相应的字体,然后再创建 THREE.TextGeometry 对象,代码大体如下:

function loadFont() {
	var fontUrl = "../build/fonts/gentilis_regular.typeface.json";
	var loader = new THREE.FontLoader();
	loader.load( fontUrl, function ( response ) {
		var font = response;
		// 定义选项
		var options = {
				amount: 0.1,
				//steps: 1,
				font: null,
				size: 8,
				height: 1.5,
				curveSegments: 12,
				bevelEnabled: false,
				bevelThinkness: 10,
				bevelSize: 8,
				bevelSegments: 3
			};
		// 定义 text
		var textGeometry = new THREE.TextGeometry("Learning \n Three.js", options);
		text = new THREE.SceneUtils.createMultiMaterialObject(textGeometry, meshMaterial);
	} );
}
    下面我们给出一个具体的示例,完整代码如下所示:

<!DOCTYPE html>
<html>
<head>
    <title>示例 06.07 - TextGeometry</title>
	<script src="../build/three.js"></script>
	<script src="../build/js/controls/OrbitControls.js"></script>
	<script src="../build/js/libs/stats.min.js"></script>
	<script src="../build/js/libs/dat.gui.min.js"></script>
	<script src="../jquery/jquery-3.2.1.min.js"></script>
    <style>
        body {
            /* 设置 margin 为 0,并且 overflow 为 hidden,来完成页面样式 */
            margin: 0;
            overflow: hidden;
        }
		/* 统计对象的样式 */
		#Stats-output {
			position: absolute;
			left: 0px;
			top: 0px;
		}
    </style>
</head>
<body>

<!-- 用于 WebGL 输出的 Div -->
<div id="webgl-output"></div>
<!-- 用于统计 FPS 输出的 Div -->
<div id="stats-output"></div>

<!-- 运行 Three.js 示例的 Javascript 代码 -->
<script type="text/javascript">

	var scene;
	var camera;
	var render;
	var webglRender;
	//var canvasRender;
	var controls;
	var stats;
	var guiParams;
	
	var ground;
	var text;
	
	var meshMaterial;
	
	var ambientLight;
	var spotLight;
	var axesHelper;
	//var cameraHelper;

    $(function() {
		stats = initStats();
		scene = new THREE.Scene();
		
		webglRender = new THREE.WebGLRenderer( {antialias: true, alpha: true} ); // antialias 抗锯齿
		webglRender.setSize(window.innerWidth, window.innerHeight);
		webglRender.setClearColor(0xeeeeee, 1.0);
		webglRender.shadowMap.enabled = true; // 允许阴影投射
		render = webglRender;
		
		camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 2147483647); // 2147483647
		camera.position.set(-45.5, 68.2, 90.9);
		
		var target = new THREE.Vector3(10, 0 , 0);
		controls = new THREE.OrbitControls(camera, render.domElement);
		controls.target = target;
		camera.lookAt(target);
		
		$('#webgl-output')[0].appendChild(render.domElement);
		window.addEventListener('resize', onWindowResize, false);
		
		// 加入一个坐标轴:X(橙色)、Y(绿色)、Z(蓝色)
		axesHelper = new THREE.AxesHelper(60);
		scene.add(axesHelper);
		
		ambientLight = new THREE.AmbientLight(0x0c0c0c);
		scene.add(ambientLight);
		
		spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(0, 260, 230);
		spotLight.shadow.mapSize.width = 5120; // 必须是 2的幂,默认值为 512
		spotLight.shadow.mapSize.height = 5120; // 必须是 2的幂,默认值为 512
        spotLight.castShadow = true;
        scene.add(spotLight);
		//cameraHelper = new THREE.CameraHelper(spotLight.shadow.camera);
		//scene.add(cameraHelper);
		
		// 加入一个地面
		var groundGeometry = new THREE.PlaneGeometry(100, 100, 4, 4);
		var groundMaterial = new THREE.MeshLambertMaterial({color: 0x777777}); // MeshBasicMaterial 材质不能接收阴影
		ground = new THREE.Mesh(groundGeometry, groundMaterial);
		ground.rotation.set(-0.5 * Math.PI, 0, 0); // 沿着 X轴旋转-90°
		ground.receiveShadow = true;
		scene.add(ground);
		
		// 材质
        meshMaterial = [
			new THREE.MeshPhongMaterial({
				specular: 0xffffff,
                color: 0xeeffff,
                shininess: 100,
				side: THREE.DoubleSide})
			//,new THREE.MeshBasicMaterial({wireframe: true})
		];
		
		/** 用来保存那些需要修改的变量 */
		guiParams = new function() {
			this.rotationSpeed = 0.02;
			
			this.options = {
				amount: 0.1,
				//steps: 1,
				font: null,
				size: 8,
				height: 1.5,
				curveSegments: 12,
				bevelEnabled: false,
				bevelThinkness: 10,
				bevelSize: 8,
				bevelSegments: 3
			};
		}
		/** 定义 dat.GUI 对象,并绑定 guiParams 的几个属性 */
		var gui = new dat.GUI();
		gui.add(guiParams.options, "size", 1, 72, 1).onChange(function(e){createText()});
		gui.add(guiParams.options, "height", 0.1, 15, 0.1).onChange(function(e){createText()});
		gui.add(guiParams.options, "curveSegments", 1, 30, 1).onChange(function(e){createText()});
		gui.add(guiParams.options, "bevelEnabled").onChange(function(e){createText()});
		gui.add(guiParams.options, "bevelThinkness", 0, 15, 0.01).onChange(function(e){createText()});
		gui.add(guiParams.options, "bevelSize", 0, 15, 0.01).onChange(function(e){createText()});
		gui.add(guiParams.options, "bevelSegments", 1, 12, 1).onChange(function(e){createText()});
		
		//../build/fonts/gentilis_regular.typeface.json
		//../build/fonts/helvetiker_regular.typeface.json
		//../build/fonts/droid/droid_sans_regular.typeface.json
		//../build/fonts/droid/droid_serif_regular.typeface.json
		loadFont('../build/fonts/droid/droid_sans_regular.typeface.json');
		
		renderScene();
    });
	
	/** 渲染场景 */
	function renderScene() {
		stats.update();
		rotateMesh(); // 旋转物体
		
		requestAnimationFrame(renderScene);
		render.render(scene, camera);
	}
	
	/** 初始化 stats 统计对象 */
	function initStats() {
		stats = new Stats();
		stats.setMode(0); // 0 为监测 FPS;1 为监测渲染时间
		$('#stats-output').append(stats.domElement);
		return stats;
	}
	
	/** 当浏览器窗口大小变化时触发 */
	function onWindowResize() {
		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		render.setSize(window.innerWidth, window.innerHeight);
	}
	
	/** 旋转物体 */
	var step = 0;
	function rotateMesh() {
		step += guiParams.rotationSpeed;
		scene.traverse(function(mesh) {
			if (mesh === text) {
				//mesh.rotation.x = step;
				mesh.rotation.y = step;
				//mesh.rotation.z = step;
			}
		});
	}
	
	function createText() {
		scene.remove(text);
		
		// 定义 text
		var textGeometry = new THREE.TextGeometry("Learning \n Three.js", guiParams.options);
		text = new THREE.SceneUtils.createMultiMaterialObject(textGeometry, meshMaterial);
		//text.scale.set(0.1, 0.1, 0.1);
		textGeometry.computeBoundingBox();
		text.position.set(0, Math.abs(textGeometry.boundingBox.min.y), 0);
		scene.add(text);
	}
	
	/** 加载字体,传入字体 json 路径,如“../build/fonts/helvetiker_bold.typeface.json” */
	function loadFont(fontUrl) {
		var loader = new THREE.FontLoader();
		loader.load( fontUrl, function ( response ) {
			var font = response;
			guiParams.options.font = font;
			createText();
		} );
	}

</script>
</body>
</html>
    在这个示例中,读者可以利用右上角的菜单功能自由地试验各种常用参数的效果。特别地,关于 bevel 斜角的几个参数比较难观察出效果,这里针对本示例给出一个指导试验方案:先启用 bevelEnabled,然后把右上角 size 和 height 两个值调至最大,仔细观察“T”字轮廓处并不断调小这两个值看看有啥不同效果。

    以上都是 three.js 发布包里自带的字体。如果需要自定义的字体又该怎么来弄呢?其实并不难,例如我想在 three.js 中使用 Windows 10 系统里的仿宋字体,步骤如下:

  • 第一步,我们把操作系统路径下(例如我的电脑是 C:\Windows\Fonts\仿宋 常规)的字体“仿宋 常规”拷贝出来(譬如 D:\myfonts)
  • 第二步,打开浏览器并在地址栏输入 https://gero3.github.io/facetype.js/ 链接,然后点击“选择文件”上传刚才我们拷贝出来的字体文件(D:\myfonts\simfang.ttf)
  • 第三步,上传完成后,选中“Generate a JSON file (.json)”选项,最后点击“Convert”按钮,等待一会儿会有一个转换后的 xxx.json 文件下载下来(譬如 D:\myfonts\FangSong_Regular.json)
  • 第四步,把这个转换好的 xxx.json 文件加载到你的场景中使用即可

未完待续···

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值