【Threejs进阶教程-效果篇】1.Threejs文字与css2d/css3d技术

Threejs文字与css2d/css3d技术

  • 学习ThreeJS的捷径
  • 学习之前先搞清楚自己想要什么样的效果
  • 贴图文字
    • 准备一张带文字的png贴图
    • 使用sprite来进行贴图实现2D始终面朝相机的文字
    • 使用planeGeometry来贴图实现3D文字
    • 使用planeGeometry来贴图实现伪3D文字
    • 动态贴图文字
      • html2Canvas
  • 文字几何体(半数以上的新人都会踩一遍文字几何体的坑)
    • 认识3D几何体以及新人误区
    • 字体JSON如何获取
    • 创建文字几何体
  • css2d/css3d技术
    • 理解什么是css2d/3d
    • css2d的使用
    • css2d 事件
    • css2D/3D制作各种文字效果
    • css2d/3d需要注意的点

学习ThreeJS的捷径

本段内容会写在0篇以外所有的,本人所编写的Threejs教程中

对,学习ThreeJS有捷径
当你有哪个函数不懂的时候,第一时间去翻一翻文档
当你有哪个效果不会做的时候,第一时间去翻一翻所有的案例,也许就能找到你想要的效果
最重要的一点,就是,绝对不要怕问问题,越怕找找别人问题,你的问题就会被拖的越久

如果你确定要走WebGL/ThreeJS的开发者路线的话,以下行为可以让你更快的学习ThreeJS

  1. 没事就把所有的文档翻一遍,哪怕看不懂,也要留个印象,至少要知道Threejs有什么
  2. 没事多看看案例效果,当你记忆的案例效果足够多时,下次再遇到相似问题时,你就有可能第一时间来找对应的案例,能更快解决你自己的问题
  3. 上述案例不只是官网的案例,郭隆邦技术博客,跃焱邵隼,暮志未晚等站点均有不少优质案例,记得一并收藏
    http://www.yanhuangxueyuan.com/ 郭隆邦技术博客
    https://www.wellyyss.cn/ 跃焱邵隼
    http://www.wjceo.com/ 暮志未晚(暮老的站点暂时挂了,请查阅他之前的threejs相关文档)
    暮老的csdn首页
    这三个站点是我最常逛的站点,推荐各位有事没事逛一下,看看他们的案例和写法思路,绝对没坏处

学习之前先搞清楚自己想要什么样的效果

threejs有多种添加文字的方式

  1. 添加带文字的贴图到物体上
  2. 文字几何体
  3. css2d和css3d技术

threejs中,有N种文字的效果
最常见的,2D文字,这种文字会始终面向你,无论你怎么看,文字都是正着的,这种文字一般是2D文字,实现思路是上面的,1和2

伪3D文字,这里只讲一种,在你平视它的时候,它是不变形的,但是当你抬高了视角后,在看向文字,则会有3D效果,实现方式有1和2

3D文字,会根据你视角旋转,改变形态的文字,实现方式有1,2,3

我们下面按照贴图法,css2d/3d法,和文字几何体法三种方式来介绍如何加载不同种类的文字

贴图文字

准备一张带文字的png贴图

在这里插入图片描述

使用sprite来进行贴图实现2D始终面朝相机的文字

