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;//适当偏移,不与地面重合
相关推荐
格瑞@_@2 天前
11.Three.js使用indexeddb前端缓存模型优化前端加载效率
前端·javascript·缓存·three.js·indexeddb缓存
谢小飞3 天前
我做了三把椅子原来纹理这样加载切换
前端·three.js
小白菜学前端3 天前
ThreeJS创建一个3D物体的基本流程
3d·three.js
茶老翁4 天前
1-初识Three.js
前端·three.js
莫石5 天前
搓绳子(直)
前端·数学·three.js
小白菜学前端6 天前
3d 添加辅助坐标器和轨道控制器
3d·three.js
孙_华鹏8 天前
threejs——实战中材质的应用
前端·three.js·数据可视化
天涯学馆11 天前
Three.js灯光阴影与动画交互
前端·unity3d·three.js
格瑞@_@15 天前
6.Three.js贴图与uv映射(uv坐标)理解和实践
javascript·three.js·贴图·uv
入秋丶24 天前
threejs - 包围盒和包围球
three.js