上传图片转成3D VR效果 / VR效果在项目中落地实践 / 应用到了用photo-sphere-viewer + A-Frame +Threejs 通过不同的技术分别实现了3D VR效果

article/2025/8/16 3:29:18

系统简介 : 该系统为 react + TS + tailwindcss 响应式系统 , 上传图片后可实现手动旋转 3D 图片,还包含了 6 贴图立方体展示和 6 贴图动态展示

项目亮点 : 包含主流3D VR库 , 可根据具体需求选择具体的技术栈

全部页面概览

这是单面VR页面的代码(gif展示页面)

import React, { useRef, useState, useEffect } from 'react'
import { Viewer } from 'photo-sphere-viewer'
import 'photo-sphere-viewer/dist/photo-sphere-viewer.css'import { PlusOutlined } from '@ant-design/icons'
import { Image, Upload } from 'antd'
import type { GetProp, UploadFile, UploadProps } from 'antd'type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0]const getBase64 = (file: FileType): Promise<string> =>new Promise((resolve, reject) => {const reader = new FileReader()reader.readAsDataURL(file)reader.onload = () => resolve(reader.result as string)reader.onerror = error => reject(error)})export default function VrUploader () {const [selectedFileUrl, setSelectedFileUrl] = useState('')const [confirmedImageUrl, setConfirmedImageUrl] = useState('')const viewerRef = useRef<HTMLDivElement | null>(null)const viewerInstance = useRef<Viewer | null>(null)const [previewOpen, setPreviewOpen] = useState(false)const [previewImage, setPreviewImage] = useState('')const [fileList, setFileList] = useState<UploadFile[]>([])const handlePreview = async (file: UploadFile) => {if (!file.url && !file.preview) {file.preview = await getBase64(file.originFileObj as FileType)}setPreviewImage(file.url || (file.preview as string))setPreviewOpen(true)}const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {// 始终只保留最后一张图片const latestFileList = newFileList.slice(-1)setFileList(latestFileList)if (latestFileList.length > 0) {const file = latestFileList[0].originFileObj as Fileconst url = URL.createObjectURL(file)setSelectedFileUrl(url)} else {setSelectedFileUrl('')setConfirmedImageUrl('')}}const uploadButton = (<button style={{ border: 0, background: 'none' }} type='button'><PlusOutlined /><div style={{ marginTop: 8 }}>上传</div></button>)const handleConfirm = () => {if (selectedFileUrl) {setConfirmedImageUrl(selectedFileUrl)}}const handleCancel = () => {setFileList([])setSelectedFileUrl('')setConfirmedImageUrl('')// 销毁 Viewer 实例并清空引用if (viewerInstance.current) {viewerInstance.current.destroy()viewerInstance.current = null}}const [isRetote, setIsRetote] = useState(false) // 是否旋转const handleRetote = () => {setIsRetote(prev => {const newState = !previf (viewerInstance.current) {if (newState) {viewerInstance.current.startAutorotate()} else {viewerInstance.current.stopAutorotate()}}return newState})}useEffect(() => {if (confirmedImageUrl && viewerRef.current) {if (viewerInstance.current) {viewerInstance.current.setPanorama(confirmedImageUrl)} else {viewerInstance.current = new Viewer({container: viewerRef.current, //必---html元素信息panorama: confirmedImageUrl, //必---图片路径description: '<p>This is a description.</p>'})}}}, [confirmedImageUrl])return (<div className='p-4 cursor-pointer'><div className='bg-gray-100 flex items-center justify-center w-100'><div className='min-w-[70%]'><h2 className='text-2xl font-bold mb-4 mt-4'><p>单图上传</p><p>VR 生成(photo-sphere-viewer)</p></h2><div className='grid grid-cols-2 md:grid-cols-3 gap-4 mb-4'><Uploadaction='https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload'listType='picture-card'fileList={fileList}onPreview={handlePreview}onChange={handleChange}>{fileList.length >= 8 ? null : uploadButton}</Upload>{previewImage && (<ImagewrapperStyle={{ display: 'none' }}preview={{visible: previewOpen,onVisibleChange: visible => setPreviewOpen(visible),afterOpenChange: visible => !visible && setPreviewImage('')}}src={previewImage}/>)}</div>{/* 按钮区域 */}<div className='flex w-full justify-between'><buttononClick={handleConfirm}disabled={!selectedFileUrl}className={`px-4 py-2 rounded-md text-white ${selectedFileUrl? 'bg-blue-600 hover:bg-blue-700': 'bg-gray-400 cursor-not-allowed'}`}>生成 VR</button><buttononClick={handleRetote}className={`px-4 py-2 rounded-md text-white bg-green-600 hover:bg-green-700`}>{!isRetote ? '开始巡检' : '停止巡检'}</button><buttononClick={handleCancel}className={`px-4 py-2 rounded-md text-white bg-red-600 hover:bg-red-700`}>重置图片</button></div>{/* VR区域 */}<divclassName='h-[50vh] w-full bg-black mt-6 rounded overflow-hidden mb-6'ref={viewerRef}>{!selectedFileUrl && (<p className='text-white p-4'>请上传一张比例为2:1 / 圆形图</p>)}</div></div></div></div>)
}

完整代码 : GitHub - hyy20000804/Img-to-VR: 响应式图片转VR系统

遇到的问题总结: 

一.在单图 VR 模块

1.photo-sphere-viewer 目前 v5 版本不稳定,npm 中最新版本为 4.8.1,官网地址 https://photo-sphere-viewer.js.org/ 要切换为 v4 版本

2.默认配置器选择为等距矩形可处理等矩形图(2:1 的比例)和圆形图(正方形圆形),当传递手机拍摄的照片(9:16/3:4 的比例)时会存在 VR 效果不太完美的情况

3.自动旋转功能(即项目中的"开始巡检")也是通过 v4 的写法实现,如果按照 v5 官网写法会报错

二.在俩个多图 VR 模块中

6 张贴图尺寸不一时会报错警告


http://www.hkcw.cn/article/sHSTfWkbmt.shtml

相关文章

鸿蒙NEXT应用加固工具哪家更好?国内主流的6款对比

随着鸿蒙NEXT系统的推进&#xff0c;越来越多企业将目光投向鸿蒙生态下的应用部署与数据安全。尤其是在核心业务App逐步上架鸿蒙原生平台的当下&#xff0c;如何实现高效、可靠的鸿蒙NEXT应用安全加固&#xff0c;已成为企业技术选型的关键环节。本文将对市面上6款主流的鸿蒙NE…

包粽子日赚500元 传统手艺撬动就业新机遇

包粽子日赚500元 传统手艺撬动就业新机遇!临近端午,粽香四溢的背后,一场关于传统手艺与市场需求的“双向奔赴”正在上演。掌握包粽技艺的年轻人正以“一叶一技”撬动就业新机遇。非遗手艺不仅成为节令经济的热门选择,还催生了产业链条上的多元岗位,比如有外语能力的大学生…

英伟达被曝将在华新建设施 引发美议员安全担忧

英伟达被曝将在华新建设施 引发美议员安全担忧。美国半导体巨头英伟达CEO黄仁勋多次强调,美国对华芯片管制不仅没有成功,反而促使中国加速自主研发芯片的进程。然而,美国议员对此并未采纳,反而针对英伟达在中国的新布局提出质疑。据彭博社和《华尔街日报》报道,英伟达计划…

高盛总裁:债市对美国债务更担心 财政恶化风险加剧

高盛总裁:债市对美国债务更担心 财政恶化风险加剧!高盛总裁John Waldron表示,目前宏观层面的最大风险并不是关税。尽管所有注意力都集中在关税上,但债券市场的关注点正转向美国减税方案和财政状况,这令人担忧。有分析人士指出,债券投资者正在为财政恶化的更高风险定价,他…

LINUX中TOMCAT安装和Nginx源码安装

一&#xff1a;web服务器 1、Web服务器介绍 ‌Web服务器是一种运行于互联网上的计算机硬件或软件&#xff0c;用于存储、处理和传输网页和其他网站内容。‌ 它通常运行在服务器上&#xff0c;绑定服务器的IP地址并监听某一个TCP端口&#xff0c;接收来自客户端的请求&#x…

解密Linux权限管理:从入门到精通

目录 shell命令及其工作原理 用户切换 sudo 权限 是什么&#xff1f; 为什么&#xff1f; 怎么办&#xff1f; 目录权限怎么理解 &#xff1f; 缺省权限 1.umask 的目的是什么&#xff1f; 2.为什么要有umask 粘滞位 shell命令及其工作原理 Shell的最简单定义&#…

ROS云课基础篇-01-Linux-250529

ROS云课基础篇收到了很多反馈&#xff0c;正面评价比例高&#xff0c;还有很多朋友反馈需要写更具体一点。 ROS云课基础篇极简复习-C、工具、导航、巡逻一次走完-CSDN博客 于是&#xff0c;有了这篇以及之后的案例&#xff0c;案例均已经测试过8年&#xff0c;但没有在博客公…

贵州一公路巨石砸中汽车 司机轻伤车辆受损

5月28日,贵州毕节市七星关区何官屯镇一条通村公路突发落石。一块约300斤重的巨石砸中一辆过路汽车,导致车辆从路边高坎坠落。司机受轻伤,送医检查后当日返家,车损由保险公司处理。落石还击碎了附近民房的玻璃门,但无人受伤。事发地为地质灾害点,连续下雨诱发了这次事故。…

向武汉理工大学捐赠1分钱也有证书 培养捐赠意识

向武汉理工大学捐赠1分钱也有证书 培养捐赠意识!近日,武汉理工大学发起了一项名为“527生日捐”的活动,庆祝学校合并组建25周年。一些校友晒出了捐赠1分钱后获得的电子证书,引起了网友的关注。校方表示,该活动不限捐赠金额,主要目的是让大家参与进来,培养捐赠意识。有武…

Python打卡训练营-Day13-不平衡数据的处理

浙大疏锦行 知识点&#xff1a; 不平衡数据集的处理策略&#xff1a;过采样、修改权重、修改阈值交叉验证代码 过采样 过采样一般包含2种做法&#xff1a;随机采样和SMOTE 过采样是把少的类别补充和多的类别一样多&#xff0c;欠采样是把多的类别减少和少的类别一样 一般都是缺…

嵌入式学习笔记 - freeRTOS任务优先级抢占,时间片抢占的实现机制

一 任务优先级、时间片抢占 已经知道freeRTOS的任务切换函数发生在systick中断中&#xff0c;如下图 由上图可见&#xff0c;任务切换有个先决条件TaskIncrementTick&#xff08;&#xff09;函数返回为1&#xff0c;这个函数如下图&#xff0c; 函数返回值为xSwitchRequired&…

西方国家对乌军援,再加码 张学峰:俄乌双方的较量还将持续一段时间:局势再添变数

德国新任总理默茨近日表示,德国等西方国家已全面解除对援乌远程武器的射程限制,允许乌克兰使用其提供的武器打击俄罗斯境内纵深军事目标。对此,俄罗斯总统新闻秘书佩斯科夫回应称,这一决定与俄方寻求和平解决冲突的努力背道而驰。默茨上任以来,在是否向乌克兰提供“金牛座…

钟南山谈新冠后肺结节患者增多 CT检查增加发现更多

钟南山谈新冠后肺结节患者增多 CT检查增加发现更多!我国约有1.5亿肺结节高危人群,每年新检出的肺结节病例达1000万至2000万。新冠疫情后肺结节检出率显著上升的原因之一是新冠后做CT的人数大幅增加,进而让更多的肺结节被发现。中国工程院院士钟南山表示,环境污染等也会导致…

油价或将上调 6月3日24时调整

油价或将上调 6月3日24时调整!成品油价将于6月3日24时进行调整。今日油价上涨,涨幅有所变动,国内油价整体呈上涨趋势,但接近搁浅。目前全国大部分地区的油价处于6元时代。下一次调价日期为6月3日晚24时。以下是今日油价概览:此外,可以参考历年油价走势以了解更多信息。责…

金靖张凌赫怨种姐弟又开始发力 两人互斗引热议

凌赫啊你小子又开始皮了,放弃吧牛牛你是斗不过金靖的允悲允悲允悲她那张嘴多会说,脑子还快,简直是血脉压制,你只能哞哞叫哈哈哈哈每周都等着看这俩姐弟的新乐子,太有意思了!责任编辑:zx0002

天降纸尿裤砸碎小车挡风玻璃 肇事者一直没有现身

5月23日,江门市蓬江区的周先生说他的爱车停放在小区楼下停车位,结果竟被一大袋用过的纸尿片砸中。这些浸湿的纸尿片重量惊人,周先生的车顶被砸凹,挡风玻璃也被砸碎了,车辆的维修费花了近6千元,事发已经过去多日,可肇事者一直没有现身。周先生说,报警已经多日,派出所一…

中国学生美国梦碎 签证政策引发留学困境

5月28日,特朗普政府威胁要吊销约27.7万名中国学生中的许多人的签证,并对来自中国内地和香港的未来申请者进行额外审查。这一消息让刚从美国驻北京大使馆走出来的18岁学生李昆泽感到焦虑。他刚刚成功申请到本科留学签证,但现在情况突变,时间紧迫,无法再申请其他国家的留学机…

《歌手2025》首轮袭榜赛制公布 投票截止前1小时隐藏票数

5月30日,湖南卫视歌手发布第二场揭榜赛制:微博网友可从7位在线歌手陈楚生、MickeyGuyton、GAI周延、白举纲、格瑞丝金斯勒、单依纯、马嘉祺中,为袭榜歌手查理普斯选择1位对决对象。截止至今天17:00,网友推荐次数最高的歌手将作为守榜歌手,在节目中与袭榜歌手进行1V1对决。…

余华回应刘楚昕获奖 感动与坚持的力量

人的一生会经历很多痛苦,但回首想起来都是传奇。近日,90后作家刘楚昕创作的小说《泥潭》获得了漓江文学奖虚构类奖。在发表获奖感言时,他哽咽着分享了和病故女友的故事,让不少网友潸然泪下。许多人表示,开头以为是“狗粮”,结局竟然是“刀子”。在现场听完刘楚昕的获奖感…

李兆杰教授因病逝世 法学界痛失领军人物

5月29日晚,清华大学法学院发布讣告,沉痛悼念李兆杰教授。李兆杰教授于2025年5月29日在北京因病逝世,享年70岁。李兆杰教授是汉族,籍贯山东省东明县,1955年出生于吉林省长春市。他曾在北京大学国际法研究所和清华大学法学院任教。作为改革开放以来我国新一代国际法学者中的…