我如何创建放大镜效果来放大 three.js 或 babylon.js 3d 场景中的元素?

How might I create a magnifying glass effect to magnify elements in a three.js or babylon.js 3d scene?

很长一段时间以来,我一直在尝试寻找一种方法来创建放大镜效果,该效果将跟随鼠标并放大场景中的元素。类似步枪瞄准镜的东西。有什么想法可以从哪里开始吗?

自然地,在提出问题后,我想到了一个解决方案。虽然不幸的是,它不是我一直在寻找的原生 babylon.js 解决方案,但它仍然有效。它使用 divs 和 jquery 来放大用作 3D space 平面上的 material 的源图像。 诀窍在于 'overtarget' 函数,目标上的鼠标位置已转换为图像高度和宽度的百分比,用于根据该百分比在玻璃内移动放大的 div . 我使用 php 从数据库中获取图像,然后计算其大小,因为这就是我的项目的结构。当然,您可以从任何图像开始,然后手动输入 ht 和 wd。

这是一个演示:http://64.78.15.229/eyemap3Djs/magnify.html

我希望这对某人有用。也许它可以用作游戏中的步枪瞄准镜或类似的东西。

 <?php

 $studyID= $_GET['studyID'];

 $myServer = "[your server]";
 $myUser = "[you]";
 $myPass = "[password]";
 $myDB = "[db]"; 

 $dbhandle = mssql_connect($myServer, $myUser, $myPass)
   or die("Couldn't connect to SQL Server on $myServer"); 
 $selected = mssql_select_db($myDB, $dbhandle)
   or die("Couldn't open database $myDB"); 
 $query = "SELECT * FROM [your table] WHERE id=".$studyID; 

 $result = mssql_query($query);

 $numRows = mssql_num_rows($result); 
 while($row = mssql_fetch_array($result))
 {
     $imageFile= $row["imageFile"];
     $mag= $row["mag"];
 }
 mssql_close($dbhandle);

 $size = getimagesize($imageFile);
 $ht=$size[1];
 $wd=$size[0];

 ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html" charset="utf-8"/>
 <link rel="stylesheet" href="//code.jquery.com/ui/1.12.0/themes/base/jquery-ui.css">
 <style>
     html, body {
      font-family: Verdana, Geneva, sans-serif;
      font-size: 12px;
      color: #333;
      width   : 100%;
      height  : 98%;
      margin  : 0;
      padding : 0;
     }

     #renderCanvas {
      width   : 100%;
      height  : 100%;
      touch-action: none;
      z-index: 100;
     }
     #glass{
      position:absolute; 
      overflow:hidden;
      border:1px solid black;
      border-radius: 50%;
      padding-top: 0px;
      padding-right: 0px;
      padding-bottom: 0px;
      padding-left: 0px;
       pointer-events: none;
      z-index: 100;
      display:none;
     }

    #legend{
      position:absolute;
      font-size:10px;
      font-family:Verdana, Geneva, sans-serif;
      top:10px;
      left:10px;
      height:50px;
      width:60px;
      background-color:white;
      z-index: 200;
    }

 </style>

 <title>Magnifier</title>

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
 <script src="js/babylon.2.4.js"></script>

  <script>
     var studyID=<?php echo $studyID; ?>;
     var imageFile="<?php echo $imageFile; ?>";
     var mag=<?php echo $mag; ?>;
     var picW=<?php echo $wd; ?>;
     var picH=<?php echo $ht; ?>;
     picW=picW*mag;
     picH=picH*mag;
     var percentage=picW/picH;
     var svgW=1024;
     var svgH=(1024/picW)*picH;
     var glassH=200;
     var glassW=200;
     var scene;
     var camera;
     var cameraz=0;
     var glassOff=false;
     var leftPosition="";
     var rightPosition="";

     $(document).ready(function(){  
         $("#targetImg").attr({'src':imageFile});
         $("#targetImg").css({'height':picH, 'width':picW});
     });


     window.addEventListener('DOMContentLoaded', function(){

      var canvas = document.getElementById('renderCanvas');

      var engine = new BABYLON.Engine(canvas, true);

      var createScene = function () {
          var scene = new BABYLON.Scene(engine);

          var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(-25, 49, -40), scene);

          this.angularSensibility = 5000;

          cameraz=-1*(picW/140);

          camera = new BABYLON.FreeCamera("FreeCamera", new BABYLON.Vector3(-0.6, -4, cameraz), scene);

          camera.keysUp = [84]; // T
          camera.keysDown = [66]; // B
          camera.keysLeft = [70]; // L
          camera.keysRight = [72]; // H
          camera.angularSensibility = this.angularSensibility;
          camera.attachControl(canvas, true);

          //Ground
          var ground = BABYLON.Mesh.CreatePlane("ground", 200.0, scene);
          ground.material = new BABYLON.StandardMaterial("groundMat", scene);       
          ground.material.diffuseTexture = new BABYLON.Texture("textures/wallTile.jpg", scene);
          ground.material.diffuseTexture.hasAlpha = true;
          //ground.material.backFaceCulling = false;
          ground.position = new BABYLON.Vector3(5, -10, -15);
          ground.rotation = new BABYLON.Vector3(Math.PI / 2, 0, 0);

          //target
          var target = new BABYLON.Mesh.CreatePlane("target", 10, scene);
          target.scaling.x = percentage;
          target.material = new BABYLON.StandardMaterial("Mat", scene);
          target.material.diffuseTexture = new BABYLON.Texture("<?php echo $imageFile; ?>", scene);
          target.material.emissiveColor = new BABYLON.Color3(1, 1, 1); // self-illuminate
          target.material.diffuseTexture.hasAlpha = true;
          target.position = new BABYLON.Vector3(0, -5, -5);

          scene.gravity = new BABYLON.Vector3(0, -0.9, 0);

          scene.collisionsEnabled = true;

          camera.checkCollisions = true;
          camera.applyGravity = true;

          camera.ellipsoid = new BABYLON.Vector3(1, 3, 1);

          ground.checkCollisions = true;
          target.checkCollisions = true;

          return scene;
      }

       scene = createScene();

      engine.runRenderLoop(function(){
          scene.render();
      });

      window.addEventListener('resize', function(){
          engine.resize();
      });

      window.addEventListener("mousemove", function (e) {
          if(glassOff==false){

             var pickResult = scene.pick(scene.pointerX, scene.pointerY);

           if (pickResult.hit) {
               var w=percentage*10;
               var h = (pickResult.pickedPoint.x).toFixed(4);
               var v = (pickResult.pickedPoint.y).toFixed(4);
               var x=0;
               var y=0;

               y=v*-1;
               percenty=(y/10).toFixed(4);
               x=Number(((w/2))+(1*h)).toFixed(4);
               percentx=(x/w).toFixed(4);

               if(pickResult.pickedMesh.name=="target"){
                $("#glass").show();
                overtarget(e,percentx,percenty);
                overtarget=true;
               }else{
                $("#glass").hide();
                overtarget=false;
               }
           }
          }
      });
     });

 function overtarget(e,percentx,percenty){
      $('#glass').css({
          height:glassH,
          width: glassW,
          left:  e.pageX-glassW/2,
          top:   e.pageY-glassH/2
      });

      var picX = (percentx * picW) * -1;
      var picY = (percenty * picH) * -1;

      $('#targetImg').css({
         'margin-left':  picX+glassW/2,
         'margin-top':   picY+glassH/2
      });
 }
 </script>

 </head>
 <body>
     <canvas id="renderCanvas"></canvas>
     <div id="glass"><img id="targetImg" src=""/></div>
     <div id="legend">T=forward<BR />B=back<BR />F=left<BR />H=right</div>     
 </body>`
 </html>