本文为稀土技能社区首发签约文章,14天内制止转载,14天后未获授权制止转载,侵权必究!
声明:本文涉及图文和模型资料仅用于个人学习、研究和欣赏,请勿二次修正、不合法传达、转载、出版、商用、及进行其他获利行为。
摘要
本节专栏内容,咱们来了解一下 Three.js
中的多媒体常识,文章将依次具体讲解 Three.js
中文本字体的原理的运用、图片元素原理及运用、音频元素的原理及运用、视频元素的原理及运用等。了解完基本原理后,将利用本文内容所学到的常识,简单制造一个能够播映视频的三维手机展现页面。经过本文内容的学习和实践,你将了解到 Three.js
中各种多媒体元素的运用场景及何运用多媒体元素创立一个烘托愈加实在的三维可交互页面相关的内容。
作用
在学习原理之前,咱们先来看看本文多媒体运用的最终示例页面,它是一个三维产品展现页面,主体是最新版某知名品牌手机 ,场景布景运用了全景天空盒,运用鼠标能够对三维场景进行旋转和缩放、点击手机屏幕开端播映视频,再次点击屏幕视频中止,屏幕复原。由于示例页面布置在
Gitpage
,可能会有加载超时的情况,咱们感兴趣的话最好克隆代码到本地实践。
翻开以下链接,在线预览作用,大屏拜访作用更佳。
-
在线预览地址:dragonir.github.io/threejs-ode…
本专栏系列代码保管在 Github
仓库【threejs-odessey】,后续一切目录也都将在此仓库中更新。
代码仓库地址:git@github.com:dragonir/threejs-ode…
码上

原理
文字
在三维页面开发过程中,3D
字体是咱们需求常常用到的页面装修和功能介质,咱们能够经过如下简单的方式,在 Three.js
中增加文本字体,其间 FontLoader
用于加载字体文件;TextGeometry
用于创立字体网格。
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';
fontLoader.load('fontface.json', font => {
textMesh.geometry = new TextGeometry('1000!', {
font: font,
size: 100,
height: 40
});
scene.add(textMesh);
});

字体加载器 FontLoader
FontLoader
是用于加载 JSON
格式的字体的类,回来 font
, 回来值是表明字体的 Shape
类型的数组。
结构函数:
FontLoader(manager : LoadingManager)
办法:
-
.load (url : String, onLoad : Function, onProgress : Function, onError : Function) : undefined
-
url
:文件的URL
或许途径,也能够为Data URI
。 -
onLoad
:将在加载完结时调用。参数是即将被加载的font
。 -
onProgress
:将在加载过程中调用,参数是包含total
和loaded
字节值。 -
onError
:将在加载过错时调用。
-
-
.parse (json : Object) : Font
-
json
:用于解析的JSON
格式的方针。
-
文本缓冲几何体 TextGeometry
TextGeometry
用于将文本生成为单一的几何体的类,它是由一串给定的文本以及由加载的字体和该几何体父类中的设置参数来构成。
结构函数:
TextGeometry(text : String, parameters : Object)
-
text
:即将显现的文本。 -
parameters
:包含有下列参数的方针-
font
:THREE.Font
的实例。 -
size[Float]
:字体巨细,默认值为100
。 -
height[Float]
:挤出文本的厚度。默认值为50
。 -
curveSegments[Integer]
:表明文本曲线上点的数量。默认值为12
。 -
bevelEnabled[Boolean]
:是否敞开斜角,默以为false
。 -
bevelThickness[Float]
:文本上斜角的深度,默认值为20
。 -
bevelSize[Float]
:斜角与原始文本概括之间的延伸间隔,默认值为8
。 -
bevelSegments[Integer]
:斜角的分段数,默认值为3
。
-
假如咱们只想单纯在页面上加载文案介绍标签,而不是三维字体的话,咱们直接运用 HTML
元素和 CSS
完结,能够利用 raycaster
来完结文字在三维场景中的显现与躲藏。具体完结办法能够看看我之前写的另一篇文章《Three.js 打造缤纷夏日3D梦中情岛》。
在线将字体转换为Three.js支持的格式:facetype
图片
图片在 Three.js
中也是常常用到的元素,比如咱们能够运用图片给网格模型增加纹路、能够运用图片给场景增加布景或天空盒子、也能够单纯用于信息展现。下面列举了几种在场景中加载图片的办法,咱们能够依据不同的场景挑选适宜的办法。
常用的办法,咱们在场景中创立一个平面网格,然后运用 TextureLoader
加载图片,将图片作为平面的纹路贴图增加到场景中。
let mesh = new THREE.Mesh(new THREE.PlaneGeometry(10.41, 16), new THREE.MeshStandardMaterial({
map: new THREE.TextureLoader().load('/texture/image.png'),
transparent: true,
side: THREE.DoubleSide
}));

