本篇文章八青妹从绘制点、绘制线条、绘制平面、再到绘制立体图像,搭建一个简易的场景。从本文中,学习几何体和材质的使用。
注:本文的案例中,暂不介绍光照的影响。后面写完动画后,再来写光照。
1. 满天繁星(绘制点)
1.1 基础概念
threejs在场景中放置一个物体,需要先设置形状、材质,然后用一个实例包裹住,最后渲染到场景当中去。那即使是一个点,也是如此。这里使用的物体模式是BufferGeometry,点材质是PointsMaterial。
-
BufferGeometry(): 这是 Three.js 中更加高效的几何体类型。它使用 TypedArray(如Float32Array)来存储几何数据,并直接与 WebGL 的 Buffer 对象进行交互。相比于Geometry,BufferGeometry在创建和修改时可能更加复杂,但它的性能优势非常明显,尤其是在处理大量顶点数据的场景中。 -
PointsMaterial():Three.js 中用于渲染点云效果的材质类型。PointsMaterial的主要特点包括:- 点的渲染方式:
PointsMaterial使用 WebGL 的gl.POINTS渲染模式,即将几何体的每个顶点渲染为一个点。这使得它能够快速高效地渲染大量的点云数据。 - 点的大小:
PointsMaterial可以通过size属性来设置点的大小,以像素为单位。这使得我们能够控制点的视觉效果。 - 点的颜色:
PointsMaterial可以通过color属性来设置点的颜色。颜色可以是一个单一的值,也可以是一个纹理贴图。 - 透明度:
PointsMaterial支持透明度设置,通过transparent和opacity属性来控制。这使得我们能够创造出一些特殊的视觉效果,如烟雾、粒子等。
- 点的渲染方式:
星空背景的思路为:创建BufferGeometry,点的材质为大小0.1的白色,随机生成5000个。
const geometry = new THREE.BufferGeometry();
// 创建点材质
const material = new THREE.PointsMaterial({ color: 0xffffff,size: 0.1,transparent: true });
// 创建点对象
const points = new THREE.Points(geometry,material);
scene.add(points);
1.2 代码实现
在官方文档中,使用了数学函数(MathUtils.randFloatSpread)来生成随机数。参考文档THREE.MathUtils.randFloatSpread 定义坐标点和设置位置的地方可以改为下述代码,效果类似。
const vertices = [];
for(let i = 0; i < 10000; i++) {
const x = THREE.MathUtils.randFloatSpread(2000);
const y = THREE.MathUtils.randFloatSpread(2000);
const z = THREE.MathUtils.randFloatSpread(2000);
vertices.push(x,y,z);
}
geometry.setAttribute('position',new THREE.Float32BufferAttribute(vertices,3));
2. 行星轨道(绘制线条)
2.1 基本概念
对于线条来说,可使用的材质有LineBasicMaterial和LineDashedMaterial,两种材质的区别显而易见,后者是虚线段。
LineBasicMaterial是用于渲染线条的基础材质类型,它是一种非光照材质,只根据设置的颜色和其他属性来渲染线条。
以下是 THREE.LineBasicMaterial 的主要属性:
color: 设置线条的颜色。可以是一个 hex 颜色值、一个 CSS 颜色名或一个 RGB 数组。默认值为0xffffff。linewidth: 设置线条的宽度。默认值为1。注意, WebGL 规范不要求浏览器支持可变线宽,所以实际渲染的线宽可能与设置的不一致。transparent: 设置为true时,材质将具有透明度。默认值为false。
2.2 代码实现圆圈的绘制
首先,我们先看下直线绘制是怎么编写的。
const geometry = new THREE.BufferGeometry();
//线条材质
const material = new THREE.LineBasicMaterial( { color: 0x0000ff,transparent: true,opacity:0.9 } );
//定义三个点
const vertices=[
-2,0,0,
0,2,0,
2,0,0
]
//每三个数字确定一个位置信息
geometry.setAttribute('position',new THREE.BufferAttribute(new Float32Array(vertices),3));
//将顶点位置和材质组合在一起
const line = new THREE.Line( geometry, material );
scene.add( line );
效果如下所示:
可以看到的是,线是画在每一对连续的顶点之间,线条不是闭合的。现在,八青妹想要的是一个圆形的线条,该如何实现呢?由上图可以联想到用线条可以画三角形、四边形、五边形……N边形,等等,如果多边形的每条边到中心点的距离都一样,且每条边的长度也一样,当边越来越多的时候,是不是就接近于圆呢?
将上述代码中vertices的赋值改为如下方式:
//半径
const radius = 2;
//线段的个数,值越大圆越光滑
const segments = 36;
const vertices = [];
for(let i = 0; i <= segments; i++) {
const theta = (i / segments) * Math.PI * 2;
vertices.push(Math.cos(theta) * radius,Math.sin(theta) * radius,0);
}
3. 发光的太阳(绘制平面)
3.1 基础概念
MeshBasicMaterial是一个以简单着色(平面或线框)方式来绘制几何体的材质,该材质不受光照的影响,只根据设置的颜色和纹理来渲染物体。
THREE.MeshBasicMaterial 的常用属性:
color: 设置材质的颜色。可以是一个 hex 颜色值、一个 CSS 颜色名或一个 RGB 数组。默认值为0xffffff。map: 设置纹理贴图。如果设置了纹理贴图,它会覆盖在材质的颜色上。wireframe: 设置为true时,物体将以线框模式渲染。默认值为false。transparent: 设置为true时,材质将具有透明度。默认值为false
PlaneGeometry是一个用于生成平面几何体的类。PlaneGeometry(width : Float, height : Float, widthSegments : Integer, heightSegments : Integer)
width— 平面沿着 X 轴的宽度。默认值是1。height— 平面沿着 Y 轴的高度。默认值是1。widthSegments— (可选)平面的宽度分段数,默认值是1。heightSegments— (可选)平面的高度分段数,默认值是1。
3.2 代码实现
// 创建太阳平面几何体
const sunGeometry = new THREE.PlaneGeometry(1.5,1.5);
// 创建太阳发光材质
const sunMaterial = new THREE.MeshBasicMaterial({
color: 0xffff00
});
// 创建太阳mesh
const sun = new THREE.Mesh(sunGeometry,sunMaterial);
scene.add(sun);
效果如下所示:
4. 行星 (立体图像)
4.1 基础概念
需要在轨道上绘制一个球体代表行星。SphereGeometry是threejs中创建球体几何体的类,可以用来创建各种球体形状。
THREE.SphereGeometry 的常用属性:
radius: 球体的半径。默认值为1。widthSegments: 球体围绕 X 轴划分的水平分段数量。默认值为32。值越大,球体越平滑。heightSegments: 球体围绕 Y 轴划分的垂直分段数量。默认值为16。值越大,球体越平滑。
4.2 代码实现
在放置这个球体的时候要注意,这个球体中心距离中心原点的距离为轨道的半径。
const geometry_sphere = new THREE.SphereGeometry(0.5,32,32);
const material_sphere = new THREE.MeshBasicMaterial({ color: 0xffffff });
const sphere = new THREE.Mesh(geometry_sphere,material_sphere);
scene.add(sphere);
//旋转角度
let rotateAngle=0
sphere.position.set(radius * Math.cos(rotateAngle),radius * Math.sin(rotateAngle),0)