three.js标签标注、场景信息标注——系统总结,总有一款适合你

three.js标签标注、场景信息标注------系统总结,总有一款适合你

视频总结www.bilibili.com/video/BV1gC...

下面是具体的文字总结

标注技术分类

标注效果分类

CSS2DRenderer渲染HTML元素

HTML元素作为标签使用,标签尺寸不随场景缩放变化

CSS3DRenderer渲染HTML元素

HTML元素作为标签使用,标签尺寸随场景缩放变化

精灵模型Sprite标注

精灵模型可以图片或canvas画布作为纹理,然后标注,可以实现类似CSS3DRenderer渲染HTML元素的效果。

默认区别在于Sprite本质上是threejs模型对象,会被其他模型物体遮挡,但是CSS3标签,本质上是HTML元素,只是叠加到canvas画布上,不是threejs物体的一部分,如果CSS3标签你想隐藏遮挡,需要手动添加代码,通过射线的方式,判断标签是否被其他模型遮挡,然后设置标签的style属性隐藏即可。

图片创建纹理对象,作为精灵Sprite材质的map属性值

canvas画布创建纹理对象,作为精灵Sprite材质的map属性值

2D标注:矩形平面网格模型

地面导航箭头(矩形平面+背景透明的颜色贴图)

地面指南针方向(矩形平面+背景透明的颜色贴图)

地图可视化,地面的波动光圈

3D标注:立体网格模型

智慧城市、地图场景中的热点标注(四棱锥)

火焰特效(序列帧动画或shader)

CSS2DRenderer(HTML元素作为标签)

下面给大家介绍一个threejs的扩展库CSS2DRenderer.js,通过CSS2DRenderer.js可以把HTML元素作为标签标注三维场景。

引入扩展库CSS2DRenderer.js

在threejs文件包目录examples/jsm/renderers/,你可以找到CSS2DRenderer.js扩展库。

threejs扩展库CSS2DRenderer.js提供了两个类CSS2渲染器CSS2DRenderer、CSS2模型对象CSS2DObject

