我是靠谱客的博主 高兴超短裙,这篇文章主要介绍React + Threejs + Swiper 实现全景图效果,现在分享给大家,希望可以做个参考。

  咱先看看全景图实现效果:展示地址
  截图:
全景图

  体验了一下是不是感觉周围环境转了一圈,感觉世界是圆的?????
  没错!恭喜你答对了!地球就是圆的!????

全景效果实现

  有了上面的提示,对 threejs 有一点了解的小伙伴可能就猜出来了,这个全景效果其实就是使用一个球体实现的~ 而我们只是在球体表面上贴了一张纹理贴图而已(滚轮向外滚就可以看到这个球体了,看上去像个玻璃球,怪好看的,还有个彩蛋????(好吧,说出来就不是彩蛋了)):
在这里插入图片描述

  初始时,我们的视角在球体正中心,视角的移动则是依靠 threejs 提供的工具 OrbitControls 来控制。

  那么创建这个球体的代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
const geometry = new THREE.SphereBufferGeometry(500, 32, 32); geometry.scale(-1, 1, 1); // 将纹理反贴 const material = new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load(imglist[0].default) // 传入图片的URL或者路径,也可以是 Data URI. }); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh); const controls = new OrbitControls(camera, renderer.domElement); controls.enablePan = false; controls.maxDistance = 1000;

不知道 Data URI 是什么的可以看看 MDN 文档

轮播图

  轮播图实现则是使用 swiper 这个库,使用起来非常方便,具体可自行查阅文档。
  在滑动轮播图时,会触发一个 onSliderChange 事件,这个事件传入当前的 swiper 作为参数,我们就可以通过当前激活的元素来获取图片并替换球体的纹理贴图了:

复制代码
1
2
3
4
5
6
onSliderChange = curSwiper => { const mesh = this.mesh; const texture = imglist[curSwiper.activeIndex].default; mesh.material.map = new THREE.TextureLoader().load(texture); };

  下面是我的 swiper 设置,其中 SwiperSlider 是一个可滑动的轮播图卡片,EffectCoverflow 是滑动时触发的效果,swiper 中提供了四种可选效果:Fade、Coverflow、Flip 以及 Cube。imglist 则是一组图片,其中 imglist[i].default 属性保存了图片的 base64 编码。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Swiper, SwiperSlide } from 'swiper/react'; import SwiperCore, { EffectCoverflow } from 'swiper'; import 'swiper/swiper.min.css'; import 'swiper/components/effect-coverflow/effect-coverflow.min.css'; SwiperCore.use([EffectCoverflow]); //.... <Swiper className='panoramic-imgs' spaceBetween={50} // 间距 slidesPerView={3} // 轮播图里可预览图片数 onSlideChange={this.onSliderChange} // 滑动时触发的回调 onSwiper={(swiper) => console.log(swiper)} // 初始加载时触发的回调 direction='vertical' // 轮播图方向,默认是水平 horizontal effect={'coverflow'} // 滑动效果 grabCursor={true} // 鼠标放在轮播图上是否显示拖拽 centeredSlides={true} // 当前处于激活状态的图片是否要居中 coverflowEffect={{ // coverflow 效果参数设置,可自行调整 "rotate": 50, "stretch": 0, "depth": 100, "modifier": 1, "slideShadows": true }} > { imglist.map((img, idx) => { return <SwiperSlide key={idx}> <img src={img.default} className='panoramic-img'></img> </SwiperSlide> }) } </Swiper>

  全景效果的实现就说到这了,当然,如果什么地方有疑问可以留言或者参考我的代码(下面贴出来),只要对 threejs 和 react 有一定了解的同学我相信实现这么一个效果并不难,代码量也很小~

