threeJS入门

目录

WebGL和three.js

WebGL是在浏览器中实现三维效果的一套规范。three.js是基于WebGL实现的一个三维开源库,可以很方便地实现3D场景和动画。

创建3D图形

场景(scene) 相机(camera):人的眼睛 渲染器(renderer)

20230906095341

20230906095415

3D世界是由点组成,两个点能够组成一条直线,三个不在一条直线上的点就能够组成一个三角形面,无数三角形面就能够组成各种形状的物体。

点的定义

// 创建一个点
var point = new THREE.Vector3(1, 2, 3);
// or using set
var point2 = new THREE.Vector3();
point2.set(1, 2, 3);

线的定义

在Threejs中,一条线由点,材质和颜色组成。

THREE.Geometry形状包含一个数组vertices,这个vertices就是存放无数的点(THREE.Vector3)的数组。

也可以使用专为线准备的材质,THREE.LineBasicMaterial。

var p1 = new THREE.Vector3(-100, 0, 100);
var p2 = new THREE.Vector3(100, 0, -100);
// 声明一个Geometry
var geometry = new THREE.Geometry();
geometry.vertices.push(p1);
geonetry.vertice.push(p2);
// LineBasicMaterial
// 创建一个 THREE.LineBasicMaterial 来定义线段的样式。你可以设置线段的颜色、线宽等属性
var material = new THREE.LineBasicMaterial({ color: 0xff0000, linewidth: 2 });
var line = new THREE.Line(geometry, material);
scene.add(line);

三角形面的定义

// 定义三角形面的三个顶点
var p1 = new THREE.Vector3(-100, 0, 100);
var p2 = new THREE.Vector3(100, 0, -100);
var p3 = new THREE.Vector3(-100, 0, -100);
// 声明一个Geometry
var faceGeometry = new THREE.Geometry();
// MeshBasicMaterial是一种材质,用于定义网格模型的颜色,side属性用于定义网格模型的双面或单面渲染
var faceMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide });
// 将三个顶点添加到Geometry中
faceGeometry.vertices.push(p1);
faceGeometry.vertices.push(p2);
faceGeometry.vertices.push(p3);

var face = THREE.Mesh(faceGeometry, faceMaterial);

scene.add(face);

这段代码创建了一个圆形的网格对象(Mesh),使用了 THREE.CircleGeometry 来定义圆的几何形状,以及 THREE.MeshBasicMaterial 来指定圆的材质。

THREE.CircleGeometry 的参数解释如下:

第一个参数是圆的半径; 第二个参数是圆的分段数,决定了圆的平滑度; 第三个参数是圆的起始角度; 第四个参数是圆的结束角度。

起始角度是 0,结束角度是 Math.PI * 2,表示一个完整的圆。

创建一个圆环与之类似,只是起始角度和结束角度不太一样。

// 创建一个圆
var circleGeometry = new THREE.CircleGeometry(50, 20, 0, Math.PI * 2);

var circleMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide });

//移除圆的中心点
circleGeometry.vertices.shift();

var circle = new THREE.Mesh(circleGeometry, circleMaterial);

scene.add(circle);

动态场景

第一种方法是让物体在坐标系里面移动,摄像机不动。 第二种方法是让摄像机在坐标系里面移动,物体不动。

移动物体示意代码:

// 创建场景、渲染器和摄像机,省略代码...

// 创建一个立方体
var cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
var cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

// 将立方体添加到场景中
scene.add(cube);

// 动画循环
function animate() {
  requestAnimationFrame(animate);

  // 更新立方体的位置
  cube.position.x += 0.01;

  // 渲染场景
  renderer.render(scene, camera);
}

// 启动动画循环
animate();

更新摄像机示意代码:

// 创建场景、渲染器和摄像机,省略代码...
// 创建一个立方体
var cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
var cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

// 将立方体添加到场景中
scene.add(cube);

// 动画循环
function animate() {
  requestAnimationFrame(animate);

  // 更新摄像机的位置
  camera.position.x += 0.01;

  // 渲染场景
  renderer.render(scene, camera);
}

