Sprite
精灵在计算机图形学中指包含在场景中的二维动画和图像,即sprite
是一个永远朝向相机的平面,类似广告牌,没有z
轴的概念,并且sprite
不接受阴影。
示例:https://ithanmang.gitee.io/threejs/home/201808/20180815/03-sprite-text.html
示例创建一个三维坐标轴,使用canvas
绘制字体,并作为纹理加入到sprite
的map
属性中,从而创建出二维字体标签,用来显示信息,并且可以跟随坐标轴缩放和移动。
首先,通过canvas
绘制出圆角矩形,并且矩形的大小随文字的多少而改变,关于canvas
的知识可以去http://www.runoob.com/html/html5-canvas.html 学习。
/* 绘制圆角矩形 */
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x+r, y);
ctx.lineTo(x+w-r, y);
ctx.quadraticCurveTo(x+w, y, x+w, y+r);
ctx.lineTo(x+w, y+h-r);
ctx.quadraticCurveTo(x+w, y+h, x+w-r, y+h);
ctx.lineTo(x+r, y+h);
ctx.quadraticCurveTo(x, y+h, x, y+h-r);
ctx.lineTo(x, y+r);
ctx.quadraticCurveTo(x, y, x+r, y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
然后,绘制文字精灵,并返回创建出的sprite
/* 创建字体精灵 */
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.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
+ borderColor.b + "," + borderColor.a + ")";
context.lineWidth = borderThickness;
/* 绘制圆角矩形 */
roundRect(context, borderThickness/2, borderThickness/2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);
/* 字体颜色 */
context.fillStyle = "rgba(0, 0, 0, 1.0)";
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(10,5,0);
return sprite;
}
使用sprite
可以用来显示模型的信息,当然使用div
和平面也可以显示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sprite 粒子(精灵)创建文字</title>
<style>
body {
margin: 0;
overflow: hidden;/* 溢出隐藏 */
}
</style>
<script src="../../libs/build/three-r93.js"></script>
<script src="../../libs/examples/js/Detector.js"></script>
<script src="../../libs/examples/js/libs/dat.gui.min.js"></script>
<script src="../../libs/examples/js/libs/stats.min.js"></script>
<script src="../../libs/examples/js/controls/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, 10000);
camera.position.set(20, 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 dirX = new THREE.Vector3( 1, 0, 0 );
var dirY = new THREE.Vector3( 0, 1, 0 );
var dirZ = new THREE.Vector3( 0, 0, 1 );
var origin = new THREE.Vector3( 0, 0, 0 );
var length = 10;
var arrowHelperX = new THREE.ArrowHelper( dirX, origin, length, 0xff0000 );
var arrowHelperY = new THREE.ArrowHelper( dirY, origin, length, 0x00ff00 );
var arrowHelperZ = new THREE.ArrowHelper( dirZ, origin, length, 0x0000ff );
scene.add( arrowHelperX );
scene.add( arrowHelperY );
scene.add( arrowHelperZ );
/* 原点 */
var spriteOrigin = makeTextSprite( " vector3(0, 0, 0) ",
{
fontsize: 20,
borderColor: {r:255, g:0, b:0, a:0.4},/* 边框黑色 */
backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景颜色 */
} );
spriteOrigin.center = new THREE.Vector2(0, 0);
scene.add( spriteOrigin );
spriteOrigin.position.set(0, -5, 0);
var spriteY = makeTextSprite( "Y",
{
fontsize: 20,
borderColor: {r:255, g:0, b:0, a:0.4},/* 边框黑色 */
backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景颜色 */
} );
spriteY.center = new THREE.Vector2(0, 0);
scene.add( spriteY );
spriteY.position.set(0, 6, 0);
var spriteX = makeTextSprite( "X",
{
fontsize: 20,
borderColor: {r:255, g:0, b:0, a:0.4},/* 边框黑色 */
backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景颜色 */
} );
spriteX.center = new THREE.Vector2(0, 0);
scene.add( spriteX );
spriteX.position.set(10, -5, 0);
var spriteZ = makeTextSprite( "Z",
{
fontsize: 20,
borderColor: {r:255, g:0, b:0, a:0.4},/* 边框黑色 */
backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景颜色 */
} );
spriteZ.center = new THREE.Vector2(0, 0);
scene.add( spriteZ );
spriteZ.position.set(0, -5, 10);
}
/* 创建字体精灵 */
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.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
+ borderColor.b + "," + borderColor.a + ")";
context.lineWidth = borderThickness;
/* 绘制圆角矩形 */
roundRect(context, borderThickness/2, borderThickness/2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);
/* 字体颜色 */
context.fillStyle = "rgba(0, 0, 0, 1.0)";
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(10,5,0);
return sprite;
}
/* 绘制圆角矩形 */
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x+r, y);
ctx.lineTo(x+w-r, y);
ctx.quadraticCurveTo(x+w, y, x+w, y+r);
ctx.lineTo(x+w, y+h-r);
ctx.quadraticCurveTo(x+w, y+h, x+w-r, y+h);
ctx.lineTo(x+r, y+h);
ctx.quadraticCurveTo(x, y+h, x, y+h-r);
ctx.lineTo(x, y+r);
ctx.quadraticCurveTo(x, y, x+r, y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
/* 性能插件 */
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>