zoukankan      html  css  js  c++  java
  • ThreeJS学习7_裁剪平面(clipping)

    ThreeJS学习7_裁剪平面(clipping)

    clipping


    1. 裁剪平面简介

    裁剪平面指的是存在一个平面, 能够对场景中的物质进行截断, 这个平面就是裁剪平面, 裁剪平面分为全局的裁剪和局部裁剪

    • 全局裁剪指的有一个平面裁剪了整个场景的物体, 这需要在renderer中设置
    • 局部裁剪指的有一个平面裁剪裁剪指定物体, 这需要在指定物体的material中设置
      • 里面涉及到被裁剪的物体的是否需要渲染阴影
      • 里面还涉及到被多个平面裁剪时, 保留并集还是交集, 下面一一讲解


    2. 全局裁剪和局部裁剪

    1. 全局裁剪只需要设置一样

      renderer.clippingPlanes = planes

      renderer 是 WebGLRenderer实例,

      clippingPlanes 是用户自定义的剪裁平面,在世界空间中被指定为THREE.Plane对象。 这些平面全局使用。空间中与该平面点积为负的点将被切掉。 默认值是[]

      planes类型为[], 元素是任意的平面, 啥子叫做点积为负, 也就是点到平面的向量和平面法向量夹角大于90度, 简单来说, 平面法向量的反方向都被截断, , 该平面的法向量为(-1, 0, 0), 法向量的方向为x轴的负方向, 距离原点的距离为0.2, 因此, 在x>0.2的区域全部被截断不显示

      结合案例来看,

    全局剪切

    1. 局部裁剪, 除了设置 renderer , 还要设置指定物质的material, 当平面裁剪时, 就只有物质被裁剪, 看案例

    局部裁剪

    此时的设置是

    // 这个也是全局的, localClippingEnable = false也有效
    // 全局截断平面
    renderer.clippingPlanes = Empty;
    // 这个是全局的, 不开的话material中的clipping无效
    // 这个设置为true后才能局部截断
    renderer.localClippingEnabled = true;
    // 设置clipping
    // 在material中设置clippingPlanes: 局部截断平面, clipShadows为截断阴影是否展示
    clippingPlanes: [localPlane], clipShadows: true
    
    1. 截断阴影展示

    ​ 通过比对可以看出设置截断阴影( clipShadows )为true时, 就像截断后的物质不存在, 已经没有阴影了, 设置为clipShadows为false时, 截断后的物质仍然能产生阴影



    3. 被多个裁剪平面裁剪后

    设置material中的clipIntersection = true, 会只裁剪更改剪裁平面的行为,以便仅剪切其交叉点,而不是它们的并集。

    clipIntersection默认为false, 裁剪平面的并集

    简单来说, 有多个裁剪平面, 每个裁剪平面裁剪的区域分布为c1, c2, ... ,cn, 默认设置, 裁剪 c1区域+c2区域+...+cn区域, 当clipIntersection=true时, 裁剪的只有这些区域共同的部分, c1 ∩ c2 ∩ ... cn

    // 更改剪裁平面的行为,以便仅剪切其交叉点,而不是它们的并集。默认值为 false。
    // 设置为true后剪切交集而不是并集
    clipIntersection: true
    

    三个截断平面法向量分布为(1, 0, 0), (0, -1, 0), (0, 0, -1), c1 为x负半轴区域, c2为 y正半轴, c3为z正半轴, 可以看到, 当clipIntersection为false时, c1, c2, c3区域都被截断了, 当为true时, 截断了他们共同的部分

    效果如下

    1. clipIntersection = true;

    1. clipIntersection = false;



    4. 被多个裁剪平面截断后代码

    <!DOCTYPE html>
    <html lang="ch">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <style>
        body{
          margin: 0;
          overflow: hidden;
        }
      </style>
    </head>
    <body>
    <div id="container">
    
    </div>
    
    <script type="module">
      import * as THREE from '../build/three.module.js';
      import {OrbitControls} from "./jsm/controls/OrbitControls.js";
      import {GUI} from "./jsm/libs/dat.gui.module.js";
    
      let container, camera, scene, renderer, mesh;
    
      let params = {
        clipIntersection: true,
        planeConstant: 0,
        showHelpers: false
      };
    
      let clipPlanes = [
          new THREE.Plane(new THREE.Vector3(1, 0, 0), 0),
          new THREE.Plane(new THREE.Vector3(0, -1, 0), 0),
          new THREE.Plane(new THREE.Vector3(0, 0, -1), 0)
      ];
    
      init();
      animation();
    
      function init() {
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x8FBCD4);
        scene.add(new THREE.AmbientLight(0x8FBCD4, 0.4));
    
        container = document.getElementById('container');
        camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 200);
        camera.position.set(-1.5, 2.5, 3.0);
        scene.add(camera);
    
        let pointLight = new THREE.PointLight(0xffffff, 1);
        // 灯跟着相机走, 效果不错
        camera.add(pointLight);
    
        scene.add(new THREE.AxesHelper(5));
    
        renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.localClippingEnabled = true;
        container.appendChild(renderer.domElement);
    
        let group = new THREE.Group();
    
        for (let i = 0; i <= 30; i += 2) {
          let geometry = new THREE.SphereBufferGeometry(i / 30, 48, 24);
          let material = new THREE.MeshLambertMaterial({
            color: new THREE.Color().setHSL(Math.random(), 0.5, 0.5),
            side: THREE.DoubleSide,
            clippingPlanes: clipPlanes,
            // 更改剪裁平面的行为,以便仅剪切其交叉点,而不是它们的并集。默认值为 false。
            // 设置为true后剪切交集而不是并集
            clipIntersection: params.clipIntersection
          });
    
          group.add(new THREE.Mesh(geometry, material));
        }
    
        scene.add(group);
    
        let helpers = new THREE.Group();
        helpers.add(new THREE.PlaneHelper(clipPlanes[0], 2, 0xff0000));
        helpers.add(new THREE.PlaneHelper(clipPlanes[1], 2, 0x00ff00));
        helpers.add(new THREE.PlaneHelper(clipPlanes[2], 2, 0x0000ff));
        helpers.visible = false;
        scene.add(helpers);
    
        let gui = new GUI();
    
        gui.add(params, 'clipIntersection').name('clip intersection').onChange(value=>{
    
          /*for(let item in group.children){
            item.material.clipIntersection = value;
          }*/
    
          let children = group.children;
    
          for (let i = 0; i < children.length; i++) {
            children[i].material.clipIntersection = value;
          }
    
        });
    
        gui.add(params, 'planeConstant', -1, 1).step(0.01).name('plane constant').onChange(value=>{
    
          for (let i = 0; i < clipPlanes.length; i++) {
            clipPlanes[i].constant = value;
          }
        });
    
        gui.add(params, 'showHelpers').name('show helpers').onChange(value=>{
          helpers.visible = value;
        });
    
    
        let controls =  new OrbitControls(camera, renderer.domElement);
        controls.enabledZoom = false;
    
        window.addEventListener('resize', onWindowResize, false);
      }
    
      function animation(){
        render();
    
        requestAnimationFrame(animation);
      }
    
      function render() {
    
        renderer.render(scene, camera);
      }
    
      function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
    
        renderer.setSize(window.innerWidth, window.innerHeight);
      }
    
    
    </script>
    </body>
    </html>
    
  • 相关阅读:
    进位制 与成熟表示
    例题 3-6 环状序列
    -------------------开启我的手残之旅---------我就是喜欢写笔记-------咋滴啦?-----
    图的遍历---------开始开始-------o(∩_∩)o 哈哈
    -----------什么是图?------------
    并查集-----集合以及计算----
    ----堆----希望这是一个容易上手的工具--------
    kafka-docker----(how to setup http proxy in container??)
    FW: Dockerfile RUN, CMD & ENTRYPOINT
    telnet --- no route to host solution "iptables -F " in the target machine
  • 原文地址:https://www.cnblogs.com/xiaxiangx/p/13873037.html
Copyright © 2011-2022 走看看