React+Threejs+Swiper如何實現全景圖效果

這篇“React+Threejs+Swiper如何實現全景圖效果”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“React+Threejs+Swiper如何實現全景圖效果”文章吧。

十多年的江口網站建設經驗,針對設計、前端、開發、售后、文案、推廣等六對一服務,響應快,48小時及時工作處理。成都營銷網站建設的優勢是能夠根據用戶設備顯示端的尺寸不同,自動調整江口建站的顯示方式,使網站能夠適用不同顯示終端,在瀏覽器中調整網站的寬度,無論在任何一種瀏覽器上瀏覽網站,都能展現優雅布局與設計,從而大程度地提升瀏覽體驗。成都創新互聯公司從事“江口網站設計”,“江口網站推廣”以來,每個客戶項目都認真落實執行。

全景效果實現

??有了上面的提示,對 threejs 有一點了解的小伙伴可能就猜出來了,這個全景效果其實就是使用一個球體實現的~ 而我們只是在球體表面上貼了一張紋理貼圖而已(滾輪向外滾就可以看到這個球體了,看上去像個玻璃球,怪好看的,還有個彩蛋?(好吧,說出來就不是彩蛋了)):

React+Threejs+Swiper如何實現全景圖效果

??初始時,我們的視角在球體正中心,視角的移動則是依靠 threejs 提供的工具 OrbitControls 來控制。

??那么創建這個球體的代碼如下:

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 作為參數,我們就可以通過當前激活的元素來獲取圖片并替換球體的紋理貼圖了:

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 編碼。

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 有一定了解的同學我相信實現這么一個效果并不難,代碼量也很小~

完整代碼

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+Threejs+Swiper如何實現全景圖效果
URL網址:http://m.kartarina.com/article10/jedcdo.html

成都網站建設公司_創新互聯,為您提供品牌網站建設搜索引擎優化Google電子商務網站營銷

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

h5響應式網站建設
主站蜘蛛池模板: 精品人妻无码专区中文字幕 | 久久久久无码精品国产| 无码视频一区二区三区| (无码视频)在线观看| 国产午夜无码精品免费看动漫| 人妻无码αv中文字幕久久琪琪布| 色综合热无码热国产| 亚洲AV无码久久精品成人| 麻豆人妻少妇精品无码专区| 亚洲av无码一区二区三区不卡| 无码少妇一区二区浪潮免费| 亚洲精品无码久久一线| 国产成人亚洲精品无码AV大片 | 国产品无码一区二区三区在线蜜桃| 人妻夜夜添夜夜无码AV| 精品久久久久久无码国产| 亚洲日韩国产二区无码| 无码中文字幕乱在线观看| 中国无码人妻丰满熟妇啪啪软件| 无码少妇A片一区二区三区| 中文无码字慕在线观看| 免费无码av片在线观看| 日韩免费无码视频一区二区三区 | 色噜噜综合亚洲av中文无码| 惠民福利中文字幕人妻无码乱精品 | 亚洲国产精品无码AAA片| 成人免费无码大片A毛片抽搐| 亚洲AV无码久久久久网站蜜桃 | 日韩精品久久无码人妻中文字幕| 国产福利电影一区二区三区久久老子无码午夜伦不 | 无码8090精品久久一区| 亚洲aⅴ无码专区在线观看| 中文字幕无码免费久久99| 久久久无码精品亚洲日韩按摩 | 国产精品无码专区AV在线播放| 精品无码久久久久国产动漫3d | 无码中文av有码中文a| 国产成人无码免费看视频软件| 久久精品中文无码资源站| 国产成人无码免费看视频软件| 一夲道dvd高清无码|