目录

Threejs

threejs

学习 Three.js 的基础知识

在开始创建 3D 场景之前,您需要了解 Three.js 的基本组件、场景、相机、渲染器、几何体和材质等等。

场景(Scene)

场景是 Three.js 中所有 3D 对象的容器。它定义了 3D 空间中的位置、方向和光照。

相机(Camera)

相机定义了 3D 场景中的视角。通过设置相机的位置和角度,可以控制场景中的视觉效果。

渲染器(Renderer)

渲染器将场景和相机中的 3D 对象渲染到屏幕上。Three.js 提供了多个渲染器,包括 CanvasRenderer、WebGLRenderer 和 SVGRenderer。

几何体(Geometry)

几何体定义了 3D 对象的形状。Three.js 提供了多个几何体,如立方体、球体、圆柱体等等,也可以自定义几何体。

材质(Material)

材质定义了 3D 对象的外观。材质可以包括纹理、颜色、反射和透明度等等。

网格(Mesh)

网格是几何体和材质的组合体。它将几何体的形状和材质的外观结合在一起,并添加到场景中进行渲染。

创建 3D 场景

使用 Three.js 创建 3D 场景需要了解如何添加和组合 3D 对象、调整相机位置和视角、应用材质和纹理、创建灯光和阴影等等。

如何添加和组合 3D 对象

在 Three.js 中,可以通过以下步骤来添加和组合 3D 对象:

创建几何体

首先,需要创建一个几何体来定义 3D 对象的形状。Three.js 提供了多个几何体,如立方体、球体、圆柱体等等,也可以自定义几何体。

例如,以下代码创建一个立方体几何体:

var geometry = new THREE.BoxGeometry( 1, 1, 1 );

创建材质

接下来,需要创建一个材质来定义 3D 对象的外观。材质可以包括纹理、颜色、反射和透明度等等。

例如,以下代码创建一个基本材质:

var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );

创建网格对象

接下来,需要将几何体和材质组合起来,创建一个网格对象。

例如,以下代码创建一个红色立方体:

var cube = new THREE.Mesh( geometry, material );

将网格对象添加到场景中

最后,需要将网格对象添加到场景中,以便进行渲染。

例如,以下代码将立方体添加到场景中:

scene.add( cube );

调整相机位置和视角

在 Three.js 中,可以通过调整相机的位置和视角来控制场景中的视觉效果。以下是一些常用的方法:

设置相机位置 可以使用相机的 position 属性来设置相机在 3D 空间中的位置。例如,以下代码将相机的位置设置为 x=0、y=0、z=5:

camera.position.set( 0, 0, 5 );

设置相机视角 可以使用相机的 lookAt() 方法来设置相机的视角。该方法需要一个 Three.js 向量作为参数,表示相机所要对准的位置。 例如,以下代码将相机对准场景中心点:

camera.lookAt( 0, 0, 0 );

控制相机旋转

可以使用相机的 rotation 属性来控制相机的旋转角度。例如,以下代码将相机绕 y 轴旋转 45 度:

camera.rotation.y = Math.PI / 4;

控制相机缩放 可以使用相机的 zoom 属性来控制相机的缩放比例。例如,以下代码将相机的缩放比例设置为 2:

camera.zoom = 2;
camera.updateProjectionMatrix(); // 需要调用该方法来更新相机投影矩阵

应用材质和纹理

在 Three.js 中,可以通过应用材质和纹理来改变 3D 对象的外观。以下是一些常用的方法:

应用材质

可以通过将材质对象赋给网格对象的 material 属性来应用材质。例如,以下代码将一个红色材质应用于立方体:

var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var cube = new THREE.Mesh( geometry, material );

Three.js 中还有其他类型的材质可用,如 MeshPhongMaterial、MeshStandardMaterial 等,可以根据需要选择。

应用纹理

可以通过将纹理对象赋给材质对象的 map 属性来应用纹理。例如,以下代码将一个纹理贴图应用于立方体:

var texture = new THREE.TextureLoader().load( 'texture.png' );
var material = new THREE.MeshBasicMaterial( { map: texture } );
var cube = new THREE.Mesh( geometry, material );

其中,TextureLoader 是 Three.js 内置的纹理加载器,可以加载常见的图片格式。

在使用纹理时,还可以设置纹理的重复和偏移。例如,以下代码将一个纹理重复 5 次并向右偏移 0.5:

texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 5, 1 );
texture.offset.set( 0.5, 0 );