原料加载器 TextureLoader
TextureLoader
是 Three.js
中加载图片原料的一个类,其内部运用 ImageLoader
来加载文件。
结构函数:
TextureLoader(manager :LoadingManager)
办法:
.load (url: String, onLoad: Function, onProgress: Function, onError: Function) :Texture
-
url
:文件的URL
或许途径。 -
onLoad
:加载完结时将调用,回调参数为即将加载的texture
。 -
onProgress
:将在加载过程中进行调用,实例包含total
和loaded
字节。 -
onError
:在加载过错时被调用。
第二个常常运用到图片的场景就是图片能够作为场景的布景,除了将烘托器设置通明在 CSS
中设置 background
的方式之外,咱们也能够直接经过 scene.background
办法来给场景设置布景。愈加炫酷的方式是,咱们能够经过如下的方式给场景设置三维全景环境贴图,作用类似于全景相片或许全景地图。本文后续的示例中,也将采用该办法给页面设置全景布景。
const cubeTextureLoader = new THREE.CubeTextureLoader();
const environmentMap = cubeTextureLoader.load([
'/textures/environmentMaps/px.jpg',
'/textures/environmentMaps/nx.jpg',
'/textures/environmentMaps/py.jpg',
'/textures/environmentMaps/ny.jpg',
'/textures/environmentMaps/pz.jpg',
'/textures/environmentMaps/nz.jpg'
]);
scene.background = environmentMap;
scene.environment = environmentMap;
立方体原料加载器 CubeTextureLoader
CubeTextureLoader
是用于加载立方体原料的一个类,内部运用 ImageLoader
加载文件。
结构函数:
CubeTextureLoader(manager :LoadingManager)
办法:
.load ( urls : String, onLoad : Function, onProgress : Function, onError : Function ) : null
-
urls
:数组长度为6
的图像数组,内容为URL
,每一个URL
用于CubeTexture
的每一侧,顺序为[pos-x, neg-x, pos-y, neg-y, pos-z, neg-z]
。 -
onLoad
:加载完结时将调用,回调参数是已被加载的texture
。 -
onProgress
:将在加载过程中进行调用,包含total
和loaded
字节。 -
onError
:在加载过错时被调用。
下面两个网站供给丰富的三维全景布景相片及将 hdr
图片裁切成上述需求的 6
张贴图的才能,咱们能够按自己需求下载和编辑。
HDR全景布景相片下载网站:polyhaven

HDR立方体原料转换东西:HDRI-to-CubeMap

