likes
comments
collection
share

Threejs开发3D展馆 | 大帅老猿threejs特训

作者站长头像
站长
· 阅读数 17

本文将介绍如果使用Threejs开发制作一个3D展馆,效果如图:

Threejs开发3D展馆 | 大帅老猿threejs特训

首先,我们需要一个展馆模型。我是通过Blender做出来的,在Blender中将模型导出为glb格式。

Threejs开发3D展馆 | 大帅老猿threejs特训

接下来,我们通过代码将模型加载到网页中。

在3D图形开发中,最基本的概念就是场景、相机和光源。这三个是构成3D世界的基本要素。所以,我们需要先创建一个场景、设置相机和光源。

//创建场景
const scene = new THREE.Scene();

//设置相机
const camera = new THREE.PerspectiveCamera(45, container.offsetWidth / container.offsetHeight, 10, 10000);
camera.position.set(5, 10, -40);//设置相机位置
camera.lookAt(0,0,0);//让相机看相原点
//光源,平行光
var light2 = new THREE.DirectionalLight(0xffffff, 1);
scene.add(light2);

然后,我们使用Threejs提供的GLTFLoader将模型加载进来。

const loader = new GLTFLoader();
loader.load(
'../resources/models/zhanguan2.glb',
function (gltf) {
scene.add(gltf.scene);//将模型添加到场景中
})

效果如下:

Threejs开发3D展馆 | 大帅老猿threejs特训

这时候我们会发现,整个场馆有点暗,而且只有场馆里面是亮的,围墙是黑乎乎的。因为我们用的是平行光,有些地方会照不到,所以就是黑的了。接下来,我们用环境贴图的方式,照亮整个场馆。我们使用这张图片:

Threejs开发3D展馆 | 大帅老猿threejs特训

new RGBELoader().load('../resources/sky.hdr', function (texture) {

texture.mapping = THREE.EquirectangularReflectionMapping

scene.environment = texture

renderer.outputEncoding = THREE.sRGBEncoding

renderer.render(scene, camera)

})

效果如下:

Threejs开发3D展馆 | 大帅老猿threejs特训

接下来,我们来实现,2023烟花播放的效果。效果看起来很酷炫,但其实实现起来挺简单的。

gltf.scene.traverse((child) => {

if (child.name === '2023') {

let happyNewYear2023 = child

const video = document.createElement('video')

video.src = './resources/yanhua.mp4'

video.muted = true

video.autoplay = true

video.loop = true

const VideoTexture = new THREE.VideoTexture(video)

const videoMaterial = new THREE.MeshBasicMaterial({

map: VideoTexture

})
happyNewYear2023.material = videoMaterial
}
}

上面这段代码,就是通过遍历的方式,将2023这个子模型筛选出来。然后使用视频贴图,将贴图映射到“2023”上。效果如下:

Threejs开发3D展馆 | 大帅老猿threejs特训

同样的,展馆内的屏幕也是通过这种方式实现的:

if (child.name === '屏幕1' ) {

const video = document.createElement('video');

video.src = "./resources/video01.mp4";

video.muted = true;

video.autoplay = "autoplay";

video.loop = true;

video.play();

const videoTexture = new THREE.VideoTexture(video);

const videoMaterial = new THREE.MeshBasicMaterial({ map: videoTexture });

child.material = videoMaterial;

}

接下来,我们将人物角色加载进来,同样使用的是GLTFLoader.

new GLTFLoader().load('../resources/models/player.glb', (gltf) => {
  playerMesh = gltf.scene
  scene.add(playerMesh)
}

角色加载进来后,如何让她移动呢?使用playerMesh.translateZ()方法,让其在Z轴方向移动,对应到场景中,就是在地面上移动了。那如果碰到墙壁,是不是就不应该让角色继续前进了呢?所以要实现碰撞检测功能,这里使用Threejs中的Raycaster射线检测来实现。

window.addEventListener('keydown', (e) => {

if (e.key === 'w') {

const curPos = playerMesh.position.clone(); //获取角色当前位置

playerMesh.translateZ(1);//让角色往前走一步

const frontPos = playerMesh.position.clone();//在获取现在的位置

playerMesh.translateZ(-1 );//退回原来的位置

const frontVector3 = frontPos.sub(curPos).normalize()//让前面位置的向量减去后面位置的向量

const raycasterFront = new THREE.Raycaster(playerMesh.position.clone().add(playerHalfHeight), frontVector3);

const collisionResultsFrontObjs = raycasterFront.intersectObjects(scene.children);

if (collisionResultsFrontObjs && collisionResultsFrontObjs[0] && collisionResultsFrontObjs[0].distance > 1) { // 距离大于1才可以继续前进

playerMesh.translateZ(0.1);

}

}
if (e.key === 's') {//后退
playerMesh.translateZ(-0.1);
}
})

到这里,展馆的基本功能就实现完了。

加入猿创营 (v:dashuailaoyuan),一起交流学习

转载自:https://juejin.cn/post/7188801712877436988
评论
请登录