完整代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import React, { Component } from 'react'; import Layout from '@theme/Layout'; import Head from '@docusaurus/Head'; import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; import * as _ from 'underscore'; import { message } from 'antd'; import { Swiper, SwiperSlide } from 'swiper/react'; import SwiperCore, { EffectCoverflow } from 'swiper'; import 'swiper/swiper.min.css'; import 'swiper/components/effect-coverflow/effect-coverflow.min.css'; import './index.css'; import imgs from './imgs.json'; SwiperCore.use([EffectCoverflow]); const imglist = imgs.map(img => { return require('../../../static/img/panoramic/' + img.name); }); export default class Panormatic extends Component { constructor() { super(); this.renderer = null; this.camera = null; this.scene = null; this.container = null; this.controls = null; this.showMessage = true; // 彩蛋提示 } componentDidMount() { const container = document.getElementById('panoramic-canvas-container'); const canvas = document.getElementById('panoramic-canvas'); const renderer = new THREE.WebGLRenderer({ canvas, antialias: true }); renderer.setClearColor(0xffffff); // b2e0df 绿豆沙色 renderer.setPixelRatio( window.devicePixelRatio ); const height = container.clientHeight; const width = container.clientWidth; renderer.setSize(width, height); const camera = new THREE.PerspectiveCamera(60, width / height, 1, 30000); camera.position.set(0, 0, 1); camera.center = new THREE.Vector3(0, 0, 0); const scene = new THREE.Scene(); const geometry = new THREE.SphereBufferGeometry(500, 32, 32); geometry.scale(-1, 1, 1); // 将纹理反贴 const material = new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load(imglist[0].default) }); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh); const controls = new OrbitControls(camera, renderer.domElement); // controls.enableZoom = false; controls.enablePan = false; controls.maxDistance = 1000; this.renderer = renderer; this.camera = camera; this.scene = scene; this.container = container; this.controls = controls; this.mesh = mesh; // 设置提示框的全局配置 message.config({ top: 100, duration: 3.5, maxCount: 1, }); this.onControlsChange = _.throttle(this.onChange, 100); controls.addEventListener('change', this.onControlsChange); window.addEventListener('resize', this.onWindowResize); this.renderLoop(); } componentWillUnmount() { const mesh = this.mesh; mesh.material.dispose(); mesh.geometry.dispose(); this.scene.remove(mesh); window.removeEventListener('resize', this.onWindowResize); this.controls.removeEventListener('change', this.onControlsChange); message.destroy(); } onChange = (e) => { const camera = this.camera; if (camera.position.distanceTo(camera.center) >= 700) { if (this.showMessage) { message.success('????恭喜你发现了全景效果的小秘密~????'); this.showMessage = false; } } else { this.showMessage = true; } } onSliderChange = (curSwiper) => { const mesh = this.mesh; const texture = imglist[curSwiper.activeIndex].default; mesh.material.map = new THREE.TextureLoader().load(texture); }; onWindowResize = () => { const camera = this.camera; const renderer = this.renderer; const width = this.container.clientWidth; const height = this.container.clientHeight; camera.aspect = width / height; camera.updateProjectionMatrix(); renderer.setSize(width, height); }; renderLoop = () => { this.renderer.render(this.scene, this.camera); requestAnimationFrame(this.renderLoop); }; render() { return ( <Layout> <Head> <title>全景图 | Yle</title> </Head> <div id='panoramic-container'> <Swiper className='panoramic-imgs' spaceBetween={50} slidesPerView={3} onSlideChange={this.onSliderChange} onSwiper={(swiper) => console.log(swiper)} direction='vertical' effect={'coverflow'} grabCursor={true} centeredSlides={true} coverflowEffect={{ "rotate": 50, "stretch": 0, "depth": 100, "modifier": 1, "slideShadows": true }} > { imglist.map((img, idx) => { return <SwiperSlide key={idx}> <img src={img.default} className='panoramic-img'></img> </SwiperSlide> }) } </Swiper> <div id='panoramic-canvas-container'> <canvas id='panoramic-canvas'></canvas> </div> </div> </Layout> ); } }

  觉得对你有帮助的不妨顺手点个赞????

最后

以上就是高兴超短裙最近收集整理的关于React + Threejs + Swiper 实现全景图效果的全部内容,更多相关React内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(74)

评论列表共有 0 条评论

立即
投稿
返回
顶部