除此之外,如咱们在本专栏《Three.js 进阶之旅:奇特的粒子系统-迷失太空》一文中所学的相同,还能够将图片转化为 canvasTexture
加载到模型中。
音频
Three.js
中音频元素能够用于游戏音效或许数字展厅等场景中。现在,咱们介绍关于声响的两个方针。Three.js
中声源有一个十分有趣的特性就是生源会受到摄像机间隔的影响,当摄像机离声源物体间隔较近时,音量就会变大,反之则会变小;摄像机左右两边的方位别离决议着左右两边扬声器声响的巨细。
咱们像下面这个示例相同,在场景中增加音频。首先,咱们在场景中先创立一个 THREE.PersoectiveCamera
,然后定义 THREE.AudioListener
方针,并将它经过 add
办法增加到相机上。为了体验音频的上述特性,咱们在场景中创立 3
个音源:
var listener1 = new THREE.AudioListener();
var listener2 = new THREE.AudioListener();
var listener3 = new THREE.AudioListener();
camera.add(listener1);
camera.add(listener2);
camera.add(listener3);
接着,咱们在场景中创立一个立方体作为音频的载体,并创立一个 THREE.PositionalAudio
方针关联到 THREE.AudioListener
方针上,最后加载音频文件,并在加载器内经过设置一些音频特点来操控音频的播映和表现,其间:
-
setRefDistance
:该特点指定声响从间隔声源多远的方位开端衰减其音量。 -
setLoop
:该特点指定声响是否被循环播映,默认只播映一遍。 -
setRolloffFactor
:该特点指定声源音量跟着间隔衰减的速度。
var geometry = new THREE.BoxGeometry(40, 40, 40);
var material = new THREE.MeshBasicMaterial({
color: 0xffffff,
map: textureLoader.load('/texture/dog.png')
});
var dog = new THREE.Mesh(geometry, material);
dog.position.set(0, 20, 0);
var posSound = new THREE.PositionalAudio(listener1);
var audioLoader = new THREE.AudioLoader();
audioLoader.load('/audio/dog.ogg', function (buffer) {
posSound.setBuffer(buffer);
posSound.setRefDistance(30);
posSound.play();
posSound.setRolloffFactor(10);
posSound.setLoop(true);
});
这样咱们将在场景中增加了一个能够播映狗叫声响的 dog
声源,利用相同的步骤,咱们再往场景中 (0, 20, 100)
和 (0, 20, -100)
的方位再增加其他两种动物的声源。然后咱们再往场景中增加一个第一人称操控器 THREE.FirstPersonControls
,这样就能模仿在场景中来回走动的作用。在移动的过程中,就能感受到上述的音频在 Three.js
中场景中的特性,声响的的音量和方位会跟着摄像机地点的方位改动。例如,假如你将视角方位移动到奶牛的正前方,你就基本上只能听到奶牛的声响,而猫和狗的声响则坐落左声道中且十分微弱。
controls = new THREE.FirstPersonControls(camera);
controls.movementSpeed = 70;
controls.lookSpeed = 0.15;
controls.noFly = true;
controls.lookVertical = false;