通过以上方法,可以应用不同的材质和纹理,从而改变 3D 对象的外观。

创建灯光和阴影等等

在 Three.js 中,可以通过创建灯光和开启阴影等方式来增强 3D 场景的逼真感。以下是一些常用的方法:

创建灯光 可以使用 Three.js 中提供的灯光类型,如 AmbientLight、PointLight、SpotLight、DirectionalLight 等来创建不同类型的灯光。例如,以下代码创建了一个点光源:

var light = new THREE.PointLight( 0xffffff, 1, 100 );
light.position.set( 0, 0, 10 );
scene.add( light );

其中,0xffffff 表示灯光的颜色,1 表示灯光的强度,100 表示灯光的最大距离。

开启阴影 可以通过设置对象的 castShadow 和 receiveShadow 属性来开启阴影。例如,以下代码创建了一个平面和一个立方体,并开启了阴影:

var plane = new THREE.Mesh( planeGeometry, planeMaterial );
plane.receiveShadow = true;

var cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.castShadow = true;
scene.add( plane, cube );

其中,plane.receiveShadow 表示平面接收阴影,cube.castShadow 表示立方体产生阴影。

为了使阴影能够正确渲染,还需要设置灯光的 castShadow、shadow.mapSize、shadow.bias 和 shadow.camera 属性。例如,以下代码设置了点光源的阴影参数:

light.castShadow = true;
light.shadow.mapSize.width = 512;
light.shadow.mapSize.height = 512;
light.shadow.bias = -0.001;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 100;

通过以上方法,可以创建不同类型的灯光,并开启阴影等效果,从而增强 3D 场景的逼真感。

结合以上知识给出一个具体的案例

下面是一个使用 Three.js 创建带有灯光和阴影的 3D 场景的案例:

// 创建场景、相机和渲染器
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

// 创建灯光
var light = new THREE.PointLight( 0xffffff, 1, 100 );
light.position.set( 0, 0, 10 );
light.castShadow = true;
light.shadow.mapSize.width = 512;
light.shadow.mapSize.height = 512;
light.shadow.bias = -0.001;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 100;
scene.add( light );

// 创建物体
var geometry = new THREE.BoxGeometry();
var material = new THREE.MeshStandardMaterial( { color: 0xff0000 } );
var cube = new THREE.Mesh( geometry, material );
cube.position.set( 0, 0, 1 );
cube.castShadow = true;
scene.add( cube );

var planeGeometry = new THREE.PlaneGeometry( 20, 20 );
var planeMaterial = new THREE.MeshStandardMaterial( { color: 0xaaaaaa } );
var plane = new THREE.Mesh( planeGeometry, planeMaterial );
plane.position.set( 0, -2, 0 );
plane.receiveShadow = true;
scene.add( plane );

// 调整相机位置和视角
camera.position.z = 5;

// 渲染场景
function animate() {
    requestAnimationFrame( animate );
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render( scene, camera );
}
animate();

学习 Three.js 高级特性

一旦您熟悉了 Three.js 的基础知识,可以开始探索 Three.js 的高级特性,如动画、物理模拟、后期处理、粒子效果等等。

物理模拟

Three.js 支持使用物理引擎来实现物理模拟效果。其中, Ammo.js 和 Cannon.js 是两个比较流行的物理引擎库。

下面是一个使用 Cannon.js 实现物理模拟的示例:

// 创建场景、相机和渲染器
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

// 创建平面
var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff } );
var groundGeometry = new THREE.PlaneGeometry( 100, 100 );
var ground = new THREE.Mesh( groundGeometry, groundMaterial );
ground.rotation.x = -Math.PI / 2;
ground.position.y = -2;
ground.receiveShadow = true;
scene.add( ground );

// 创建球体
var ballMaterial = new THREE.MeshPhongMaterial( { color: 0xff0000 } );
var ballGeometry = new THREE.SphereGeometry( 1, 32, 32 );
var ball = new THREE.Mesh( ballGeometry, ballMaterial );
ball.position.y = 5;
ball.castShadow = true;
ball.receiveShadow = true;
scene.add( ball );

// 创建物理引擎世界
var world = new CANNON.World();
world.gravity.set( 0, -9.82, 0 );

// 创建地面的刚体
var groundShape = new CANNON.Plane();
var groundBody = new CANNON.Body( { mass: 0 } );
groundBody.addShape( groundShape );
world.addBody( groundBody );

