How to project a rectangle onto a Mesh/Terrain object, for use as a select marquee? (in three.js)

前端 未结 1 1728
没有蜡笔的小新
没有蜡笔的小新 2020-12-19 16:44

I have a terrain which was generated using the THREE.Terrain library. I\'d like to be able to click and drag out a marquee and select objects that are on the surface of the

相关标签:
1条回答
  • 2020-12-19 17:13

    Right after I posted my comment, I had a thought exactly like Don McCurdy (cheers, Don :) ). Quick search on https://www.shadertoy.com gave me that shader https://www.shadertoy.com/view/XlsBRB (look at the awesome comments from FabriceNeyret2 there). So I just adapted that fragment shader for this very rough concept.

    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(0, 5, 10);
    var renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    
    var controls = new THREE.OrbitControls(camera, renderer.domElement);
    
    var geom = new THREE.PlaneGeometry(20, 20, 10, 10);
    geom.vertices.forEach(v => {
      v.z = THREE.Math.randFloat(-1, 1);
    });
    geom.rotateX(-Math.PI * .5);
    geom.computeFaceNormals();
    geom.computeVertexNormals();
    
    var uniforms = {
      center: {
        value: new THREE.Vector3()
      },
      size: {
        value: new THREE.Vector2(1, 1)
      },
      lineHalfWidth: {
        value: 0.1
      }
    }
    
    var matShader = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vertShader,
      fragmentShader: fragShader
    });
    
    var matWire = new THREE.MeshBasicMaterial({
      color: "gray",
      wireframe: true
    });
    
    var obj = THREE.SceneUtils.createMultiMaterialObject(geom, [matShader, matWire]);
    
    scene.add(obj);
    
    var gui = new dat.GUI();
    gui.add(uniforms.size.value, "x", .5, 5.0).name("size.x");
    gui.add(uniforms.size.value, "y", .5, 5.0).name("size.y");
    gui.add(uniforms.lineHalfWidth, "value", .05, 2.0).name("line half-width");
    
    var raycaster = new THREE.Raycaster();
    var mouse = new THREE.Vector2();
    var intersects = [];
    var point = new THREE.Vector3();
    
    window.addEventListener("mousemove", function(event) {
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
      raycaster.setFromCamera(mouse, camera);
      intersects = raycaster.intersectObject(obj, true);
      if (intersects.length === 0) return;
      obj.worldToLocal(point.copy(intersects[0].point));
      uniforms.center.value.copy(point);
    
    }, false);
    
    
    render();
    
    function render() {
      requestAnimationFrame(render);
      renderer.render(scene, camera);
    }
    body {
      overflow: hidden;
      margin: 0;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>
    <script src="https://cdn.rawgit.com/mrdoob/three.js/0949e59f/examples/js/controls/OrbitControls.js"></script>
    <script src="https://cdn.rawgit.com/mrdoob/three.js/0949e59f/examples/js/utils/SceneUtils.js"></script>
    <script src="https://cdn.rawgit.com/mrdoob/three.js/0949e59f/examples/js/libs/dat.gui.min.js"></script>
    <script>
      var vertShader = `
        varying vec2 vPos;
        void main() {
          vPos = position.xz;
          gl_Position = projectionMatrix *
                        modelViewMatrix *
                        vec4(position,1.0);
        }
      `;
    
      var fragShader = `
        uniform vec3 center;
        uniform vec2 size;
        uniform float lineHalfWidth;
        
        varying vec2 vPos;
        
        void main() {
          vec2 Ro = size * .5;
          vec2 Uo = abs( vPos - center.xz ) - Ro;
          
          vec3 c = mix(vec3(1.), vec3(1.,0.,0.), float(abs(max(Uo.x,Uo.y)) < lineHalfWidth));
          
          gl_FragColor = vec4(c, 1.  );
        }
        
      `;
    </script>

    0 讨论(0)
提交回复
热议问题