AudioListener
AudioListener
用一个虚拟的 listener
表明在场景中一切的方位和非方位相关的音效。
一个 Three.js
程序一般创立一个 AudioListener
,它是音频实体结构函数的必须参数。大多数情况下, listener
方针是 camera
的子方针,Camera
的 3D
改换表明了 listener
的 3D
改换。
结构函数:
AudioListener()
特点:
-
.context[AudioContext]
:listener
结构函数中的AudioContext
。 -
.gain[GainNode]
:运用AudioContext.createGain()
创立GainNode
。 -
.filter[AudioNode]
:默以为null
。 -
.timeDelta[Number]
:audio
实体的时间差值,默认是0
。
办法:
-
.getInput()
:回来gainNode
。 -
.removeFilter()
:设置filter
特点为null
。 -
.getFilter()
:回来filter特点的值。 -
.setFilter(value: AudioNode)
:设置filter
特点的值。 -
.getMasterVolume()
: 回来音量。 -
.setMasterVolume(value: Number)
:设置音量。
音频加载器 AudioLoader
用来加载 AudioBuffer
的一个类,内部默认运用 FileLoader
来加载文件。
结构函数:
AudioLoader(manager: LoadingManager)
办法:
.load(url: String, onLoad: Function, onProgress: Function, onError: Function): undefined
-
url
:文件的URL
或许途径。 -
onLoad
:加载完结时将调用,回调参数为即将加载的呼应文本。 -
onProgress
:将在加载过程中进行调用,实例包含total
和loaded
字节。 -
onError
:在加载过错时被调用。
PositionalAudio
PositionalAudio
创立一个方位相关的音频方针。
结构函数:
PositionalAudio(listener :AudioListener);
特点:
.panner[PannerNode]
:方位相关音频的 PannerNode
。
办法:
-
.getOutput()
:回来panner
。 -
.getRefDistance()
:回来panner.refDistance
的值。 -
.setRefDistance(value: Float)
:设置panner.refDistance
的值。 -
.getRolloffFactor ()
:回来panner.rolloffFactor
的值。 -
.setRolloffFactor (value: Float)
:设置panner.rolloffFactor
的值。 -
.getDistanceModel()
:回来panner.distanceModel
的值。 -
.setDistanceModel(value: String)
:设置panner.distanceModel
的值。 -
.getMaxDistance()
:回来panner.maxDistance
的值。 -
.setMaxDistance(value : Float)
:设置panner.maxDistance
的值。 -
.setDirectionalCone(coneInnerAngle: Float, coneOuterAngle: Float, coneOuterGain: Float )
:用来把盘绕声响转换为定向声响。
第一人称操控器 FirstPersonControls
在音频例子中,镜头操控器运用的是第一人称操控器 FirstPersonControls
,它是 FlyControls
的另一个完结。
结构函数:
FirstPersonControls(object : Camera, domElement : HTMLDOMElement)
-
object
: 被操控的摄像机。 -
domElement
: 用于事件监听的HTML
元素。
特点:
-
.activeLook[Boolean]
:是否能够环视四周,默以为true
。 -
.autoForward[Boolean]
:摄像机是否主动向前移动,默以为false
。 -
.constrainVertical[Boolean]
:笔直环视是否束缚在[.verticalMin, .verticalMax]
之间,默认值为false
。 -
.domElement[HTMLDOMElement]
:用于监听鼠标/接触事件,该特点必须在结构函数中传入。 -
.enabled[Boolean]
:是否启用操控器,默以为true
。 -
.heightCoef
:确定当y
重量挨近.heightMax
时相机移动的速度,默认值为1
. -
.heightMax[Number]
:用于移动速度辅助的摄像机高度上限,默认值为1
。 -
.heightMin[Number]
:用于移动速度断定的相机高度下限,默认值为0
。 -
.heightSpeed[Boolean]
:摄像机的高度是否影响向前移动的速度,默认值为false
。 -
.lookVertical[Boolean]
:是否能够笔直环视,默以为true
。 -
.lookSpeed[Number]
:环视速度,默以为0.005
。 -
.mouseDragOn[Boolean]
:鼠标是否被按下,只读。 -
.movementSpeed[Number]
:移动速度,默以为1
。 -
.object[Camera]
:被操控的摄像机。 -
.verticalMax[Number]
:你能够笔直环视视点的上限,规模在0
到Math.PI
弧度之间,默以为Math.PI
。 -
.verticalMin[Number]
:你能够笔直环视视点的下限,规模在0
到Math.PI
弧度之间,默以为0
。
办法:
-
.dispose()
:若不再需求该操控器调用此办法。 -
.handleResize()
:若运用程序窗口巨细发生改动时调用此办法。 -
.lookAt(vector: Vector3)
或.lookAt (x : Float, y: Float, z: Float)
:一个表明方针方位的向量,或许世界空间方位的x
、y
、z
重量。 -
.update(delta: Number)
:更新操控器,常被用在动画循环中。
音频运用的完整示例代码坐落
08-media/src/sampleAudio.js
,若想了解具体完结细节可查看该文件。
视频
在 Three.js
中自然也能够运用视频媒介来展现内容,咱们能够运用视频元素制造数字展厅、产品介绍简介、元世界会议等。咱们能够像下面这样运用视频元素:
const video = document.getElementById('video');
const texture = new THREE.VideoTexture(video);
视频纹路 VideoTexture
VideoTexture
用于创立一个运用视频来作为贴图的纹路方针。
结构函数:
VideoTexture(video: Video, mapping: Constant, wrapS: Constant, wrapT: Constant, magFilter: Constant, minFilter: Constant, format: Constant, type: Constant, anisotropy: Number)
-
video
:将被作为纹路贴图来运用的Video
元素。 -
mapping
:纹路贴图将被怎么映射到物体上,它是THREE.UVMapping
中的方针类型。 -
wrapS
:默认值是THREE.ClampToEdgeWrapping
。 -
wrapT
:默认值是THREE.ClampToEdgeWrapping
。 -
magFilter
:当一个纹素掩盖大于一个像素时,贴图将怎么采样,其默认值为THREE.LinearFilter
。 -
minFilter
:当一个纹素掩盖小于一个像素时,贴图将怎么采样,其默认值为THREE.LinearFilter
。 -
format
:默认值为THREE.RGBAFormat
。 -
type
:默认值是THREE.UnsignedByteType
。 -
anisotropy
:沿着轴,经过具有最高纹素密度的像素的采样数。 默认情况下,这个值为1
。设置一个较高的值将会比基本的mipmap
发生更清晰的作用,代价是需求运用更多纹路样本。
特点:
-
.generateMipmaps[Boolean]
:是否生成mipmap
,默以为false
。 -
.isVideoTexture[Boolean]
:只读,用于查看给定方针是否为视频纹路类型。 -
.needsUpdate[Boolean]
:不必手动设置这个值,它由update()
办法来进行操控。
办法:
-
.update()
:在每一次新的一帧可用时,这个办法将被主动调用,并将.needsUpdate
设置为true
。
注意:首次运用纹路后,无法更改视频。相反,在纹路上调用.dispose并实例化一个新的纹路。
完结
接下来,咱们运用以上讲述的多媒体常识,制造一个能够播映视频的三维手机展现页面。
场景初始化
场景初始化流程和专栏前面几个示例流程基本上相同的,都是按初始化烘托器、场景、相机、增加光照、页面缩放事件监听更新相机等流程进行,因而不再赘述。为了进步场景烘托的实在性,本文着重关注在 WebGLRenderer
初始化之后设置的这些特点:
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('canvas.webgl'),
antialias: true,
alpha: true
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.physicallyCorrectLights = true;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 2;
renderer.outputEncoding = THREE.sRGBEncoding;
-
renderer.physicallyCorrectLights
:该特点表明是否敞开物理光线矫正,敞开后可设置跟着离光源的间隔增加光照怎么减弱,点光源和聚光灯等灯光受其影响。将其设置为true
能够使得场景中的光线更自然。 -
renderer.toneMapping
:表明的是烘托场景的色彩映射类型,现在Three.js
中包含NoToneMapping
、LinearToneMapping
、ReinhardToneMapping
、CineonToneMapping
、ACESFilmicToneMapping
这5
中色彩类型,依据实践的运用场景,能够挑选不同的烘托色彩来增强烘托实在性。 -
renderer.toneMappingExposure
:是色彩映射的曝光程度,值越大,曝光度越高。 -
renderer.outputEncoding
:表明烘托器的输出编码类型,能够告知烘托器将片段着色器中的最终颜色值从线性颜色空间转化为sRGB
颜色空间,Three.js
中默认编码类型为LinearEncoding
,当咱们运用的纹路中包含sRGB
数据编码时,咱们能够将其设置为sRGBEncoding
,使纹路正确烘托。
创立全景布景
为了营造炫酷的三维作用,咱们能够按上述图片章节所讲述的原理将场景布景设置成全景,除了需求将 scene.background
设置成环境贴图之外,咱们还需求修正一下 scene
的 environment
特点,这样做的目的是可已将环境贴图运用到场景中的全局方针上,此时不需求经过 scene.traverse
遍历场景的一切方针来逐个修正每个方针的环境贴图。
const cubeTextureLoader = new THREE.CubeTextureLoader();
const environmentMap = cubeTextureLoader.load([
'/textures/environmentMaps/px.jpg',
'/textures/environmentMaps/nx.jpg',
'/textures/environmentMaps/py.jpg',
'/textures/environmentMaps/ny.jpg',
'/textures/environmentMaps/pz.jpg',
'/textures/environmentMaps/nz.jpg'
]);
environmentMap.encoding = THREE.sRGBEncoding;
scene.background = environmentMap;
scene.environment = environmentMap;

