• threejs CameraHelper 查看照相机的观察范围


    简单例子

    这个例子,是在一个视图中,看到照相机的辅助线,也就是,一个照相机的观察访问

    这样,就需要两个照相机,一个是主照相机,一个是加有辅助线的照相机(有两种,正交和透视,这里辅助的使用的是正交的)

    设置两个照相机位置:注意,辅助的子照相机要在主照相机里面,这样才能在主照相机的镜头下看到辅助照相机的观察范围

     //场景、摄像机、渲染器、实体
        var scene, camera, renderer, cameraHelper;
        var cube, controls;
        //在页面加载完,进行绘制渲染页面
        window.onload = function() {
          init(); //数据初始化
          setSize(); //设置大小画布
          cube(); //绘制实体
          animate(); //动画渲染
        };
        //初始化摄像机,场景,渲染器,以及一些工具,比如摄像机辅助线,控制器
        function init() {
          scene = new THREE.Scene();
          camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            500
          );
          camera.position.set(10, 5, 20);
          camera.lookAt(new THREE.Vector3(0, 0, 0));
          //正交投影照相机
          camera2 = new THREE.OrthographicCamera(-1, 1, 1, -1, 5, 10);
          renderer = new THREE.WebGLRenderer({ alpha: true });
          camera2.position.set(0, 0, 5);
          camera2.lookAt(new THREE.Vector3(0, 0, 0));
          //renderer = new THREE.WebGLRenderer();
          //camera.position.z = 10;
          controls = new THREE.OrbitControls(camera);
          controls.autoRotate = true;
    
          //照相机帮助线
          cameraHelper = new THREE.CameraHelper(camera2);
          scene.add(cameraHelper);
        }
        //设置画布大小,这个设置为整个视图,就不需要剪切了
        function setSize() {
          renderer.setSize(window.innerWidth, window.innerHeight);
          document.body.appendChild(renderer.domElement);
        }
        //普通的四方体
        function cube() {
          var geometry = new THREE.BoxGeometry(1, 1, 1);
          var material = new THREE.MeshNormalMaterial({ color: 0x00ff00 });
          cube = new THREE.Mesh(geometry, material);
          //设置位置
          cube.position.set(0, 0, -1.5);
          scene.add(cube);
        }
        function animate() {
          requestAnimationFrame(animate); //一帧帧动画
          cube.rotation.x += 0.005;
          cube.rotation.y += 0.005;
          cube.rotation.z += 0.005;
          camera.updateProjectionMatrix();
          controls.update();
          cameraHelper.update();
          renderer.render(scene, camera); //渲染
        }

     看完简单的例子,看看复杂的,

    左边是一个视图,用一个小的照相机渲染出来的就是右边辅助线的照相机,

    右边是两个照相机渲染出来的,右边,外面有个大的照相机,看到里面有个小的照相机,并且通过辅助线看到里面照相机的观察区域。

    html部分:是,一个Canvas ,然后拆分为左右两个视图

    <canvas id="c"></canvas>
        <div class="split">
           <div id="view1" tabindex="1"></div>
           <div id="view2" tabindex="2"></div>
        </div>
      <script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>
    <script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/js/controls/OrbitControls.js"></script>

    css

    html, body {
      margin: 0;
      height: 100%;
    }
    #c {
       100%;
      height: 100%;
      display: block;
    }
    .split {
      position: absolute;
      left: 0;
      top: 0;
       100%;
      height: 100%;
      display: flex;
    }
    .split>div {
       100%;
      height: 100%;
    }

    js,他是有两个照相机,

    1.一个透视作为主照相机,

    2.一个正交作为辅助照相机,

    在正交照相机加上辅助线,然后把辅助线弄到场景里面,

    这样我们就可以在一个照相机(主照相机下)下看到另一个照相机(另一个有辅助线的照相机)的作用范围(辅助线范围)

    var renderer,
      scene,
      camera,
      camera2,
      cameraHelper,
      canvas,
      view1Elem,
      view2Elem;
    function init() {
      renderer = new THREE.WebGLRenderer({ canvas });
      const size = 1;
      const near = 5;
      const far = 50;
      //正交投影照相机
      camera = new THREE.OrthographicCamera(-size, size, size, -size, near, far);
      //透视投影照相机
      camera2 = new THREE.PerspectiveCamera(
        60, // fov
        2, // aspect
        0.1, // near
        500 // far
      );
      //照相机帮助线
      cameraHelper = new THREE.CameraHelper(camera);
      scene = new THREE.Scene();
      scene.background = new THREE.Color("black");
      scene.add(cameraHelper);
    }
    
    function setCarema() {
      camera.zoom = 0.2;
      camera.position.set(0, 10, 20);
    
      //旋转控制器
      const controls = new THREE.OrbitControls(camera, view1Elem);
      controls.target.set(0, 5, 0);
      controls.update();
    
      camera2.position.set(16, 28, 40);
      camera2.lookAt(0, 5, 0);
    
      //旋转控制器
      const controls2 = new THREE.OrbitControls(camera2, view2Elem);
      controls2.target.set(0, 5, 0);
      controls2.update();
    }
    
    function drawObj() {
      //面的绘制
    
      {
        const planeSize = 40;
    
        const loader = new THREE.TextureLoader();
        const texture = loader.load(
          "https://threejsfundamentals.org/threejs/resources/images/checker.png"
        );
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        texture.magFilter = THREE.NearestFilter;
        const repeats = planeSize / 2;
        texture.repeat.set(repeats, repeats);
    
        const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
        const planeMat = new THREE.MeshPhongMaterial({
          map: texture,
          side: THREE.DoubleSide
        });
        const mesh = new THREE.Mesh(planeGeo, planeMat);
        mesh.rotation.x = Math.PI * -0.5;
        scene.add(mesh);
      }
      //正方体的绘制
      {
        const cubeSize = 4;
        const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
        const cubeMat = new THREE.MeshPhongMaterial({ color: "#8AC" });
        const mesh = new THREE.Mesh(cubeGeo, cubeMat);
        mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
        scene.add(mesh);
      }
      //球体的绘制
      {
        const sphereRadius = 3;
        const sphereWidthDivisions = 32;
        const sphereHeightDivisions = 16;
        const sphereGeo = new THREE.SphereBufferGeometry(
          sphereRadius,
          sphereWidthDivisions,
          sphereHeightDivisions
        );
        const sphereMat = new THREE.MeshPhongMaterial({ color: "#CA8" });
        const mesh = new THREE.Mesh(sphereGeo, sphereMat);
        mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
        scene.add(mesh);
      }
      //光线的设置
      {
        const color = 0xffffff;
        const intensity = 1;
        const light = new THREE.DirectionalLight(color, intensity);
        light.position.set(0, 10, 0);
        light.target.position.set(-5, 0, 0);
        scene.add(light);
        scene.add(light.target);
      }
    }
    //重新渲染 渲染器的大小,如果canvas的大小不是renderer的大小,就重新设置大小 canvas的大小,这个是因为
    function resizeRendererToDisplaySize(renderer) {
      const canvas = renderer.domElement;
      const width = canvas.clientWidth;
      const height = canvas.clientHeight;
      const needResize = canvas.width !== width || canvas.height !== height;
      if (needResize) {
        renderer.setSize(width, height, false);
      }
      return needResize;
    }
    
    //剪刀,用来切割canvas 到两个view中,通过view切割计算,找到view的位置,然后进行渲染 function setScissorForElement(elem) { const canvasRect = canvas.getBoundingClientRect(); //包围盒的正方体 const elemRect = elem.getBoundingClientRect(); // compute a canvas relative rectangle const right = Math.min(elemRect.right, canvasRect.right) - canvasRect.left; const left = Math.max(0, elemRect.left - canvasRect.left); const bottom = Math.min(elemRect.bottom, canvasRect.bottom) - canvasRect.top; const top = Math.max(0, elemRect.top - canvasRect.top); const width = Math.min(canvasRect.width, right - left); const height = Math.min(canvasRect.height, bottom - top); // setup the scissor to only render to that part of the canvas const positiveYUpBottom = canvasRect.height - bottom; renderer.setScissor(left, positiveYUpBottom, width, height); renderer.setViewport(left, positiveYUpBottom, width, height); // return the aspect return width / height; } function render() { resizeRendererToDisplaySize(renderer); // turn on the scissor 开启剪刀,可以进行切割 renderer.setScissorTest(true); // render the original view { const aspect = setScissorForElement(view1Elem); // update the camera for this aspect camera.left = -aspect; camera.right = aspect; camera.updateProjectionMatrix(); cameraHelper.update(); // don't draw the camera helper in the original view cameraHelper.visible = false; scene.background.set(0x000000); renderer.render(scene, camera); } // render from the 2nd camera { const aspect = setScissorForElement(view2Elem); // update the camera for this aspect camera2.aspect = aspect; camera2.updateProjectionMatrix(); // draw the camera helper in the 2nd view cameraHelper.visible = true; scene.background.set(0x000040); renderer.render(scene, camera2); } requestAnimationFrame(render); } window.onload = function() { canvas = document.querySelector("#c"); view1Elem = document.querySelector("#view1"); view2Elem = document.querySelector("#view2"); init(); setCarema(); drawObj(); requestAnimationFrame(render); };

    上面这个例子有点小复杂,因为涉及到,剪刀进行切割视图的计算

  • 相关阅读:
    SAP MM VL32N和MIGO对内向交货单做收货,都会更新其'总体货物移动状态'
    Several mentality of SAP project customers in private enterprises
    GIT·AccessToken的基础使用
    MSSQL·按照某个字段重复删除旧的一条数据
    MSSQL·WHERE INT列=''时的结果集
    技能Get·手动更新HP笔记本BIOS过程记录
    GIT·.NetFramework MVC项目默认的.gitignore文件备份
    .Net·发布过程中报:在应用程序之外使用注册为allowDefinition='MachineTOApplication'的节是错误...
    知识总结·多系统数据同步API调用设计原则
    MSSQL·查看表锁进程及杀死进程的脚本
  • 原文地址:https://www.cnblogs.com/xuqp/p/11060268.html
Copyright © 2020-2023  润新知