js 复制代码
// 引入CSS2渲染器CSS2DRenderer和CSS2模型对象CSS2DObject
import { CSS2DRenderer,CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
js 复制代码
// 引入CSS2渲染器CSS2DRenderer
import { CSS2DRenderer } from 'three/addons/renderers/CSS2DRenderer.js';
// 引入CSS2模型对象CSS2DObject
import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';

总体思路

本节课先为大家演示标签标注最基本的内容,更多需要完善优化的的细节,可以关注后面几节课讲解。

  • 1.HTML元素创建标签
  • 2.CSS2模型对象CSS2DObject
  • 3.CSS2渲染器CSS2DRenderer
  • 4.CSS2Renderer.domElement重新定位

1. HTML元素创建标签

你可以根据需要,使用HTML、CSS代码创建你想要的标签。如果基于vue或react开发,也可以用vue或react创建的UI组件表示标签。

js 复制代码
<div id="tag">标签内容</div>

如果你想用HTML元素作为标签标注三维场景中模型信息,就需要考虑定位的问题。比如一个模型,在代码中你可以知道它的局部坐标或世界坐标xyz,但是你并不知道渲染后在canvas画布上位置,距离web页面顶部top和左侧的像素px值。

自己写代码把世界坐标xyz,转化为像素px表示屏幕坐标,比较麻烦,不过threejs扩展库CSS2DRenderer.js可以帮助你实现坐标转化,给HTML元素标签定位,下面给大家演示如何实现。

2. CSS2模型对象CSS2DObject

js 复制代码
// 引入CSS2模型对象CSS2DObject
import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';

通过CSS2DObject类,可以把一个HTML元素转化为一个类似threejs网格模型的对象,换句话说就是你可以把CSS2DObject当成threejs的一个模型一样去设置位置.position或添加到场景中。

js 复制代码
const div = document.getElementById('tag');
// HTML元素转化为threejs的CSS2模型对象
const tag = new CSS2DObject(div);

你想把HTML标签标注在那个位置,你通过.position属性设置标签模型对象的xyz坐标。

js 复制代码
tag.position.set(50,0,50);

把HTML元素对应的CSS2模型对象添加到其它模型对象或三维场景中。

js 复制代码
scene.add(tag);
js 复制代码
const group = new THREE.Group();
group.add(tag);

3. CSS2渲染器CSS2DRenderer

js 复制代码
// 引入CSS2渲染器CSS2DRenderer
import { CSS2DRenderer } from 'three/addons/renderers/CSS2DRenderer.js';
js 复制代码
// 创建一个CSS2渲染器CSS2DRenderer
const css2Renderer = new CSS2DRenderer();

CSS2渲染器CSS2DRenderer和WebGL渲染器WebGLRenderer虽然不同,但是有些属性和方法是相似的,可以类比记忆学习。比如.domElement.setSize().render()。可以先参考webgl渲染器写代码,然后再给大家解释其中的含义。

3.1 CSS2Renderer.render()渲染HTML标签

CSS2渲染器CSS2DRenderer和常用的WebGL渲染器WebGLRenderer一样都是渲染器,只是渲染模型对象不同,WebGLRenderer主要是渲染threejs自身的网格、点、线等模型,CSS2DRenderer用来渲染HTML元素标签对应的CSS2模型对象CSS2DObject

js 复制代码
// 用法和webgl渲染器渲染方法类似
css2Renderer.render(scene, camera);
// renderer.render(scene, camera);

3.2 CSS2Renderer.setSize()

设置CSS2Renderer.render()渲染输出标签的尺寸范围,一般和threejs canvas画布宽高度一致即可。

js 复制代码
// width, height:canvas画布宽高度
css2Renderer.setSize(width, height);

3.3 渲染结果CSS2Renderer.domElement

CSS2Renderer.render()渲染会输出标签对应的HTML元素,也就是css2Renderer.domElement,你可以插入到web网页中任何你想放的位置。

js 复制代码
document.body.appendChild(css2Renderer.domElement);

查看css2Renderer.render()渲染结果CSS2Renderer.domElement

threejs执行css2Renderer.render()之后,你打开浏览器控制台元素 选项,找到你创建的HTML标签<div id="tag">标签内容</div>,你可以发现<div id="tag"></div>外面多了一层div父元素,CSS2Renderer.domElement对应的就是<div id="tag"></div>外面的父元素。

js 复制代码
document.body.appendChild(css2Renderer.domElement);
// 渲染HTML标签对应的CSS2DObject模型对象
css2Renderer.render(scene, camera);

外面父元素的宽高度也被CSS2Renderer设置为threejs canvas画布的宽高度,就是css2Renderer.setSize(width, height);设置的结果。

js 复制代码
css2Renderer.setSize(width, height);
html 复制代码
<!-- `<div id="tag"></div>`外面多了一层div父元素 -->
<div style="overflow: hidden; width: 600px; height: 300px;">
</div>

4. CSS2Renderer.domElement重新定位

<div id="tag"></div>外面div父元素重新定位,叠加到canvas画布上,与canvas画布重合即可,你可以可以看到HTML标签的标注效果。

CSS2Renderer.domElement定位方法很多,不过这都是普通前端CSS知识,也不一定要与课程相同,你可以根据你自己的前端CSS知识,自由发挥。你只要能让标签父元素叠加到threejs canvas画布上面且重合就行。

下面是本节课案例中布局方式写法,后面也会给大家演示其它的布局写法。

js 复制代码
css2Renderer.domElement.style.position = 'absolute';
css2Renderer.domElement.style.top = '0px';

你可以测试下面两个div元素的布局规律,会知道为什么设置.style.top = '0px'

js 复制代码
<div style="height: 300px;background: #999;">默认定位元素</div>
<div style="position: absolute;">绝对定位</div>

改变canvas画布在网页的布局位置,标签父元素css2Renderer.domElement也要跟着重新定位

js 复制代码
// 改变canvas画布在网页位置,标签父元素也要重新定位
renderer.domElement.style.marginTop = '200px';
css2Renderer.domElement.style.top = '200px';

css2Renderer.render()渲染本质

<div id="tag"></div>本身也多了一些CSS位置相关属性,这些都是css2Renderer.render()渲染的结果。你也可以发现,你创建的HTML标签<div id="tag"></div>不在原来的位置了,其实是被CSS2Renderer改变了位置。

css2Renderer.render()渲染HTML元素对应的CSS2模型对象,本质上就是根据CSS2模型对象的xyz世界坐标,计算HTML标签元素在canvas画布上的屏幕像素坐标位置。

js 复制代码
const div = document.getElementById('tag');
// HTML元素转化为threejs的CSS2模型对象
const tag = new CSS2DObject(div);
js 复制代码
// 渲染HTML标签对应的CSS2DObject模型对象
css2Renderer.render(scene, camera);

测试

改变模型mesh位置。

js 复制代码
mesh.position.set(100,0,0);

如果你想用HTML元素标注模型,可以把CSS2模型对象也设置在mesh对应的位置。

js 复制代码
tag.position.set(100,0,0);

CSS3DRenderer渲染HTML标签

CSS3渲染器CSS3DRenderer和CSS2渲染器CSS2DRenderer整体使用流程基本相同,只是在HTML标签渲染效果方面不同,比如CSS3渲染的标签会跟着场景相机同步缩放,而CSS2渲染的标签默认保持自身像素值。

下面就在CSS2渲染器代码基础上给大家讲解。

设置CSS3渲染器代码

和CSS2渲染器代码一样设置,只需要把CSS2换成CSS3即可。

JavaScript 复制代码
// 引入CSS3渲染器CSS3DRenderer
import {CSS3DRenderer} from 'three/addons/renderers/CSS3DRenderer.js';
JavaScript 复制代码
// 创建一个CSS3渲染器CSS3DRenderer
const css3Renderer = new CSS3DRenderer();
css3Renderer.setSize(width, height);
// HTML标签<div id="tag"></div>外面父元素叠加到canvas画布上且重合
css3Renderer.domElement.style.position = 'absolute';
css3Renderer.domElement.style.top = '0px';
//设置.pointerEvents=none,解决HTML元素标签对threejs canvas画布鼠标事件的遮挡
css3Renderer.domElement.style.pointerEvents = 'none';
document.body.appendChild(css3Renderer.domElement);
JavaScript 复制代码
// 渲染循环
function render() {
    css3Renderer.render(scene, camera);
    // ...
    requestAnimationFrame(render);
}
JavaScript 复制代码
window.onresize = function () {
    ...
    // HTML标签css3Renderer.domElement尺寸重新设置
    css3Renderer.setSize(width,height);
};

CSS3对象模型CSS3DObject

CSS3对象模型CSS3DObject可以类比前面介绍的CSS2模型对象CSS2DObject学习。

js 复制代码
// 引入CSS3模型对象CSS3DObject
import { CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js';

通过CSS3DObject类,可以把一个HTML元素转化为一个CSS3模型对象,就像threejs的网格模型一样,可以添加到场景中,可以设置位置,可以作为其它模型对象的子对象。

js 复制代码
const div = document.getElementById('tag');
// HTML元素转化为threejs的CSS3模型对象
const tag = new CSS3DObject(div);
//标签tag作为mesh子对象,默认标注在模型局部坐标系坐标原点
mesh.add(tag);
// 相对父对象局部坐标原点偏移80,刚好标注在圆锥
tag.position.y += 80;

tag.position.y += 80;标注圆锥模型的顶部

js 复制代码
const geometry = new THREE.ConeGeometry(25, 80);
geometry.translate(0, 40, 0);
const mesh = new THREE.Mesh(geometry, material);
mesh.add(tag);
// 相对父对象局部坐标原点偏移80,刚好标注在圆锥顶部
tag.position.y += 80;

CSS3DObject渲染效果测试

CSS3模型对象CSS3DObject渲染结果,就像一个矩形平面网格模型一样。你通过相机控件OrbitControls旋转、缩放三维场景,CSS3模型对象CSS3DObject跟着旋转、缩放。

旋转过程中HTML元素标签的正反面都可以看到。

一个网格模型被另一个不透明网格模型遮挡,canvas画布上不会显示,不过注意一点CSS3DObject模型本质上渲染到网页上还是HTML元素,这就是说模型背面的HTML标签并不会被遮挡,CSS3DObject标签是以HTMl元素形式叠加在canvas画布上的,不受threejs内部模型对象影响。

禁止CSS3DObject标签对应HTMl元素背面显示

js 复制代码
<div id="tag" style="backface-visibility: hidden;">标签内容</div>

标签相对标注点的位置

默认情况下CSS3模型对象渲染的标签的几何中心默认和标注位置的坐标重合。

CSS3DRenderer渲染的HTML标签尺寸

CSS2DRenderer渲染HTML元素标签,默认情况下,HTML元素会保持本身尺寸的像素值,除非你通过代码缩放。

CSS3DRenderer渲染的HTML元素,你可以把HTML标签对象想象为一个矩形平面网格模型Mesh,HTML标签对象在threejs中的尺寸来源是HTML元素的像素尺寸值,比如HTML像素高度40px,那么HTML标签对象在threejs中的数字相当于高度为40的矩形平面网格模型。

测试验证上面规律总结:把标签的高度设置为160px,160的一半是80,也就是圆锥的高度,这样HTML标签下半部分和圆锥底部重合。

js 复制代码
<div id="tag" style="height: 160px;">标签内容</div>

border、padding、height、width都会影响标签渲染大小,你可以分别测试体验。

html 复制代码
<style>
    #tag {
        padding: 0px 10px;
        border: #00ffff solid 1px;
        height: 40px;
        border-radius: 5px;
        width: 65px;
    }
</style>

缩放标签

js 复制代码
const div = document.getElementById('tag');
const tag = new CSS3DObject(div);
tag.scale.set(0.5,0.5,1);//缩放标签尺寸

标签偏移

CSS2渲染HTML标签偏移方式

JavaScript 复制代码
const div = document.getElementById('tag');
// id="tag"元素高度322px,默认标签中心与标注点
div.style.top = '-161px'; //平移-161px,指示线端点和标注点重合

CSS2渲染的标签和CSS3渲染的标签偏移方式不同,CSS3标签,直接按照threejs模型尺寸修改方式改变,比用HTML像素方式更方便准确。

js 复制代码
tag.scale.set(0.5,0.5,1);//缩放标签尺寸
tag.position.y += 10;//累加标签高度一半,标签底部和圆锥顶部标注位置重合

CSS3精灵模型CSS3DSprite

js 复制代码
// 引入CSS3精灵模型对象CSS3DSprite
import { CSS3DSprite } from 'three/addons/renderers/CSS3DRenderer.js';

CSS3对象模型CSS3DObject渲染效果类似矩形平面网格模型Mesh

CSS3精灵模型CSS3DSprite渲染效果类似以前学习的精灵模型对象Sprite

js 复制代码
const div = document.getElementById('tag');
// HTML元素转化为threejs的CSS3精灵模型`CSS3DSprite`
const tag = new CSS3DSprite(div);
//标签tag作为mesh子对象,默认标注在模型局部坐标系坐标原点
mesh.add(tag);
// 相对父对象局部坐标原点偏移80,刚好标注在圆锥
tag.position.y += 80;

CSS3精灵模型CSS3DSprite渲染特点

CSS3精灵模型CSS3DSprite对应的HTML标签,可以跟着场景缩放,位置可以跟着场景旋转,但是自身的姿态角度始终平行于canvas画布,不受旋转影响,就像精灵模型一样Sprite

CSS3精灵模型CSS3DSprite尺寸、位置、缩放等渲染规律和CSS3对象模型CSS3DObject基本一致。

标签局部遮挡鼠标事件

HTML标签<div id="tag"></div>外面的父元素css3Renderer.domElement防止鼠标遮挡canvas事件方式,和CSS2渲染器一样。

js 复制代码
//设置.pointerEvents=none,解决HTML元素标签对threejs canvas画布鼠标事件的遮挡
css3Renderer.domElement.style.pointerEvents = 'none';

标签<div id="tag"></div>在CSS3渲染器渲染的时候,默认会被设置为pointer-events: auto;,这时候虽然css3Renderer.domElement不遮挡canvas画布的鼠标事件,但是<div id="tag"></div>遮挡canvas画布的鼠标事件。

这时候你可以通过代码强制改变CSS3渲染器给标签设置的.style.pointerEvents = 'auto',设置为.style.pointerEvents = 'none',这时候注意一点,修改.style.pointerEvents,要在实例化new CSS3DObject(div)之后,因为执行new CSS3DObject(div)的时候,会把HTML标签设置为.style.pointerEvents = 'auto'

js 复制代码
const div = document.getElementById('tag');
// HTML元素转化为threejs的CSS3模型对象
const tag = new CSS3DObject(div);
// new CSS3DObject(div);之后设置style.pointerEvents 
div.style.pointerEvents = 'none';

Sprite作为标签标注设备

实际开发的时候,可以使用精灵模型Sprite + 颜色贴图作为标签,标注三维场景。

下面具体知识点,在精灵模型章节基本都讲解过,学习下面内容之前,你可以尝试用精灵模型去标注工厂设备。

精灵模型标签

如果你想想用精灵模型表达什么含义,可以美术提供一个对应的贴图。

JavaScript 复制代码
const texLoader= new THREE.TextureLoader();
const texture = texLoader.load("./警告.png");
const spriteMaterial = new THREE.SpriteMaterial({
  map: texture,
});
const sprite = new THREE.Sprite(spriteMaterial);

可以根据标注的场景尺寸量级,设置精灵模型大小,不要过大或过小,先大概标注,比如精灵标签比设备尺寸小一个数量级,然后再精确调整。

JavaScript 复制代码
sprite.scale.set(5, 5, 1);
sprite.position.y = 5 / 2; //标签底部箭头和空对象标注点重合  

标注工厂设备

在工厂三维模型需要标注的位置,设置一个空对象,用来控制精灵模型标签的位置。

JavaScript 复制代码
// obj是建模软件中创建的一个空对象
const obj = gltf.scene.getObjectByName('设备A标注');
//tag会标注在空对象obj对应的位置
obj.add(sprite);

精灵模型底部和标注位置重合

设置精灵模型位置属性,使精灵标签底部和空对象标注位置重合。

JavaScript 复制代码
sprite.scale.set(4, 4, 1);
//标签底部箭头和空对象标注点重合  
sprite.position.y = 4/2;

精灵模型Sprite和CSS3精灵模型CSS3DSprite标签差异

精灵模型渲染Sprite的标签,默认可以被其他网格模型遮挡,但是CSS3渲染器渲染的HTML元素标签是叠加在canvas画布上,不会被其它网格模型遮挡。

标注多个设备状态

封装一个创建精灵标签的函数,可以根据需要调用,标注任何设备。

JavaScript 复制代码
import * as THREE from 'three';
// 标注位置对应的模型对象obj
function createSprite(obj,state) {
    const texLoader= new THREE.TextureLoader();
    let texture = null;
    if(state == '警告'){
        texture= texLoader.load("./警告.png");
    }else{
        texture = texLoader.load("./故障.png");
    }
    const spriteMaterial = new THREE.SpriteMaterial({
        map: texture,
    });
    const sprite = new THREE.Sprite(spriteMaterial);
    // 控制精灵大小
    sprite.scale.set(5, 5, 1);
    sprite.position.y = 5 / 2; //标签底部箭头和空对象标注点重合  
    obj.add(sprite); //tag会标注在空对象obj对应的位置
}

export default createSprite;

Sprite标签(Canvas作为贴图)

上节课案例创建标签的方式,是把一张图片作为Sprite精灵模型的颜色贴图,本节给大家演示把Canvas画布作为Sprite精灵模型的颜色贴图,实现一个标签。

注意:本节课主要是技术方案讲解,默认你有Canvas基础,如果没有Canvas基础,可以学习之后再来学习本节课内容。

Canvas画布绘制一个标签

你可以使用Canvas绘制特定轮廓的标签,比如加上指引线或箭头,可以输入特定文字。

下面代码自动适配了不同长度的文字标注,文字符号越多,canvas画布越长。

JavaScript 复制代码
// 生成一个canvas对象,标注文字为参数name
function createCanvas(name) {
    /**
     * 创建一个canvas对象,绘制几何图案或添加文字
     */
    const canvas = document.createElement("canvas");
    const arr = name.split(""); //分割为单独字符串
    let num = 0;
    const reg = /[\u4e00-\u9fa5]/;
    for (let i = 0; i < arr.length; i++) {
        if (reg.test(arr[i])) { //判断是不是汉字
            num += 1;
        } else {
            num += 0.5; //英文字母或数字累加0.5
        }
    }
    // 根据字符串符号类型和数量、文字font-size大小来设置canvas画布宽高度
    const h = 80; //根据渲染像素大小设置,过大性能差,过小不清晰
    const w = h + num * 32;
    canvas.width = w;
    canvas.height = h;
    const h1 = h * 0.8;
    const c = canvas.getContext('2d');
    // 定义轮廓颜色,黑色半透明
    c.fillStyle = "rgba(0,0,0,0.5)";
    // 绘制半圆+矩形轮廓
    const R = h1 / 2;
    c.arc(R, R, R, -Math.PI / 2, Math.PI / 2, true); //顺时针半圆
    c.arc(w - R, R, R, Math.PI / 2, -Math.PI / 2, true); //顺时针半圆
    c.fill();
    // 绘制箭头
    c.beginPath();
    const h2 = h - h1;
    c.moveTo(w / 2 - h2 * 0.6, h1);
    c.lineTo(w / 2 + h2 * 0.6, h1);
    c.lineTo(w / 2, h);
    c.fill();
    // 文字
    c.beginPath();
    c.translate(w / 2, h1 / 2);
    c.fillStyle = "#ffffff"; //文本填充颜色
    c.font = "normal 32px 宋体"; //字体样式设置
    c.textBaseline = "middle"; //文本与fillText定义的纵坐标
    c.textAlign = "center"; //文本居中(以fillText定义的横坐标)
    c.fillText(name, 0, 0);
    return canvas;
}
const canvas = createCanvas('设备A')

CanvasTexture把canvas转化为纹理对象

canvas画布作为CanvasTexture的参数创建一个纹理对象,本质上你可以理解为CanvasTexture把canvas画布当做图片,读取参数canvas画布上的像素值,创建纹理贴图Texture

JavaScript 复制代码
loader.load("../工厂.glb", function (gltf) {
  model.add(gltf.scene);
  const canvas = createCanvas('设备A');//创建一个canvas画布
  // canvas画布作为CanvasTexture的参数创建一个纹理对象
  // 本质上你可以理解为CanvasTexture读取参数canvas画布上的像素值
  const texture = new THREE.CanvasTexture(canvas);
  const spriteMaterial = new THREE.SpriteMaterial({
    map: texture,
  });
  const sprite = new THREE.Sprite(spriteMaterial);
})

精灵模型尺寸和位置设置

精灵模型尺寸和位置设置具体思路可以参考上节课讲解。

注意精灵模型宽高比和canvas画布宽高比保持一致即可。

JavaScript 复制代码
const y = 4;//精灵y方向尺寸
// sprite宽高比和canvas画布保持一致
const x = canvas.width/canvas.height*y;//精灵x方向尺寸
sprite.scale.set(x, y, 1);// 控制精灵大小
sprite.position.y = y / 2; //标签底部箭头和空对象标注点重合  
const obj = gltf.scene.getObjectByName('设备A标注'); // obj是建模软件中创建的一个空对象
obj.add(sprite); //tag会标注在空对象obj对应的位置

cavnas精灵标签封装(标注多个)

封装一个创建cavnas精灵标签的函数,可以根据需要调用,标注任何需要标注的地方。

JavaScript 复制代码
import * as THREE from 'three';
import createCanvas from './canvas';
// 标注位置对应的模型对象obj
// name:标注文字
function createSprite(obj,name) {
    const canvas = createCanvas(name);//创建一个canvas画布
    // canvas画布作为CanvasTexture的参数创建一个纹理对象
    const texture = new THREE.CanvasTexture(canvas);
    const spriteMaterial = new THREE.SpriteMaterial({
      map: texture,
    });
    const sprite = new THREE.Sprite(spriteMaterial);
    // 控制精灵大小(sprite宽高比和canvas画布保持一致)
    const s = 0.05;//通过canvas宽高度缩放后,设置sprite.scale,避免图文宽高比变形
    const x = canvas.width*s;
    const y = canvas.height*s;
    sprite.scale.set(x, y, 1);
    sprite.position.y = y / 2; //标签底部箭头和空对象标注点重合  
    obj.add(sprite); //tag会标注在空对象obj对应的位置
}

export default createSprite;

Canvas包含外部图片

如果Canvas包含外部图片作为背景,注意创建CanvasTexture的时候,不管你的代码结构怎么组织,主要要等图像加载完成再执行THREE.CanvasTexture(canvas),如果还未加载完成,创建纹理时候,读取画布像素时候,会不包含图片。

JavaScript 复制代码
// 生成一个canvas对象,标注文字为参数name
function createCanvas(img,name) {
    /**
     * 创建一个canvas对象,绘制几何图案或添加文字
     */
    const canvas = document.createElement("canvas");
    const w = 140; //根据渲染像素大小设置,过大性能差,过小不清晰
    const h = 80;
    canvas.width = w;
    canvas.height = h;
    const h1 = h * 0.8;
    const c = canvas.getContext('2d');
    c.fillStyle = "rgba(0,0,0,0.0)"; //背景透明
    c.fillRect(0, 0, w, h);
    c.drawImage(img, 0, 0, w, h);//图片绘制到canvas画布上
    // 文字
    c.beginPath();
    c.translate(w / 2, h1 / 2);
    c.fillStyle = "#ffffff"; //文本填充颜色
    c.font = "normal 32px 宋体"; //字体样式设置
    c.textBaseline = "middle"; //文本与fillText定义的纵坐标
    c.textAlign = "center"; //文本居中(以fillText定义的横坐标)
    c.fillText(name, 0, 0);
    return canvas;
}
JavaScript 复制代码
  const img = new Image();
  img.src = "./标签箭头背景.png";
  img.onload = function () {
    const canvas = createCanvas(img,'设备A');//创建一个canvas画布
    // 图片加载完成后,读取canvas像素数据创建CanvasTexture
    const texture = new THREE.CanvasTexture(canvas);
    ...
    const sprite = new THREE.Sprite(spriteMaterial);
    ...
  }

矩形Mesh+背景透明png贴图(场景标注)

three.js项目开发中,把一个背景透明的.png图像作为平面矩形网格模型Mesh的颜色贴图是一个非常有用的功能,通过这样一个功能,可以对three.js三维场景进行标注。

整体思路:创建一个矩形平面,设置颜色贴图.map,注意选择背景透明的.png图像作为颜色贴图,同时材质设置transparent: true,这样png图片背景完全透明的部分不显示。

javascript 复制代码
// 矩形平面网格模型设置背景透明的png贴图
const geometry = new THREE.PlaneGeometry(60, 60); //默认在XOY平面上
const textureLoader = new THREE.TextureLoader();
const material = new THREE.MeshBasicMaterial({
    map: textureLoader.load('./指南针.png'),        
    transparent: true, //使用背景透明的png贴图,注意开启透明计算
});
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(-Math.PI / 2);

网格地面辅助观察GridHelper

javascript 复制代码
// 添加一个辅助网格地面
const gridHelper = new THREE.GridHelper(300, 25, 0x004444, 0x004444);

矩形平面PlaneGeometry设置颜色贴图

javascript 复制代码
const geometry = new THREE.PlaneGeometry(60, 60);
const textureLoader = new THREE.TextureLoader();
const material = new THREE.MeshBasicMaterial({
    map: textureLoader.load('./指南针.png'),
});
const mesh = new THREE.Mesh(geometry, material);

开启透明transparent: true

javascript 复制代码
const material = new THREE.MeshBasicMaterial({
    map: textureLoader.load('./指南针.png'),   
    //transparent: true:使用背景透明的png贴图,注意允许透明   
    transparent: true, 
});

旋转平移矩形平面

PlaneGeometry矩形平面默认是在XOY平面上,如果你想平行于XOZ平面,就需要手动旋转。

javascript 复制代码
mesh.rotateX(-Math.PI/2);//平行地面:矩形Mesh默认单面可见,注意旋转-Math.PI / 2

如果你不想矩形平面Mesh与地面网格线重合,可以通过位置属性.position偏移。

javascript 复制代码
mesh.position.y = 1;//适当偏移,不与地面重合
相关推荐
答案—answer2 天前
开源项目:Three.js3D模型可视化编辑系统
javascript·3d·开源·开源项目·three.js·three.js编辑器
贝格前端工场2 天前
困在像素里:我的可视化大屏项目与前端价值觉醒
前端·three.js
全栈王校长3 天前
Three.js 材质进阶
webgl·three.js
全栈王校长3 天前
Three.js Geometry进阶
webgl·three.js
烛阴4 天前
3D字体TextGeometry
前端·webgl·three.js
全栈王校长4 天前
Three.js 开发快速入门
three.js
全栈王校长4 天前
Three.js 环境搭建与开发初识
three.js
DaMu4 天前
Dreamcore3D ARPG IDE “手搓”游戏引擎,轻量级实时3D创作工具,丝滑操作,即使小白也能轻松愉快的创作出属于你自己的游戏世界!
前端·架构·three.js
烛阴6 天前
从“无”到“有”:手动实现一个 3D 渲染循环全过程
前端·webgl·three.js
烛阴7 天前
拒绝配置地狱!5 分钟搭建 Three.js + Parcel 完美开发环境
前端·webgl·three.js