Afin d'obtenir un effet panoramique 3D entièrement tridimensionnel, nous utilisons le logiciel Krpano
pour convertir fisheye ordinaire L'image est rendue sous forme d'un panorama à 720°
Remarque : Le code a été ajusté et son exécution n'est pas garantie. Il explique principalement l'idée d'implémentation.
Téléchargez d'abord le logiciel de génération de panorama Krpano, qui comprend la version Linux
et la version Win
ainsi qu'un simple fichier manuel d'utilisation.
En fait, il est simple à utiliser en seulement deux étapes. La première étape consiste à générer les images nécessaires à l'affichage du panorama à partir des images téléchargées. La deuxième étape consiste à afficher le panorama selon les règles et la configuration d'affichage du panorama. fichiers.
[Recommandations associées : Les 10 derniers tutoriels vidéo thinkphp]
Télécharger des images et générer des panoramas
Le principe est très bon Simple, téléchargez l'image sur le serveur, puis utilisez l'image du serveur pour générer un panorama via le logiciel Krpano
, et transférez l'image générée vers un répertoire unifié.
Avant de commencer à télécharger des images, vous devez modifier le Krpano
fichier de configuration Krpano/templates/normal.config
comme suit :
# krpano 1.19 # 引入基本设置 include basicsettings.config # 全景图类型 自动 如果可以识别自动,不能识别图片会询问处理方法 panotype=autodetect hfov=360 # 输出设置 flash=true html5=true # convert spherical/cylindrical to cubical converttocube=true converttocubelimit=360x45 # multiresolution settings multires=true maxsize=8000 maxcubesize=2048 # 输出图片路径 tilepath=%INPUTPATH%/pano/%BASENAME%.tbs-pano/3d-pano-[c].jpg # 输出预览图图片设置 preview=true graypreview=false previewsmooth=25 previewpath=%INPUTPATH%/pano/%BASENAME%.tbs-pano/3d-pano-preview.jpg # 输出缩略图图片设置 makethumb=true thumbsize=240 thumbpath=%INPUTPATH%/pano/%BASENAME%.tbs-pano/3d-pano-thumb.jpg
Le code de l'interface de téléchargement est le suivant :
public function upload_3d_pic() { $file = $_FILES["imgUpload"]; $u_name =$file['name']; $u_temp_name =$file['tmp_name']; $u_size =$file['size']; // 生成 一个随机字符串 $str = null; $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123tbs456789abcdefghijklmnopqrstuvwxyz"; $max = strlen($strPol)-1; for($i=0;$i<$length;$i++){ $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数 } //$md5Code 会做为文件夹的名字 跟文件的名字,要保持唯一性 $md5Code =md5_16bit(hash("sha256",$u_name.time().$rand_char)).$str; $datePath =date("Y-m-d",time()); $root_path ='./upload_3dpic/'; $url_path ='/upload_3dpic/'; //外部访问url $f_up_to_path =$root_path .'/'. $datePath.'/'.$md5Code; if(!file_exists($f_up_to_path)){ mkdir($f_up_to_path, 0777, true); } $type = strtolower(substr($u_name, strrpos($u_name, '.') + 1)); $img_file_name =$md5Code."." . $type; $saveFileName = $f_up_to_path."." . $type; $true_img_url =$url_path . $datePath.'/'.$md5Code."." . $type; //外部访问链接 if (!move_uploaded_file($u_temp_name, $saveFileName)) { $this->ajaxReturn(array("error_code"=>250,"msg"=>"图片上传失败,请稍后重试!","return"=>"move pic fail>>temp_name=".$u_temp_name.">>save file name=".$saveFileName)); } else { @rmdir($f_up_to_path); } //判断文件是否存在 if(file_exists($saveFileName)){ //如果存在 则生成 全景图 $this->create_pano_pic($saveFileName); // 如果 此时没有生成图片 需要删除上传图片并报错 平面图可能生成不了图片 $dirName = dirname($saveFileName) . '/pano' . '/' . $md5Code . '.tbs-pano'; if ( !file_exists($dirName) ) { unlink($saveFileName); // 删除文件 $this->ajaxReturn(array('error_code'=>250,"msg"=>"上传图片不能生成全景图")); } //移动全景图到指定的目录 图片在哪里全景图将会生成在那个目录 $mvres = $this->mv_to_pano_path($saveFileName,$img_file_name); if ( $mvres === false ) { $this->ajaxReturn(array('error_code'=>250,"msg"=>"移动文件失败")); } }else{ $this->ajaxReturn(array('error_code'=>250,"msg"=>"img not exists!",'img_url'=>$true_img_url)); } // 移动后的缩略图路径 $thumb_url = $url_path . 'TreeDPic/' . $md5Code . '/pano/' . $md5Code . '.tbs-pano/3d-pano-thumb.jpg'; $this->ajaxReturn(array( 'error_code'=>0, 'msg'=>"sucess", 'img_url'=>$true_img_url, "pano_name"=>$md5Code, 'thumb_url'=>$thumb_url) ); } /*** * @param string $img_path * @return string * 将当前传入的图片 渲染成为全景图 */ private function create_pano_pic($img_path="") { if(empty($img_path)){ return $img_path; } if(!file_exists($img_path)){ return "图片不存在!"; } //软件注册码 $r_code ="Krpano的注册码"; $pano_path=C("KRPANO_PATH"); //krpano 路径 自己配置 $pano_tools ="krpanotools"; //krpano 生成图片的命令 $dealFlat = ''; // 处理 非球面图 if(PHP_OS == 'WINNT'){ $pano_path=$pano_path."Win"; $pano_tools ="krpanotools32.exe"; } else { // 上传平面图时 直接跳过图片生成 否则会一直等待 $dealFlat = 'echo -e "0\n" | '; } $kr_command = $dealFlat . $pano_path . "/".$pano_tools." makepano -config=" . $pano_path . "/templates/normal.config "; try{ //在生成图片之前 先注册一下码,要不生成的全景图会有水印 exec( $pano_path . '/'.$pano_tools.' register ' .$r_code); $kr_command =$kr_command.$img_path; //执行生成图片命令 exec($kr_command, $log, $status); } catch (\Exception $e){ $this->ajaxCallMsg(250,$e->getMessage()); } return true; } /** * @param $pano_img_path * @return string * 全景图生成后再调用这个方法,把全景图移到对应的目录供 xml 文件获取内容 */ private function mv_to_pano_path($pano_img_path,$img_name){ $ig_name =explode(".",$img_name)[0]; $root_path = './upload_3dpic/'; if(!file_exists($pano_img_path) ||empty($pano_img_path)){ $this->up_error_log($pano_img_path.'》》图片路径文件不存在'); return ''; } $now_path =dirname($pano_img_path);//获取当前文件目录 if ($dh = @opendir($now_path)){ //打开目录 while (($file = readdir($dh)) !== false){ //循环获取目录的 文件 if (($file != '.') && ($file != '..')) { //如果文件不是.. 或 . 则就是真实的文件 if($file=="pano"){ //全景图切片目录 $t_d_path =$root_path .'TreeDPic/'. $ig_name; if(!file_exists($t_d_path)){ //不存在就创建 @mkdir($t_d_path, 0777, true); } if(file_exists($t_d_path.'/'.$file)){ //判断是否已经存在 当前名字的 全景图 文件 return false; }else{ //否则就 把 当前上传的生成 的全景文件切片,移动到指定的目录 rename($now_path.'/'.$file,$t_d_path.'/'.$file); } }else if ($file !==$img_name){ //删除不是 原图片的文件 if(is_dir($file)){ $this->deleteDir($now_path.'/'.$file); }else{ @unlink($now_path.'/'.$file); } }else{ return false; } } } closedir($dh); }else{ return false; } } /** * @param $dir * @return bool * 删除文件夹及文件 */ private function deleteDir($dir) { if (!$handle = @opendir($dir)) { return false; } while (false !== ($file = readdir($handle))) { if ($file !== "." && $file !== "..") { //排除当前目录与父级目录 $file = $dir . '/' . $file; if (is_dir($file)) { $this->deleteDir($file); } else { @unlink($file); } } } @rmdir($dir); }
À ce stade, nous pouvons télécharger des images via l'interface de téléchargement et restituer les images en panoramas via Krpano
.
Afficher le panorama
Pour afficher l'image, il faut générer leKrpano
fichier de configuration nécessaire selon lesxml
règles.
Nous générerons un panorama basé sur le code unique généré à partir de l'image téléchargée.
// 解析XML文件 public function panorama_xml(){ $code =I("code"); $cutNum =intval(I("cutNum")); $url_path = '/upload_3dpic/'; // 切割模式分为 6图 和 12图 if(!in_array($cutNum,array(6,12))){ $this->error(); } $this->echoSixXml($url_path,$code); } private function echoSixXml($url_path,$code=""){ echo "<krpano version=\"1.19\" title=\"Virtual Tour\"> <!-- the skin --> <!-- <include url=\"/3dpic/pano/sixDefaultXml/\" />--> <!-- 视图设置 <view hlookat=\"0\" vlookat=\"0\" maxpixelzoom=\"1.0\" fovmax=\"150\" limitview=\"auto\" /> --> <skin_settings maps=\"false\" maps_type=\"google\" maps_bing_api_key=\"\" maps_google_api_key=\"\" maps_zoombuttons=\"false\" gyro=\"true\" webvr=\"true\" webvr_gyro_keeplookingdirection=\"false\" webvr_prev_next_hotspots=\"true\" littleplanetintro=\"false\" title=\"true\" thumbs=\"true\" thumbs_width=\"120\" thumbs_height=\"80\" thumbs_padding=\"10\" thumbs_crop=\"0|40|240|160\" thumbs_opened=\"false\" thumbs_text=\"false\" thumbs_dragging=\"true\" thumbs_onhoverscrolling=\"false\" thumbs_scrollbuttons=\"false\" thumbs_scrollindicator=\"false\" thumbs_loop=\"false\" tooltips_buttons=\"false\" tooltips_thumbs=\"false\" tooltips_hotspots=\"false\" tooltips_mapspots=\"false\" deeplinking=\"false\" loadscene_flags=\"MERGE\" loadscene_blend=\"OPENBLEND(0.5, 0.0, 0.75, 0.05, linear)\" loadscene_blend_prev=\"SLIDEBLEND(0.5, 180, 0.75, linear)\" loadscene_blend_next=\"SLIDEBLEND(0.5, 0, 0.75, linear)\" loadingtext=\"loading...\" layout_width=\"100%\" layout_maxwidth=\"814\" controlbar_width=\"-24\" controlbar_height=\"40\" controlbar_offset=\"20\" controlbar_offset_closed=\"-40\" controlbar_overlap.no-fractionalscaling=\"10\" controlbar_overlap.fractionalscaling=\"0\" design_skin_images=\"vtourskin.png\" design_bgcolor=\"0x2D3E50\" design_bgalpha=\"0.8\" design_bgborder=\"0\" design_bgroundedge=\"1\" design_bgshadow=\"0 4 10 0x000000 0.3\" design_thumbborder_bgborder=\"3 0xFFFFFF 1.0\" design_thumbborder_padding=\"2\" design_thumbborder_bgroundedge=\"0\" design_text_css=\"color:#FFFFFF; font-family:Arial;\" design_text_shadow=\"1\" /> <scene name=\"{$code}\" title=\"{$code}\" onstart=\"\" thumburl=\"{$url_path}TreeDPic/{$code}/pano/{$code}.tbs-pano/3d-pano-thumb.jpg\" lat=\"\" lng=\"\" heading=\"\"> <view hlookat=\"0.0\" vlookat=\"0.0\" fovtype=\"MFOV\" fov=\"120\" maxpixelzoom=\"2.0\" fovmin=\"70\" fovmax=\"140\" limitview=\"range\" vlookatmin=\"-58.156\" vlookatmax=\"58.156\" /> <preview url=\"{$url_path}TreeDPic/{$code}/pano/{$code}.tbs-pano/3d-pano-preview.jpg\" /> <image type=\"CUBE\" multires=\"true\" tilesize=\"512\"> <cube url=\"{$url_path}TreeDPic/{$code}/pano/{$code}.tbs-pano/3d-pano-%s.jpg\" /> </image> </scene> <!--<preview url=\"{$url_path}TreeDPic/{$code}/pano/{$code}.tbs-pano/preview.jpg\" />--> <image> <cube url=\"{$url_path}TreeDPic/{$code}/pano/{$code}.tbs-pano/3d-pano-%s.jpg\" /> </image> </krpano>"; }
Le scene
ne rend pas le rendu actuel, mais est automatiquement déclenché par DOM.call("toggle_item_hotspots();");
lorsque nous sélectionnons entre plusieurs panoramas.
Définissez l'itinéraire et la méthode d'affichage de la page :
public function panorama(){ //先 获取id (md5值) $code =trim(I("code")); //图片切割方式 6图(采集的是6图) 和12图(比较复杂建议生成图片 用6图 配置切割) $cutNum =intval(I("cutNum")); $this->assign("codeVal",$code); $this->assign("cutNum",$cutNum); $this->display(); }
Dans le fichier de vue correspondant :
<!DOCTYPE html> <html> <head> <title>土拨鼠全景漫游图 - {$pageData.title}</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, viewport-fit=cover" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" /> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <meta http-equiv="x-ua-compatible" content="IE=edge" /> <link rel="stylesheet" href="{$Think.TBS_STATIC}/common/css/new_base.css?v=1560493706" /> <link rel="stylesheet" href="/res/impression/vtour/pc/krpano.css"/> <style> @-ms-viewport { width:device-width; } @media only screen and (min-device-width:800px) { html { overflow:hidden; } } html { height:100%; } body { height:100%; overflow:hidden; margin:0; padding:0; font-family:Arial, Helvetica, sans-serif; font-size:16px; color:#FFFFFF; background-color:#000000; } .loading{ /* display: none; */ width: 100%; height: 100%; position: absolute; top: 0; left: 0; z-index: 3; background-color: #fff; color:#333; z-index: 100; } .loadingimg { width: 184px; height: 108px; position: absolute; top: 50%; left: 50%; -webkit-transform: translateX(-50%) translateY(-50%); -moz-transform: translateX(-50%) translateY(-50%); -ms-transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%); text-align: center; } .loadingimg img { width: 100%; height: 100%; } .poiner { display: inline-block; width: 16px; vertical-align: bottom; overflow: hidden; /* animation: poiner 3s infinite step-start; */ } </style> </head> <body> <script src="vtour/tour.js"></script> <p class="loading"> <p class="loadingimg"> <img src="{$Think.TBS_STATIC}/impression/vtour/img/loading.png"> <p>加载中</p> </p> </p> <p id="pano" style="width:100%;height:100%;"> </p> </body> <script> // var krpano = null; embedpano({ swf: "{$Think.TBS_STATIC}/impression/vtour/tour.swf?v={$Think.CDNTIME}", xml: "/3dpic/panoxml/{$cutNum}_{$codeVal}", target: "pano", html5: "auto", mobilescale: 1.0, passQueryParameters: true, }); </script> <script type="text/javascript" src="vtour/krpano.js"></script> </html>
Modifiez le chemin du fichier de ressources statique correspondant en fonction de votre projet. A cette époque, notre panorama est déjà visible.