加载手机模型
加载模型前,咱们先创立好视频纹路 videoTexture
,然后运用该纹路创立根据 MeshPhysicalMaterial
类型的 videoMaterial
视频原料。接着运用 GLTFLoader
加载手机模型,并将其增加到场景中。在回调办法中,咱们能够像下面这样对手机模型 的屏幕、边框、
logo
等方针的原料的金属度、粗糙度等特点进行微调。然后复制一份屏幕的的原始原料,以便于下个步骤中完结视频原料和原始原料的来回切换。
// 创立视频原料
const video = document.getElementById('video');
const videoTexture = new THREE.VideoTexture(video);
// 用于屏幕模型原料切换和点击交互
const screen = {
mesh: null,
material: null,
videoMaterial: new THREE.MeshPhysicalMaterial({
map: videoTexture,
envMap: environmentMap
})
};
// 加载模型
const loader = new GLTFLoader();
let model = null;
loader.load('/models/iphone.glb', mesh => {
if (mesh.scene) {
mesh.scene.traverse(child => {
if (child instanceof THREE.Mesh && child.material instanceof THREE.MeshStandardMaterial) {
child.material.envMap = environmentMap;
child.material.envMapIntensity = 2;
if (child.name === '屏幕') {
screen.mesh = child;
screen.material = child.material;
}
if (child.name.includes('logo')) {
child.material.metalness = 1;
}
}
})
mesh.scene.scale.set(60, 60, 60);
mesh.scene.position.y = -5;
mesh.scene.rotation.y = -Math.PI;
model = mesh.scene;
scene.add(mesh.scene);
}
});