// 创建球体的刚体
var ballShape = new CANNON.Sphere( 1 );
var ballBody = new CANNON.Body( { mass: 1 } );
ballBody.addShape( ballShape );
ballBody.position.set( 0, 5, 0 );
world.addBody( ballBody );

// 开始模拟物理效果
function animate() {
    requestAnimationFrame( animate );

    world.step( 1 / 60 );

    ball.position.copy( ballBody.position );
    ball.quaternion.copy( ballBody.quaternion );

    renderer.render( scene, camera );
}
animate();

在这个示例中,我们创建了一个平面和一个球体,并使用 Cannon.js 创建了物理引擎世界和物体的刚体。我们将球体放在空中,并让其受到重力作用而下落到地面上。通过不断地调用 world.step() 方法来模拟物理效果,并将物体的位置和旋转状态与刚体同步。

你可以尝试调整物体的质量、形状、摩擦力等参数,来实现不同的物理效果。注意,在使用物理引擎时需要考虑性能问题,尽可能地优化计算性能。

后期处理

在 Three.js 中,我们可以通过后期处理(Post-Processing)技术来对渲染场景进行额外的处理,以实现各种特效,比如模糊、景深、色调映射等等。

Three.js 内置了一些后期处理的库,比如 EffectComposer 和各种后期处理器(Post-Processing Pass),可以直接使用。下面是一个简单的使用 EffectComposer 实现景深效果的示例:

// 创建场景、相机和渲染器
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

// 创建物体
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshPhongMaterial( { color: 0xffffff } );
var cube = new THREE.Mesh( geometry, material );
cube.position.z = -5;
scene.add( cube );

// 创建后期处理器
var composer = new THREE.EffectComposer( renderer );
var renderPass = new THREE.RenderPass( scene, camera );
composer.addPass( renderPass );
var depthPass = new THREE.DepthPass();
composer.addPass( depthPass );
var bokehPass = new THREE.BokehPass( scene, camera, {
    focus: 1.0,
    aperture: 0.01,
    maxblur: 0.01,
    width: window.innerWidth,
    height: window.innerHeight
} );
composer.addPass( bokehPass );

// 渲染场景
function render() {
    requestAnimationFrame( render );
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    composer.render();
}
render();

在这个示例中,我们创建了一个立方体,并使用 EffectComposer 创建了后期处理器。我们添加了三个后期处理 Pass,分别是 RenderPass、DepthPass 和 BokehPass。RenderPass 将场景和相机传递给下一个 Pass,DepthPass 生成场景深度图,BokehPass 利用场景深度图和相机参数生成景深效果。最终,我们使用 composer.render() 方法渲染场景。

你可以尝试使用其他后期处理 Pass 和参数,实现不同的后期处理效果。注意,在使用后期处理时需要考虑性能问题,尽可能地优化计算性能。

粒子效果

在 Three.js 中,我们可以使用粒子系统(Particle System)来实现各种有趣的粒子效果,比如烟雾、火花、星空等等。下面是一个简单的使用粒子系统实现星空效果的示例:

// 创建场景、相机和渲染器
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

// 创建粒子系统
var particleCount = 10000;
var particles = new THREE.Geometry();
for ( var i = 0; i < particleCount; i ++ ) {
    var x = Math.random() * 2000 - 1000;
    var y = Math.random() * 2000 - 1000;
    var z = Math.random() * 2000 - 1000;
    var particle = new THREE.Vector3( x, y, z );
    particles.vertices.push( particle );
}
var particleMaterial = new THREE.PointsMaterial( {
    color: 0xffffff,
    size: 2,
    sizeAttenuation: false
} );
var particleSystem = new THREE.Points( particles, particleMaterial );
scene.add( particleSystem );

// 渲染场景
function render() {
    requestAnimationFrame( render );
    particleSystem.rotation.y += 0.001;
    renderer.render( scene, camera );
}
render();

在这个示例中,我们创建了一个粒子系统,包含了 10000 个粒子,每个粒子的位置都是随机生成的。我们使用 THREE.PointsMaterial 创建了粒子材质,并将其应用到 THREE.Points 对象上。最后,我们在渲染循环中更新粒子系统的旋转角度,渲染场景。

你可以通过调整粒子数量、粒子大小、材质颜色等参数,实现不同的粒子效果。在 Three.js 中,还有一些高级的粒子系统库,比如 THREE.GPUParticleSystem,可以提供更高性能的粒子渲染。