在这里插入图片描述

        let loader = new THREE.TextureLoader();loader.load('./文字贴图.png',texture=>{let material = new THREE.SpriteMaterial({map:texture,transparent:true,//使用png贴图就习惯性的设置透明为开//设置sizeAttenuation = false后,sprite的大小不会因为视角拉进拉远而改变//但是对位移还有效//sizeAttenuation:false});let sprite = new THREE.Sprite(material);scene.add(sprite);})

精灵方面的内容,在【ThreeJS基础教程-点线精灵篇】4.1 Sprite精灵 已介绍完毕,这里不做过多介绍

上面代码纯属是基本功,打好基础的都能看懂,我就不多介绍了

使用planeGeometry来贴图实现3D文字

        let loader = new THREE.TextureLoader();loader.load('./文字贴图.png',texture=>{let geometry = new THREE.PlaneGeometry(10,10);let material = new THREE.MeshBasicMaterial({map:texture,transparent:true,side:THREE.DoubleSide,//如果你希望两面都能看到,设置这个即可});let mesh = new THREE.Mesh(geometry,material);scene.add(mesh);})

在这里插入图片描述

又是个超级简单,不需要多讲的代码

使用planeGeometry来贴图实现伪3D文字

        let loader = new THREE.TextureLoader();loader.load('./文字贴图.png',texture=>{let geometry = new THREE.PlaneGeometry(10,10);let material = new THREE.MeshBasicMaterial({map:texture,transparent:true,side:THREE.DoubleSide,//如果你希望两面都能看到,设置这个即可});let mesh = new THREE.Mesh(geometry,material);//mesh.onBeforeRender会跟随renderer.render(scene,camera) 执行mesh.onBeforeRender = ()=>{let px = camera.position.x;//获取相机的x位置let pz = camera.position.z;//获取相机的z位置mesh.lookAt(px,0,pz);//观察相机所在位置且高度为0的点}scene.add(mesh);})

在这里插入图片描述

在上面的基础上,让物体始终观察一个方向即可,可以看出,这样的文字,在你相机正视它的时候,它是完整的,但是你俯视它的时候,就会有3D感,这种文字我称它为“伪3D文字”

实现方式很简单,首先设置物体的onBeforeRender函数,这个函数,会跟随 renderer.render() 来执行,且在渲染前执行,所以我们用它来监控相机,每渲染一阵,让其观察一次相机,但是不是像sprite一样观察相机,我们只需要以相机位置,创建一个与mesh等高的点即可,这样即可保证相机无论哪个方向,从正面看,都是完整的文字

伪3D文字有很多种,这里仅讲这一种,本质上伪3D文字,就是在控制在不同视角下,文字的渲染效果

动态贴图文字

动态贴图文字的本质,是 canvasTexture + canvas绘制来实现的

我们以上面用planeGeometry的3D文字举例

//创建canvaslet canvas = document.createElement('canvas');//canvasTexture使用的<canvas>的宽高,尽量一致,且宽高取值为2的n次幂canvas.style.width = "512px";canvas.style.height = "512px";let ctx = canvas.getContext('2d');ctx.fillStyle = "rgb(111,189,255)";//设定填充颜色ctx.font = "bolder 24px arial";//设定字体ctx.fillText("示例CanvasTexture文字",24,24); //在画布的24,24的位置添加文字ctx.globalAlpha = 0;//设定背景透明//创建画布贴图let canvasTexture = new THREE.Texture(canvas);canvasTexture.needsUpdate = true;//上面创建的canvas每更新一次,贴图更新一次let geometry = new THREE.PlaneGeometry(10,10);let material = new THREE.MeshBasicMaterial({map:canvasTexture,transparent:true});let mesh = new THREE.Mesh(geometry,material);scene.add(mesh);

在这里插入图片描述

创建过程看注释吧

关于canvas绘图技术,请自行百度

注意:只要是个< canvas > 都可以用到CanvasTexture上,比如说:Renderer.domElement,本质上就是一个< canvas>,pixijs,konvajs等一众2D框架,也具有一个< canvas>,当你想做复杂的2D效果时,可以不必拘泥于 < canvas>画图技术,可以去考虑一下WebG2D框架,是否能够满足你的需要

html2Canvas

html2Canvas文档

插播一条小科普,这个工具名称中的2,不能读成中文的二,应该读成英文单词 to,本质上这个工具的名称,应该叫: html to canvas,为了方便简写,所以省下to写成2
没用的知识+1

这个技术可以把dom转换为一个< canvas>,所以也可以通过这个,把dom做成贴图贴给CanvasTexture,但是请注意,这个转换需要很长的时间,太复杂的dom可能不适用,演示效果与上面的canvasTexture基本一致,本质上还是生成贴图 => 使用贴图的过程

文字几何体(半数以上的新人都会踩一遍文字几何体的坑)

认识3D几何体以及新人误区

在这里插入图片描述
一进入文档,我们就应该看清楚上面的继承关系

在这里插入图片描述
文字几何体,本质上是挤压几何体ExtrudeGeometry

挤压几何体的基础,又是shape
在这里插入图片描述

所以,本质上,文字几何体,就是,从字体文件转换过来的,系统绘制文字时使用的顶点,绘制的Shape,然后生成ExtrudeGeometry

既然是几何体,那么一定要考虑几何体的点线面问题,如果你的文字非常多,那用文字几何体等于作死。。。

本人曾经也作过这个死,生成的文字几何体json高达上百M,然后就加载转换后的json就得消耗巨量的性能,加上用了几百个文字去生成文字几何体。。。结果是懂得都懂

第一大坑,文字几何体会大量占用你的点线面,尤其是中文,尤其是那些高清字体

文字几何体,仅适用于,你的场景需要添加文字模型时使用

字体JSON如何获取

facetype
将任意ttf丢入到这里就可以生成字体json

这里是第二大坑!中文字体包转换出来的json,文件巨大,非常不实用,笔者曾经转换过来的最小的字体json都得20M左右

解决中文字体大的方法也有,从 TTF格式入手,TTF的字体文件大小减小,就可以解决此问题

这个问题是个偏传统前端的问题,使用字蛛(font-spider),然后把你需要的文字,用字蛛筛选出来,导出一个干净的TTF,这样转换的字体JSON会小很多

创建文字几何体

步骤如下:

  1. 引入字体json包
  2. 引入FontLoader和TextGeometry
  3. 创建文字几何体

这里我们使用threejs开发包中的字体文件,路径和文件名如下
examples/fonts/gentilis_bold.typeface.json

import {FontLoader} from "../three/examples/jsm/loaders/FontLoader.js";import {TextGeometry} from "../three/examples/jsm/geometries/TextGeometry.js"function addMesh() {let fontLoader = new FontLoader();fontLoader.load('./gentilis_bold.typeface.json',font=>{const geometry = new TextGeometry( 'Hello three.js!', {font: font,//字体size: 80,//几何体大小depth: 5,//几何体挤出深度curveSegments: 12,//曲线上的分段数,分段数越高,字体越圆滑,但是占用点线面越多bevelEnabled: true,//挤出圆角bevelThickness: 10,//圆角厚度bevelSize: 8,//圆角宽度bevelSegments: 5//圆角分段数,分段数越高,字体越圆滑,但是占用点线面越多} );let material = new THREE.MeshStandardMaterial({color:0xffffff * Math.random(),//随机色});let mesh = new THREE.Mesh(geometry,material);scene.add(mesh);})}

在这里插入图片描述
可以看得出,文字几何体创建出来的文字是3D文字模型,而且3D感极强

css2d/css3d技术

这两个技术本质上是同一个技术

理解什么是css2d/3d

css2d,看名字就知道,和css有关系,css2d本质上是使用了,css技术中的translate样式,threejs借助视角切换,来更新dom的translate值,实现< div >位置的改变

所以,css2d,本质上就是< div> 使用了3D坐标的 css技术

css2d的使用

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>*{margin: 0;padding: 0;border: 0;}body{width:100vw;height: 100vh;overflow: hidden;}</style>
</head>
<body><!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script><script type="importmap">{"imports": {"three": "../three/build/three.module.js","three/addons/": "../three/examples/jsm/"}}</script><script type="module">import * as THREE from "../three/build/three.module.js";import {OrbitControls} from "../three/examples/jsm/controls/OrbitControls.js";//显式引入css2dRenderer和css2dObjectimport {CSS2DRenderer,CSS2DObject} from "../three/examples/jsm/renderers/CSS2DRenderer.js";window.addEventListener('load',e=>{init();addMesh();render();})let scene,renderer,camera;let orbit;//1 创建全局的css2d渲染器let csS2DRenderer;function init(){scene = new THREE.Scene();renderer = new THREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(renderer.domElement);//2.和renderer一样需要设置大小,同时还要调整<div>样式csS2DRenderer = new CSS2DRenderer();csS2DRenderer.setSize(window.innerWidth,window.innerHeight)csS2DRenderer.domElement.style.position = "absolute";//绝对定位和fixed定位都可csS2DRenderer.domElement.style.left = 0;csS2DRenderer.domElement.style.top = 0;//保证css2d要完美覆盖<canvas>csS2DRenderer.domElement.style.zIndex = 1;//比<canvas>高即可csS2DRenderer.domElement.style.pointerEvents = "none";//设置无事件,以防遮挡画布上的事件document.body.appendChild(csS2DRenderer.domElement);// 别忘了添加到<body>或者你选择的容器中//还没结束,还有两步走camera = new THREE.PerspectiveCamera(50,window.innerWidth/window.innerHeight,0.1,2000);camera.add(new THREE.PointLight());camera.position.set(10,10,10);scene.add(camera);orbit = new OrbitControls(camera,renderer.domElement);orbit.enableDamping = true;scene.add(new THREE.GridHelper(10,10));}function addMesh() {//3.添加css2d物体//3.1 创建css2d物体需要一个domlet div = document.createElement('div');div.style.cssText = `width:200px;height:200px;border:1px solid #ffffff;color:#ffffff;`;div.innerText = "测试css2d文字";//3.2 创建css2dObjectlet csS2DObject = new CSS2DObject(div);scene.add(csS2DObject);}function render() {renderer.render(scene,camera);//4. 更新css2d绑定的<div>csS2DRenderer.render(scene,camera);orbit.update();requestAnimationFrame(render);}</script>
</body>
</html>

在这里插入图片描述

创建过程:
0. 显示引入css2dObject和css3dObject

  1. 创建全局的css2DRenderer
  2. 配置css2dRenderer
  3. 创建css2dObject
  4. 渲染和更新css2dRenderer

不少人第一次入坑的时候,都是在抄官方的demo,但是总有抄漏的,如果遇到css2d无效的,可以参考本人这里写的四步走来排查问题

css2d 事件

    function addMesh() {//3.添加css2d物体//3.1 创建css2d物体需要一个domlet div = document.createElement('div');div.style.cssText = `width:200px;height:200px;border:1px solid #ffffff;color:#ffffff;pointer-events:auto`;div.innerText = "测试css2d文字";div.addEventListener('click',e=>{alert('1');})//3.2 创建css2dObjectlet csS2DObject = new CSS2DObject(div);scene.add(csS2DObject);}

这里是css的知识了

父级如果携带了 pointer-events: none; 的样式,则所有子项都会继承,所以单独给需要开事件的子项开pointer-events: auto,先允许它接收事件
然后,按照我们传统的,onclick,addEventListener都可以添加事件上去,尽量用addEventListener

css2D/3D制作各种文字效果

这里仅做介绍,有兴趣的自己去了解即可,css3d和css2d使用上几乎没有区别

如果你想做3D文字,请使用css3DRenderer和css3DObject
如果你想做2D且跟随拉进拉远会变大变小,请使用css3DRenderer和css3dSprite
如果你想做2D仅跟随旋转改变位置但是不改变大小,请使用css2dRenderer和css2dObject

如果你想做伪3D文字,如上面那种,也可以用css3Dobject,然后一样的设置即可

css2d/3d需要注意的点

  1. 创建的dom,宽高值是以屏幕为例的,如果你的场景,非常小,比如说场景长宽高就10的单位,那么你创建出来的css2d会十分巨大,反之,如果场景非常小,那么你创建出来的css2d,会十分渺小,酌情选择是否需要你的dom是否要跟随变化
  2. css2d/css3d,只要你按照上面的方式设置了,那它必定在屏幕最前,一定会遮挡模型,这个是个无解问题,如果你一定需要面板与模型有正确的遮挡关系,请选择上面的动态贴图文字
  3. css2d/css3d同样与vue相性很差,这个如果你们感兴趣可以自行研究

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/797864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

操作系统复习

虚拟内存 内存(memory)资源永远都是稀缺的&#xff0c;当越来越多的进程需要越来越来内存时&#xff0c;某些进程会因为得不到内存而无法运行&#xff1b; 虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存&#xff0c;而实际上&#xff0…

HTML基础知识详解(下)(如果想知道html的全部基础知识点,那么只看这一篇就足够了!)

前言&#xff1a;在上一篇文章中&#xff0c;我们已经学习完了超链接标签、列表标签和表格标签&#xff0c;但是我们还有一些标签没有学习&#xff0c;在这篇文章中&#xff0c;我们将学习剩余的标签。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页…

JAVA并发编程(一)

JAVA并发编程&#xff08;一&#xff09; 1.1JAVA线程API 1.1.1currentThread package com.lisus2000.thread;/** * 当前线程 * */ public class Test07 extends Thread {public Test07() {System.out.println("new Test07()......" Thread.currentThread().getNa…

vivado中移位寄存器的优化(二)

移位寄存器优化用于改善移位寄存器单元&#xff08;SRLs&#xff09;与其他逻辑单元之间的负裕量路径的时序。如果存在对移位寄存器单元&#xff08;SRL16E或SRLC32E&#xff09;的时序违规&#xff0c;优化会从SRL寄存器链的开始或结束位置提取一个寄存器&#xff0c;并将其放…

深入理解数据结构第三弹——二叉树(3)——二叉树的基本结构与操作

二叉树&#xff08;1&#xff09;&#xff1a;深入理解数据结构第一弹——二叉树&#xff08;1&#xff09;——堆-CSDN博客 二叉树&#xff08;2&#xff09;&#xff1a;深入理解数据结构第二弹——二叉树&#xff08;2&#xff09;——堆排序及其时间复杂度-CSDN博客 前言…

面试:HashMap

目录 1、底层数据结构&#xff0c;1.7 与1.8有何不同? 2、为何要用红黑树&#xff0c;为何一上来不树化&#xff0c;树化阈值为何是8&#xff0c;何时会树化&#xff0c;何时会退化为链表? 3、索引如何计算? hashCode都有了&#xff0c;为何还要提供hash()方法?数组容量为…

【Easy云盘 | 第十二篇】分享模块(获取分享信息、校验分享码、获取文件列表)

文章目录 4.4.4获取分享信息4.4.5校验分享码4.4.6获取文件列表 4.4.4获取分享信息 明天做 4.4.5校验分享码 明天做 4.4.6获取文件列表 明天做

Vue3大事件项目1 登录注册

创建项目 引入 element-ui 组件库 登录&#xff1a;注册样式准备之后&#xff0c;配置校验规则&#xff08;4个条件&#xff1a;一数据、二规则&#xff09; 1. 校验相关 (1) 给当前表单绑上整个的数据对象&#xff1a;el-form > :model"ruleForm" 绑…

云服务器是不是云盘?

​  云服务器是不是云盘?云服务器和云盘是两个不同的概念&#xff0c;尽管它们都是云计算服务的一部分。云服务器是一种提供计算能力的服务&#xff0c;可以运行各种应用程序和服务&#xff0c;而云盘则是一种提供数据存储和共享服务的工具。 具体来说&#xff1a; 云服务器…

【Qt】事件

目录 一、介绍 二、进入离开事件 三、鼠标事件 3.1 鼠标单击事件 3.2 鼠标释放事件 3.3 鼠标双击事件 3.4 鼠标移动事件 3.5 滚轮事件 四、按键事件 4.1 单个按键 4.2 组合按键 五、定时器 5.1 QTimerEvent类 5.2 QTimer类 5.3 获取系统日期及时间 六、窗口移…

蓝桥杯刷题 前缀和与差分-[NewOJ P1819]推箱子(C++)

题目描述 在一个高度为H的箱子前方&#xff0c;有一个长和高为N的障碍物。 障碍物的每一列存在一个连续的缺口&#xff0c;第i列的缺口从第l各单位到第h个单位&#xff08;从底部由0开始数&#xff09;。 现在请你清理出一条高度为H的通道&#xff0c;使得箱子可以直接推出去。…

深度学习理论基础(二)深度神经网络DNN

目录 一、基础知识点Ⅰ 参数部分Ⅱ 模型部分 二、深度神经网络模型搭建1. 准备数据集2. 划分数据集3. 搭建模型4. 训练网络5. 测试网络6. 保存与导入模型 神经网络通过学习大量样本的输入与输出特征之间的关系&#xff0c;以拟合出输入与输出之间的方程&#xff0c;学习完成后&…

每日一题(leetcode31):下一个排列-思维

思路&#xff1a;从后往前找到第一个nums[i-1]>nums[i] 然后从后往前(len-1 -->i(包含))找到第一个大于nums[i-1]的数&#xff0c;与nums[i-1]交换&#xff0c;然后对下标区间为[i,len-1]的元素进行排序。 class Solution { public:void nextPermutation(vector<in…

[深度学习] 无人车环境准备

1. 安装过程基本遵循以下步骤 电脑端环境配置 - OriginBot智能机器人开源套件 需要注意以下两点&#xff1a; 1> 由于深度学习需要的包和镜像体积都比较大&#xff0c;所以虚拟机硬盘大小建议120GB 2> 虚拟机的网络适配器应该设置为桥接模式&#xff0c;如果使用NAT模…

vivado 使用网表插入调试探测流程

使用网表插入调试探测流程 在 Vivado 工具中插入调试核的过程以分层方式来演示 &#xff0c; 以应对多样化的 Vivado 用户组的不同需求 &#xff1a; • 最高层是根据选定调试的一组信号线来自动创建并配置 Integrated Logic Analyzer (ILA) 核的简单向导。 • 下一层是“…

File,IO流,递归详解

File类 介绍 java.io.File类是Java语言提供了用来描述文件和目录(文件夹)的 构造 方法 注意&#xff1a; 构造方法中通常用的是第一个方法文件和目录可以通过File封装成对象File封装的对象仅仅是一个路径名&#xff0c;它是可以存在的&#xff0c;也可以不存在 绝对路径…

【二分查找】Leetcode x 的平方根

题目解析 69. x 的平方根 这道题表面是没有顺序性&#xff0c;但是我们可以发现如果使用枚举策略&#xff0c;它是包含顺序性质的&#xff0c;因此我们将枚举算法改进成二分算法 算法讲解 我们让left指针指向1&#xff0c; right指针指向x 如果当前的mid计算出来的平方 &g…

什么是商家转账到零钱

商家转账到零钱是什么&#xff1f; 通过商家转账到零钱这个功能&#xff0c;如果我们系统需要对用户支付费用&#xff0c;比如发放佣金、提成、退款之类的&#xff0c;可以直接转账到用户的微信零钱。 【商家转账到零钱】是【企业付款到零钱】的升级版&#xff0c;2022年5月1…

怀俄明探空站数据解算PWV和Tm

1. Matlab 获取代码可关注公众号WZZHHH回复&#xff08;怀俄明探空站数据解算PWV和Tm&#xff09;&#xff0c;或者咸鱼关注&#xff1a;WZZHHH123 怀俄明探空站数据解算PWV和Tm&#xff1a; 有关 Matlab 获取代码可关注公众号WZZHHH回复&#xff08;怀俄明多线程下载&#…

语音助手背后的魔法:一文揭秘NLP在智能助手中的应用

自然语言处理&#xff08;NLP&#xff09;正逐渐渗透到我们生活的每一个角落。在今天的大盘点中&#xff0c;我们将深入探索NLP在实际生活场景中的多样化应用&#xff0c;以及它在各个案例中所展现出的强大能力。 NLP技术如今已成为智能生活的关键驱动力&#xff0c;它让机器能…