视频切换作用
上个步骤中,咱们现已新建了手机屏幕的视频原料、保存了它的原始原料,并在 screen.mesh
中保存了手机屏幕网格模型。现在咱们运用 THREE.Raycaster
经过如下的办法来完结点击手机屏幕切换它的原料功能。监听点击事件,当鼠标所点击区域发出的射线与 [screen.mesh]
网格模型数组相交时,阐明点击方位坐落手机屏幕上,此时咱们就能够经过判断手机屏幕的原料类型来切换加载视频原料仍是原始原料。
//声明raycaster和mouse变量
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
window.addEventListener('click', event => {
// 经过鼠标点击的方位计算出raycaster所需求的点的方位,以屏幕中心为原点,值的规模为-1到1.
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
// 经过鼠标点的方位和当前相机的矩阵计算出raycaster
raycaster.setFromCamera(mouse, camera);
// 获取raycaster直线和一切模型相交的数组集合
const intersects = raycaster.intersectObjects([screen.mesh]);
if (intersects.length > 0) {
const mesh = intersects[0].object;
if (mesh.material.type === 'MeshStandardMaterial') {
mesh.material = screen.videoMaterial;
} else {
mesh.material = screen.material;
}
}
}, false);

页面优化
到这里,整个示例就开发结束了,咱们能够给手机模型增加一些自转动画、在页面上增加一些提示语、跟着手机旋转的悬浮文字标签等装修性元素,增强页面的可交互性和用户体验 。
源码地址:github.com/dragonir/th…
总结
本文中主要包含的常识点包含:
-
Three.js
中文本字体的运用,及FontLoader
、TextGeometry
的具体用法。 -
Three.js
中图片元素的运用,及TextureLoader
、CubeTextureLoader
的具体用法。 -
Three.js
中音频元素的运用,及AudioListener
、AudioLoader
、PositionalAudio
的具体用法。 -
Three.js
中视频元素的运用,及VideoTexture
的具体用法。 - 第一人称操控器
FirstPersonControls
的用法。 - 怎么运用多媒体元素创立一个烘托愈加实在的三维可交互页面。
想了解其他前端常识或其他未在本文中具体描述的Web 3D开发技能相关常识,可阅读我往期的文章。假如有疑问能够在评论中留言,假如觉得文章对你有协助,不要忘了一键三连哦 。
附录
- [1]. Three.js 打造缤纷夏日3D梦中情岛
- [2]. Three.js 完结炫酷的赛博朋克风格3D数字地球大屏
- [3]. Three.js 完结2022冬奥主题3D趣味页面,含冰墩墩
- [4]. Three.js 完结3D开放世界小游戏:阿狸的多元世界
- [5]. 1000粉!运用Three.js完结一个创意纪念页面
...
- 【Three.js 进阶之旅】系列专栏拜访
- 更多往期【3D】专栏拜访
- 更多往期【前端】专栏拜访
参阅
- [1]. three.js journey
- [2]. threejs.org
- [3]. 《Three.js 开发攻略——根据WebGL和HTML5在网页上烘托3D图形和动画》