郭隆邦老师threejs教程学习笔记
threejs可以使用精灵模型或者平面网格模型作为模型标签,为了显示模型的信息,可以用一张图片作为精灵或平面网格模型的颜色贴图,也可以在canvas画布上绘制好要表达的几何图形、文字等信息,比如进度条,然后作为精灵或平面网格模型的颜色贴图。
canvas画布作为精灵模型的颜色贴图
//创建一个canvas画布绘制模型的信息,作为模型标签精灵的颜色贴图
const canvas = document.createElement("canvas");
//精灵模型会随着场景缩放,注意画布宽高尺寸不能太小
//如果canvas宽高太小,精灵标签可能会模糊
canvas.width = 512;
canvas.height = 128;
const ctx = canvas.getContext('2d');
// 矩形区域填充背景,半透明
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(0, 0, 512, 128);
ctx.beginPath();
ctx.beginPath();
ctx.translate(50, 64);
ctx.font = "bold 48px 宋体";
ctx.textBaseline = "middle";
ctx.fillStyle = "#ffffff";
ctx.fillText("写字楼人数:", 0, 0);
ctx.translate(300, 0);
ctx.fillStyle = "#00ffff";
ctx.fillText("100人", 0, 0);
//canvas画布不需要插入到body中
// document.body.appendChild(canvas)
// canvas画布对象作为CanvasTexture的参数重建一个纹理对象
// canvas画布可以理解为一张图片
const texture = new THREE.CanvasTexture(canvas);
const spriteMaterial = new THREE.SpriteMaterial({
map: texture
});
// 创建精灵模型对象
const sprite = new THREE.Sprite(spriteMaterial);
//注意xy两个方向缩放比例和canvas宽高比例一致
sprite.scale.set(96, 24, 1);
sprite.position.copy(boxMesh.position)
sprite.position.y += 70
scene.add(sprite)
canvas画布宽高(像素)
canvas画布作为精灵模型.Sprite
的颜色贴图.map
,也就是说canvas画布的宽高尺寸就是精灵颜色贴图的像素大小。所以要注意canvas画布的大小,过大占用过多的资源,过小精灵模型标签可能会显示模糊
//精灵模型会随着场景缩放,注意画布宽高尺寸不能太小
//如果canvas宽高太小,精灵标签可能会模糊
canvas.width = 512;
canvas.height = 128;
宽高比例
canvas画布作为精灵模型.Sprite
的颜色贴图,注意xy两个方向缩放比例和canvas宽高比例一致,以免压缩或拉伸
sprite.scale.set(96, 24, 1);
canvas画布作为矩形平面网格模型Mesh
的颜色贴图,注意矩形几何体PlaneGeometry
宽高比例和canvas宽高比例一致,以免压缩或拉伸
const plane = new THREE.PlaneGeometry(96, 24);
创建多个canvas精灵标签
封装createSprite函数用于创建精灵标签,封装一个repaint函数用于canvas的重绘。
function createSprite(mesh, number) {
//创建一个canvas画布绘制模型的信息,作为模型标签精灵的颜色贴图
var canvas = document.createElement("canvas");
//精灵模型会随着场景缩放,注意画布宽高尺寸不能太小
//如果canvas宽高太小,精灵标签可能会模糊
canvas.width = 512;
canvas.height = 128;
var c = canvas.getContext('2d');
var texture = new THREE.CanvasTexture(canvas);
var spriteMaterial = new THREE.SpriteMaterial({
map: texture
});
// 创建精灵模型对象
var sprite = new THREE.Sprite(spriteMaterial);
//注意xy两个方向缩放比例和canvas宽高比例一致
sprite.scale.set(96, 24, 1);
sprite.position.copy(mesh.position)
sprite.position.y += 70
groupSprite.add(sprite)
//封装一个canvas画布创建函数 num:人数
sprite.repaint = function(num) {
// 每次调用的时候,清空当前画布
canvas.width = 512; //重置画布尺寸,会清空
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(0, 0, 512, 128);
ctx.beginPath();
ctx.beginPath();
ctx.translate(50, 64);
ctx.font = "bold 48px 宋体";
ctx.textBaseline = "middle";
ctx.fillStyle = "#ffffff";
ctx.fillText("写字楼人数:", 0, 0);
ctx.translate(300, 0);
ctx.fillStyle = "#00ffff";
ctx.fillText(num + "人", 0, 0);
}
//如果写字楼的人数变化了,比如后端通知前端,前端直接调用repaint()函数,输入新的人数重新绘制即可
sprite.repaint(number)
}
createSprite(boxMesh, 132)
createSprite(boxMesh2, 126)
createSprite(boxMesh3, 100)
第一步调用repaint()
函数更新canvas画布,然后通过新绘制的canvas画布重新创建一个纹理对象CanvasTexture
赋值给给材质颜色贴图属性.map
,或者设置Texture.needsUpdate = true
直接告诉threejs渲染系统纹理对象需要更新。
// 通过周期性函数setInterval模拟前端获得后端数据更新模型标签的数据
setInterval(updateNumber, 100);
function updateNumber() {
// 随机计算一个人数,模拟写字楼真实的人数变化
const num = 100 + Math.floor(Math.random() * 200)
var sprite = groupSprite.children[0]
// 重新绘制canvas
sprite.repaint(num);
// 利用重绘后的canvas创建一个新的纹理对象赋值给精灵.map属性
//sprite.material.map = new THREE.CanvasTexture(canvas);
//也可以不用给.map重新赋值,Texture.needsUpdate设置为true,告诉系统更新纹理对象即可
sprite.material.map.needsUpdate = true;
}
效果图:
canvas画布作为平面网格模型的颜色贴图
canvas画布作为平面网格模型的颜色贴图和作为精灵模型的颜色贴图代码基本结构是相同的。
const canvas = document.createElement("canvas");
canvas.width = 512;
canvas.height = 128;
var ctx = canvas.getContext('2d');
//如果写字楼的人数变化了,比如后端通知前端,前端直接调用repaint()函数,输入新的人数重新绘制即可
repaint(100);
//封装一个canvas画布创建函数 number:人数
function repaint(number) {
// 每次调用的时候,清空当前画布
canvas.width = 512; //重置画布尺寸,会清空
// 矩形区域填充背景,半透明
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(0, 0, 512, 128);
ctx.beginPath();
ctx.beginPath();
ctx.translate(50, 64);
ctx.font = "bold 48px 宋体";
ctx.textBaseline = "middle";
ctx.fillStyle = "#ffffff";
ctx.fillText("写字楼人数:", 0, 0);
ctx.translate(300, 0);
ctx.fillStyle = "#00ffff";
ctx.fillText(number + "人", 0, 0);
}
// canvas画布可以理解为一张图片
const texture = new THREE.CanvasTexture(canvas);
//注意注意矩形几何体宽高比例和canvas宽高比例一致,以免压缩或拉伸
const plane = new THREE.PlaneGeometry(96, 24);
const planeMaterial = new THREE.MeshBasicMaterial({
map: texture,
side: THREE.DoubleSide,
transparent: true,
});
const planeMesh = new THREE.Mesh(plane, planeMaterial);
planeMesh.position.copy(boxMesh.position)
//向上平移
planeMesh.position.y += 65;
//向前平移
planeMesh.position.z += 25.1;
scene.add(planeMesh)