// 启动动画循环
animate();

在Three.js中,当我们改变了物体的位置、颜色或其他属性时,需要重新调用 renderer.render(scene, camera) 函数,以便将更新后的场景重新绘制到浏览器中。

但是,在WebGL中,渲染是一个昂贵的操作,如果我们在每次更新之后都手动调用 renderer.render(scene, camera),那么会造成性能上的浪费。

为了避免这种情况,我们可以使用 requestAnimationFrame 函数来实现自动刷新场景。requestAnimationFrame 是一个JavaScript的特殊函数,它会在浏览器每次绘制新的一帧之前调用我们指定的回调函数。通过这种方式,我们不需要手动调用 renderer.render(scene, camera),而是通过 requestAnimationFrame 自动触发渲染,并确保场景及时更新。

也就是说,requestAnimationFrame 函数会自动处理帧率和浏览器的优化机制,只有在下一帧绘制时,才会执行 renderer.render(scene, camera) 以更新场景。

相机与投影

正交投影(Orthographic Projection): 正交投影是一种平行投影方式,它不考虑物体与相机之间的距离,所有物体在投影面上的大小都是一样的。正交投影在Three.js中使用 OrthographicCamera 来实现。

透视投影(Perspective Projection): 透视投影是一种模拟人眼观察场景的投影方式。它通过将远处的物体缩小,近处的物体放大,来创造出远近不同的景深效果。透视投影在Three.js中使用 PerspectiveCamera 来实现。

20230906102858

正交投影代码实现:

相机的视图范围由 left、right、top 和 bottom 参数决定,而 near 和 far 参数定义了相机的视锥体的近平面和远平面距离。

OrthographicCamera( left, right, top, bottom, near, far )
var camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );
scene.add( camera );

透视投影代码:

var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
scene.add(camera);

fov:视场角(Field of View),表示相机在垂直方向上可见范围的角度。 aspect:视图宽度和高度的比例。 near:相机视锥体近平面距离。 far:相机视锥体远平面距离。

20230906103447

透视投影可以呈现出远近景深感,而正交投影则是保持物体尺寸一致的平行投影方式。

人类的正常视角是120度集中注意力看清楚,在30-40度

光源

光源可以为你的场景提供照明效果,使物体的材质能够反射、投射或接收光线。Three.js提供了一个基类THREE.Light,包含多种光源类型,包括环境光(AmbientLight)、平行光(DirectionalLight)、点光源(PointLight)等。你可以根据场景的需求添加适当的光源。

环境光源

环境光就是在场景中无处不在的光,它对物体的影响是均匀的,也就是无论你从物体的那个角度观察,物体的颜色都是一样的!

var light = new THREE.AmbientLight(0xffffff);
scene.add(light);

20230906103650

点光源

点光源就像一个灯泡,它会向四周发出光线,光线的强度会随着距离的增加而衰减。

var light = new THREE.PointLight(0xffffff, 1, 1000);
scene.add(light);

第一个参数是光源的颜色;第二个参数是光源的强度,默认是1.0,表示100%强度的光;第三个参数表示光的距离,从光源所在的位置,经过distance这段距离之后,光的强度将从Intensity衰减为0。

聚光灯

  • THREE.SpotLight( hex, intensity, distance, angle, exponent )
  • Hex:聚光灯发出的颜色,如0xFFFFFF
  • Intensity:光源的强度,默认是1.0,如果为0.5,则强度是一半
  • Distance:光线的强度,从最大值衰减到0,需要的距离。 默认为0,表示光不衰减,如果非0,则表示从光源的位置到Distance的距离,光都在线性衰减。到离光源距离Distance时,光源强度为0.
  • Angle:聚光灯着色的角度,用弧度作为单位,这个角度是和光源的方向形成的角度。
  • exponent:光源模型中,衰减的一个参数,越大衰减约快。

参考链接

  • 李春芳 《数据可视化》

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