1. 3D 标注
除了 CSS2DRender 和 CSS3DRender,最常用的标注方式还有 CanvasTexture 。
1.1. CSS2DRender、 CSS3DRender 和 CanvasTexture 区别
CSS2DRender:尺寸固定,正面永远朝向用户,适合复杂的场景,需写 html,代码分散。
CSS3DRender: 真正的 3D 标注,将 html 内容转换为 3D 对象并插入到场景中,需写 html,代码分散。
CanvasTexture: 也可以实现 CSS2DRender 和 CSS3DRender 的效果,SS2DRender 使用 CanvasTexture + Sprite;CSS3DRender 使用 CanvasTexture + Mesh。由于使用了 canvas 作为纹理贴图,只能绘制简单的样式,好处是逻辑代码集中,好维护。
1.2. CanvasTexture + Sprite
import * as THREE from "three";
export default class TextVideo {
constructor(
scene,
text = "helloworld",
position = new THREE.Vector3(0, 0, 0),
euler = new THREE.Euler(0, 0, 0)
) {
this.text = text;
// 创建canvas对象
const canvas = document.createElement("canvas");
this.canvas = canvas;
canvas.width = 1024;
canvas.height = 1024;
const video = document.createElement("video");
this.video = video;
video.src = "./video/chatFrame.mp4";
// 如果想要视频能够自动播放,那么就设置为静音
video.muted = true;
video.loop = true;
video.play();
const context = canvas.getContext("2d");
this.context = context;
this.texture = new THREE.CanvasTexture(canvas);
const planeGeometry = new THREE.PlaneGeometry(2, 2, 1, 1);
// this.planeMaterial = new THREE.MeshBasicMaterial({
// map: this.texture,
// alphaMap: this.texture,
// color: 0xffffff,
// side: THREE.DoubleSide,
// transparent: true,
// blending: THREE.AdditiveBlending,
// depthWrite: false,
// });
this.planeMaterial = new THREE.SpriteMaterial({
map: this.texture,
alphaMap: this.texture,
color: 0xffffff,
side: THREE.DoubleSide,
transparent: true,
blending: THREE.AdditiveBlending,
depthTest: true,
depthWrite: true,
});
this.mesh = new THREE.Sprite(this.planeMaterial);
this.mesh.scale.set(5, 5, 1);
// this.mesh = new THREE.Mesh(planeGeometry, this.planeMaterial);
this.mesh.position.copy(position);
this.mesh.rotation.copy(euler);
scene.add(this.mesh);
}
drawVideoText(text) {
let context = this.context;
context.clearRect(0, 0, this.canvas.width, this.canvas.height);
context.drawImage(this.video, 0, 0, 1024, 1024);
context.textAlign = "center";
context.textBaseline = "middle";
context.font = "bold 100px Arial";
context.fillStyle = "rgba(0,255,255,1)";
context.fillText(text, this.canvas.width / 2, this.canvas.height / 2);
this.texture.needsUpdate = true;
this.planeMaterial.needsUpdate = true;
}
update(deltaTime) {
this.drawVideoText(this.text);
}
}
1.3. CanvasTexture + Mesh
import * as THREE from "three";
export default class TextVideo {
constructor(
scene,
text = "helloworld",
position = new THREE.Vector3(0, 0, 0),
euler = new THREE.Euler(0, 0, 0)
) {
this.text = text;
// 创建canvas对象
const canvas = document.createElement("canvas");
this.canvas = canvas;
canvas.width = 1024;
canvas.height = 1024;
const video = document.createElement("video");
this.video = video;
video.src = "./video/chatFrame.mp4";
// 如果想要视频能够自动播放,那么就设置为静音
video.muted = true;
video.loop = true;
video.play();
const context = canvas.getContext("2d");
this.context = context;
this.texture = new THREE.CanvasTexture(canvas);
const planeGeometry = new THREE.PlaneGeometry(2, 2, 1, 1);
this.planeMaterial = new THREE.MeshBasicMaterial({
map: this.texture,
alphaMap: this.texture,
color: 0xffffff,
side: THREE.DoubleSide,
transparent: true,
blending: THREE.AdditiveBlending,
depthWrite: false,
});
this.mesh = new THREE.Mesh(planeGeometry, this.planeMaterial);
this.mesh.position.copy(position);
this.mesh.rotation.copy(euler);
scene.add(this.mesh);
}
drawVideoText(text) {
let context = this.context;
context.clearRect(0, 0, this.canvas.width, this.canvas.height);
context.drawImage(this.video, 0, 0, 1024, 1024);
context.textAlign = "center";
context.textBaseline = "middle";
context.font = "bold 100px Arial";
context.fillStyle = "rgba(0,255,255,1)";
context.fillText(text, this.canvas.width / 2, this.canvas.height / 2);
this.texture.needsUpdate = true;
this.planeMaterial.needsUpdate = true;
}
update(deltaTime) {
this.drawVideoText(this.text);
}
}