前端面经-WebGL/threeJS
WebGL/threeJS面试题扫描与总结-CSDN博客
1.什么是 WebGL?什么是 Three.js?请解释three.js中的WebGL和Canvas的区别?
WebGL(全写Web Graphics Library)是一种3D绘图协议,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。
Three.js是一款基于JavaScript可直接运行GPU驱动游戏与图形驱动应用于浏览器的WebGL引擎,其库提供的特性与API以绘制3D场景于浏览器。
Canvas与WebGL的区别是canvas API提供二维绘图方式,图形的绘制主要通过CanvasRenderingContext2D接口完成,通过 canvas.getContext(‘2d’) 获取二维图像绘图上下文;而WebGL API可以在任何兼容canvas中的渲染2d和3d图形,WebGL API 提供三维接口,图形绘制主要通过WebGLRenderingContext接口完成,通过canvas.getContext(‘webgl’)来获取WebGL上下文。
2.Three.js它有什么特点和优势?以及它为什么会被广泛使用?
Three.js提供了一系列简化的API和工具,使得创建三维图形更加容易的展现在浏览器端。其抽象了底层的复杂性,提供了简单、一致的接口。提供基本的渲染功能之外,还包括了丰富的扩展,如光照、贴图、粒子系统等,可以满足不同类型的三维图形需求。Three.js有一个活跃的社区,提供了大量的文档、教程和示例,方便开发者学习和解决问题。
随着社会的信息化的发展,在数据可视化、图形/游戏引擎、交互演示、图形渲染、地图、VR、物品展示、室内设计、城市规划等方面Web端展示3D的需求大量增多,人们迫切需求一款能打开浏览器即可使用的便捷式3D开发引擎,而基于JavaScript的WebGL引擎Threejs恰好可以满足这一要求,所以得以大规模应用。
3.如何在网页中引入 Three.js 库?
方法一:CDN 导入
1. 2. { 3. "imports": { 4. "three": "https://unpkg.com/three@/build/three.module.js", 5. "three/addons/": "https://unpkg.com/three@/examples/jsm" 6. } 7. } 8.
方法二:npm安装导入
npm install three --save
方法三: 模块化导入
import * as THREE from './node_modules/three/build/three.module.js'; var scene = new THREE.Scene()
方法四:script标签方式引入
var scene = new THREE.Scene() console.log(scene)
4.Three.js的基本组件和类有哪些?
Three.js的基本组件有场景(Scene)、相机(Camera)、渲染器(Renderer);
常见的类有Object3D、BufferGeometry、Geometry、BufferAttribute、Layers、Raycaster等;
Object3D类:Object3D是ThreeJs中对物体抽象的基类,包括相机和灯光都是Object3D的子类.一般情况下,我们不会直接使用这个类,对于构造物体,一般我们都是使用的Mesh.
BufferGeometry类:是面片、线或点几何体的有效表述.包括顶点位置,面片索引、法相量、颜色值、UV坐标和自定义缓存属性值.使用BufferGeometry可以有效减少向 GPU 传输上述数据所需的开销.
Geometry类:Geometry 是对 BufferGeometry 的替代,Geometry利用Vector3或Color存储了几何体的相关 attributes(如顶点位置,面信息,颜色等),但比起BufferGeometry更容易读写,但是运行效率不如有类型的队列.
BufferAttribute类:这个类用于存储与BufferGeometry相关联的attribute(例如顶点位置向量,面片索引,法向量,颜色值,UV坐标以及任何自定义attribute).利用BufferAttribute,可以更高效的向GPU传递数据.详情和例子见该页.
在BufferAttribute中,数据被存储为任意长度的矢量(通过itemSize进行定义),下列函数如无特别说明, 函数参数中的index会自动乘以矢量长度进行计算. 当想要处理类似向量的数据时, 可以使用在Vector2,Vector3,Vector4以及Color这些类中的.fromBufferAttribute(attribute,index) 方法来更为便捷地处理.
Layers类:Layers对象为Object3D分配1个到32个图层.32个图层从0到31编号标记.在内部实现上,每个图层对象被存储为一个bit mask,默认的,所有Object3D对象都存储在第0个图层上.图层对象可以用于控制对象的显示.当camera的内容被渲染时与其共享图层相同的物体会被显示.每个对象都需要与一个camera共享图层.每个继承自Object3D的对象都有一个Object3D.layers对象.
Raycaster类:这个类用于进行raycasting(光线投射).光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体).
5.three.js中的场景 (scene)、相机 (camera)和渲染器 (renderer)的作用?
场景是Three.js 中所有 3D 对象的容器。它定义了 3D 空间中的位置、方向和光照。
相机定义了 3D 场景中的视角。通过设置相机的位置和角度,可以控制场景中的视觉效果。
渲染器将场景和相机中的 3D 对象渲染到屏幕上。Three.js 提供了多个渲染器,包括 CanvasRenderer、WebGLRenderer 和 SVGRenderer。
6.three.js中的常见几何体(例如立方体、球体、圆柱体等)是如何被创建的?
6.1. 立方体(BoxGeometry)
// 参数:宽度、高度、深度、宽度分段数、高度分段数、深度分段数 const geometry = new THREE.BoxGeometry(1, 1, 1);
核心参数:
width:X 轴方向的宽度(默认 1)。
height:Y 轴方向的高度(默认 1)。
depth:Z 轴方向的深度(默认 1)。
widthSegments、heightSegments、depthSegments:控制细分程度,影响平滑度和性能。
6.2. 球体(SphereGeometry)
// 参数:半径、横向分段数、纵向分段数 const geometry = new THREE.SphereGeometry(1, 32, 16);
核心参数:
radius:球体半径(默认 1)。
widthSegments:横向分段数(默认 32),值越大越平滑。
heightSegments:纵向分段数(默认 16),控制两极的细分。
phiStart、phiLength:水平起始角度和弧度范围(默认 0 到 2π)。
thetaStart、thetaLength:垂直起始角度和弧度范围(默认 0 到 π)。
6.3 圆柱体(CylinderGeometry)
// 参数:顶部半径、底部半径、高度、径向分段数、高度分段数 const geometry = new THREE.CylinderGeometry(0.5, 1, 2, 32);
核心参数:
radiusTop:顶部半径(默认 1)。
radiusBottom:底部半径(默认 1)。
height:圆柱体高度(默认 1)。
radialSegments:径向分段数(默认 32),控制侧面的多边形数量。
heightSegments:高度分段数(默认 1),控制高度方向的细分。
openEnded:是否开放两端(默认 false,即封闭)。
6.4 平面(PlaneGeometry)
// 参数:宽度、高度、宽度分段数、高度分段数 const geometry = new THREE.PlaneGeometry(10, 10, 1, 1);
核心参数:
width、height:平面的宽和高(默认 1)。
widthSegments、heightSegments:控制细分程度,用于复杂变形或物理模拟。
6.5 圆锥体(ConeGeometry)
// 参数:半径、高度、径向分段数 const geometry = new THREE.ConeGeometry(1, 2, 32);
核心参数:
radius:底部半径(默认 1)。
height:高度(默认 1)。
radialSegments:径向分段数(默认 32)。
openEnded:是否开放底部(默认 false)。
6.6 圆环(TorusGeometry)
// 参数:圆环半径、管道半径、径向分段数、管道分段数 const geometry = new THREE.TorusGeometry(3, 1, 16, 100);
核心参数:
radius:圆环中心到管道中心的距离(默认 1)。
tube:管道半径(默认 0.4)。
radialSegments:径向分段数(默认 16)。
tubularSegments:管道分段数(默认 100)。
arc:圆环弧度(默认 2π,即完整圆环)。
6.7 圆环结(TorusKnotGeometry)
// 参数:半径、管道半径、分段数、缠绕数 const geometry = new THREE.TorusKnotGeometry(2, 0.5, 100, 16);
核心参数:
radius:圆环结中心到管道中心的距离(默认 1)。
tube:管道半径(默认 0.4)。
tubularSegments:管道分段数(默认 64)。
radialSegments:径向分段数(默认 8)。
p、q:控制缠绕方式的整数(默认 3 和 2)。
7.如何在Three.js中创建自定义几何体 **( **Custom Geometry **) **?
在 Three.js 中创建自定义几何体主要通过BufferGeometry类实现,它是现代 Three.js 中表示几何体的标准方式,相比旧版的Geometry类,BufferGeometry在性能和内存使用上更高效。以下是创建自定义几何体的核心步骤和示例:
7.1基础原理
BufferGeometry通过 ** 缓冲区属性(BufferAttribute)** 存储顶点数据,主要包括:
顶点位置(position):每个顶点的三维坐标(x, y, z)。
顶点法线(normal):用于光照计算的方向向量。
UV 坐标(uv):用于纹理映射的二维坐标。
颜色(color):顶点颜色(可选)。
7.2创建自定义几何体的步骤
7.2.1. 创建 BufferGeometry 实例
const geometry = new THREE.BufferGeometry();
7.2.2 定义顶点数据
使用Float32Array或Uint16Array存储顶点信息:
// 示例:创建一个三角形的顶点位置数据 const vertices = new Float32Array([ 0, 0, 0, // 顶点1坐标 1, 0, 0, // 顶点2坐标 0, 1, 0 // 顶点3坐标 ]);
7.2.3 创建缓冲区属性并设置到几何体
// 参数:数据数组,每个顶点的分量数(如position为3个分量:x,y,z) geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
7.2.4(可选)设置顶点法线和 UV 坐标
// 设置法线(用于光照计算) const normals = new Float32Array([ 0, 0, 1, // 顶点1的法线方向(垂直屏幕向外) 0, 0, 1, // 顶点2的法线方向 0, 0, 1 // 顶点3的法线方向 ]); geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3)); // 设置UV坐标(用于纹理映射) const uvs = new Float32Array([ 0, 0, // 顶点1的UV坐标 1, 0, // 顶点2的UV坐标 0, 1 // 顶点3的UV坐标 ]); geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));
7.2。5 (可选)设置索引(优化多个三角形共享顶点)
// 使用索引可以复用顶点,减少内存占用 const indices = new Uint16Array([ 0, 1, 2 // 表示一个由顶点0、1、2组成的三角形 ]); geometry.setIndex(indices);
7.2.6 创建材质并渲染几何体
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh);
7.3示例:创建自定义四边形
// 创建BufferGeometry const geometry = new THREE.BufferGeometry(); // 定义四个顶点的位置(顺时针排列) const vertices = new Float32Array([ -1, -1, 0, // 左下 (顶点0) 1, -1, 0, // 右下 (顶点1) 1, 1, 0, // 右上 (顶点2) -1, 1, 0 // 左上 (顶点3) ]); // 设置位置属性 geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); // 设置法线(所有顶点法线朝上) const normals = new Float32Array([ 0, 0, 1, // 顶点0法线 0, 0, 1, // 顶点1法线 0, 0, 1, // 顶点2法线 0, 0, 1 // 顶点3法线 ]); geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3)); // 设置UV坐标 const uvs = new Float32Array([ 0, 0, // 左下UV 1, 0, // 右下UV 1, 1, // 右上UV 0, 1 // 左上UV ]); geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2)); // 设置索引(两个三角形组成四边形) const indices = new Uint16Array([ 0, 1, 2, // 第一个三角形:左下-右下-右上 0, 2, 3 // 第二个三角形:左下-右上-左上 ]); geometry.setIndex(indices); // 创建材质和网格 const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 }); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh);
7.4高级技巧:创建复杂几何体
7.4.1.从数学函数生成几何体
例如创建一个正弦波平面:
const width = 10; const height = 10; const segments = 100; const vertices = new Float32Array((segments + 1) * (segments + 1) * 3); let index = 0; for (let i = 0; i for (let j = 0; j const x = (j / segments) * width - width / 2; const y = Math.sin(x) * Math.cos(i / segments * height); const z = (i / segments) * height - height / 2; vertices[index++] = x; vertices[index++] = y; vertices[index++] = z; } } // 设置位置属性并计算索引...