threejs 攝像頭區域模擬

要做一個模擬攝像頭區域的功能,本想用cameraHelper模擬出的線與模型求交點,然後通過得到的點畫三角面,可看cameraHelper的屬性,pointMap並不是直接給出了最遠的四個點,沒看出來到底是怎麼對應到三維點的,所以自己畫了個攝像頭的helper。

//攝像機區域模擬 cameraHelper
{
    function addCameraHelper(){
        var position=new THREE.Vector3(-2.29543,0.63726,3.034237);
        var position2=new THREE.Vector3(-2.29543,0.63726,3.034237);
        // var position=new THREE.Vector3(1.1354645,0.657788,1.406287);
        // var position2=new THREE.Vector3(1.1354645,0.657788,1.406287);
        var far0= CHPointPostion(Math.PI/6,innerWidth/innerHeight,0.1,2,position2,0,Math.PI/4,-Math.PI/6);

        var points=far0.points;
        var tar=far0.pointsIndex;
        console.log(tar);
        var vertices=[];

        for(var i=0;i<points.length;i++){
            var ray=points[i].sub(position);
            ray.normalize();
            var raycaster=new THREE.Raycaster(position,ray);
            var intersects=raycaster.intersectObjects(floorChildrenGroup);
            if(intersects.length>0){
                var point=intersects[0].point;
                point.y=point.y+0.05;
                vertices.push(point);
            }
        }
        var material = new THREE.LineBasicMaterial({
            color: 0xff0000,
            side:THREE.DoubleSide,
            transparent:true,
            opacity:0.5
        });
        for(var i=0;i<points.length;i++){
            var geometry= new THREE.Geometry();
            geometry.vertices.push(
                position,vertices[i]
            );
            var line = new THREE.Line( geometry, material );
            scene.add( line );
        }
        var faces=[];
        for(var i=0;i<tar.length;i=i+3){
            var index0=tar[i];
            var index1=tar[i+1];
            var index2=tar[i+2];
            var face=new THREE.Face3(index0,index1,index2);
            console.log(face);
            faces.push(face);
        }

        var geometry=new THREE.Geometry();
        geometry.vertices=vertices;
        geometry.faces=faces;
        geometry.computeFaceNormals();

        // //設置網格材質,這裏設置爲Lambert材質爲一種不發光材質
        var meshMaterial = new THREE.MeshLambertMaterial({
            color : 0xff0000,
            side: THREE.DoubleSide,
            transparent:true,
            opacity:0.5
        });
        var mesh = new THREE.Mesh(geometry, meshMaterial);
        scene.add(mesh);

    }
//計算CameraHelper中最遠的四個點座標 初始位置爲(0,0,0) 做座標變換
    function CHPointPostion(fov,aspect,near,far,startpositon,rotationX,rotationY,rotationZ) {

        var farpositon={
           points:[],
            pointsIndex:null
        }

        //計算座標變幻前的初始角度(p1/p2/p3/p4沿x軸正方向順時針排列,p1爲x y z全爲正值的點)
        var p1=new THREE.Vector3();
        p1.x=far;
        p1.y=Math.atan(fov/2)*p1.x;
        p1.z=aspect*p1.y;
        var p2=new THREE.Vector3();
        p2.x=p1.x;
        p2.y=-p1.y;
        p2.z=p1.z;
        var p3=new THREE.Vector3();
        p3.x=p1.x;
        p3.y=-p1.y;
        p3.z=-p1.z;
        var p4=new THREE.Vector3();
        p4.x=p1.x;
        p4.y=p1.y;
        p4.z=-p1.z;
        //座標變換 旋轉(俯仰角:繞z軸旋轉)
        farpositon.points.push(p1);
        farpositon.points.push(p2);
        farpositon.points.push(p3);
        farpositon.points.push(p4);

        var yrange=p1.y-p2.y;
        var zrange=p1.z-p4.z;
        var ycount=20;
        var zcount=20;

        //補點
        // for(var i=0;i<ycount;i++){
        //     var y=p1.y-(yrange/ycount)*i;
        //     for(var j=0;j<zcount;j++){
        //         var z=p1.z-(zrange/zcount)*j;
        //         var point=new THREE.Vector3();
        //         point.x=p1.x;
        //         point.y=y;
        //         point.z=z;
        //         farpositon.points.push(point);
        //     }
        // }


        var vec2Points=[];

        for(var i=0;i<farpositon.points.length;i++){
            var point=[farpositon.points[i].z,farpositon.points[i].y];

            vec2Points.push(point);
        }
        //求三角面索引
        farpositon.pointsIndex=Delaunay.triangulate(vec2Points);  //三角面集合 含頂點索引
        console.log( farpositon.pointsIndex);

        //z軸旋轉
        for(var i=0;i<farpositon.points.length;i++){
            farpositon.points[i]=farpositon.points[i].applyAxisAngle(new THREE.Vector3(0,0,1),rotationZ);
        }
        //y軸旋轉
        for(var i=0;i<farpositon.points.length;i++){
            farpositon.points[i]=farpositon.points[i].applyAxisAngle(new THREE.Vector3(0,1,0),rotationY);
        }
        //座標平移
        for(var i=0;i<farpositon.points.length;i++){
            farpositon.points[i].set(farpositon.points[i].x+startpositon.x,farpositon.points[i].y+startpositon.y,farpositon.points[i].z+startpositon.z);
        }

        return farpositon;
    }
}

其中生成三角面的索引是從網上找的二維三角剖析的js文件

var Delaunay;

(function() {
  "use strict";

  var EPSILON = 1.0 / 1048576.0;

  function supertriangle(vertices) {
    var xmin = Number.POSITIVE_INFINITY,
        ymin = Number.POSITIVE_INFINITY,
        xmax = Number.NEGATIVE_INFINITY,
        ymax = Number.NEGATIVE_INFINITY,
        i, dx, dy, dmax, xmid, ymid;

    for(i = vertices.length; i--; ) {
      if(vertices[i][0] < xmin) xmin = vertices[i][0];
      if(vertices[i][0] > xmax) xmax = vertices[i][0];
      if(vertices[i][1] < ymin) ymin = vertices[i][1];
      if(vertices[i][1] > ymax) ymax = vertices[i][1];
    }

    dx = xmax - xmin;
    dy = ymax - ymin;
    dmax = Math.max(dx, dy);
    xmid = xmin + dx * 0.5;
    ymid = ymin + dy * 0.5;

    return [
      [xmid - 20 * dmax, ymid -      dmax],
      [xmid            , ymid + 20 * dmax],
      [xmid + 20 * dmax, ymid -      dmax]
    ];
  }

  function circumcircle(vertices, i, j, k) {
    var x1 = vertices[i][0],
        y1 = vertices[i][1],
        x2 = vertices[j][0],
        y2 = vertices[j][1],
        x3 = vertices[k][0],
        y3 = vertices[k][1],
        fabsy1y2 = Math.abs(y1 - y2),
        fabsy2y3 = Math.abs(y2 - y3),
        xc, yc, m1, m2, mx1, mx2, my1, my2, dx, dy;

    /* Check for coincident points */
    if(fabsy1y2 < EPSILON && fabsy2y3 < EPSILON)
      throw new Error("Eek! Coincident points!");

    if(fabsy1y2 < EPSILON) {
      m2  = -((x3 - x2) / (y3 - y2));
      mx2 = (x2 + x3) / 2.0;
      my2 = (y2 + y3) / 2.0;
      xc  = (x2 + x1) / 2.0;
      yc  = m2 * (xc - mx2) + my2;
    }

    else if(fabsy2y3 < EPSILON) {
      m1  = -((x2 - x1) / (y2 - y1));
      mx1 = (x1 + x2) / 2.0;
      my1 = (y1 + y2) / 2.0;
      xc  = (x3 + x2) / 2.0;
      yc  = m1 * (xc - mx1) + my1;
    }

    else {
      m1  = -((x2 - x1) / (y2 - y1));
      m2  = -((x3 - x2) / (y3 - y2));
      mx1 = (x1 + x2) / 2.0;
      mx2 = (x2 + x3) / 2.0;
      my1 = (y1 + y2) / 2.0;
      my2 = (y2 + y3) / 2.0;
      xc  = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
      yc  = (fabsy1y2 > fabsy2y3) ?
        m1 * (xc - mx1) + my1 :
        m2 * (xc - mx2) + my2;
    }

    dx = x2 - xc;
    dy = y2 - yc;
    return {i: i, j: j, k: k, x: xc, y: yc, r: dx * dx + dy * dy};
  }

  function dedup(edges) {
    var i, j, a, b, m, n;

    for(j = edges.length; j; ) {
      b = edges[--j];
      a = edges[--j];

      for(i = j; i; ) {
        n = edges[--i];
        m = edges[--i];

        if((a === m && b === n) || (a === n && b === m)) {
          edges.splice(j, 2);
          edges.splice(i, 2);
          break;
        }
      }
    }
  }

  Delaunay = {
    triangulate: function(vertices, key) {
      var n = vertices.length,
          i, j, indices, st, open, closed, edges, dx, dy, a, b, c;

      /* Bail if there aren't enough vertices to form any triangles. */
      if(n < 3)
        return [];

      /* Slice out the actual vertices from the passed objects. (Duplicate the
       * array even if we don't, though, since we need to make a supertriangle
       * later on!) */
      vertices = vertices.slice(0);

      if(key)
        for(i = n; i--; )
          vertices[i] = vertices[i][key];

      /* Make an array of indices into the vertex array, sorted by the
       * vertices' x-position. Force stable sorting by comparing indices if
       * the x-positions are equal. */
      indices = new Array(n);

      for(i = n; i--; )
        indices[i] = i;

      indices.sort(function(i, j) {
        var diff = vertices[j][0] - vertices[i][0];
        return diff !== 0 ? diff : i - j;
      });

      /* Next, find the vertices of the supertriangle (which contains all other
       * triangles), and append them onto the end of a (copy of) the vertex
       * array. */
      st = supertriangle(vertices);
      vertices.push(st[0], st[1], st[2]);
      
      /* Initialize the open list (containing the supertriangle and nothing
       * else) and the closed list (which is empty since we havn't processed
       * any triangles yet). */
      open   = [circumcircle(vertices, n + 0, n + 1, n + 2)];
      closed = [];
      edges  = [];

      /* Incrementally add each vertex to the mesh. */
      for(i = indices.length; i--; edges.length = 0) {
        c = indices[i];

        /* For each open triangle, check to see if the current point is
         * inside it's circumcircle. If it is, remove the triangle and add
         * it's edges to an edge list. */
        for(j = open.length; j--; ) {
          /* If this point is to the right of this triangle's circumcircle,
           * then this triangle should never get checked again. Remove it
           * from the open list, add it to the closed list, and skip. */
          dx = vertices[c][0] - open[j].x;
          if(dx > 0.0 && dx * dx > open[j].r) {
            closed.push(open[j]);
            open.splice(j, 1);
            continue;
          }

          /* If we're outside the circumcircle, skip this triangle. */
          dy = vertices[c][1] - open[j].y;
          if(dx * dx + dy * dy - open[j].r > EPSILON)
            continue;

          /* Remove the triangle and add it's edges to the edge list. */
          edges.push(
            open[j].i, open[j].j,
            open[j].j, open[j].k,
            open[j].k, open[j].i
          );
          open.splice(j, 1);
        }

        /* Remove any doubled edges. */
        dedup(edges);

        /* Add a new triangle for each edge. */
        for(j = edges.length; j; ) {
          b = edges[--j];
          a = edges[--j];
          open.push(circumcircle(vertices, a, b, c));
        }
      }

      /* Copy any remaining open triangles to the closed list, and then
       * remove any triangles that share a vertex with the supertriangle,
       * building a list of triplets that represent triangles. */
      for(i = open.length; i--; )
        closed.push(open[i]);
      open.length = 0;

      for(i = closed.length; i--; )
        if(closed[i].i < n && closed[i].j < n && closed[i].k < n)
          open.push(closed[i].i, closed[i].j, closed[i].k);

      /* Yay, we're done! */
      return open;
    },
    contains: function(tri, p) {
      /* Bounding box test first, for quick rejections. */
      if((p[0] < tri[0][0] && p[0] < tri[1][0] && p[0] < tri[2][0]) ||
         (p[0] > tri[0][0] && p[0] > tri[1][0] && p[0] > tri[2][0]) ||
         (p[1] < tri[0][1] && p[1] < tri[1][1] && p[1] < tri[2][1]) ||
         (p[1] > tri[0][1] && p[1] > tri[1][1] && p[1] > tri[2][1]))
        return null;

      var a = tri[1][0] - tri[0][0],
          b = tri[2][0] - tri[0][0],
          c = tri[1][1] - tri[0][1],
          d = tri[2][1] - tri[0][1],
          i = a * d - b * c;

      /* Degenerate tri. */
      if(i === 0.0)
        return null;

      var u = (d * (p[0] - tri[0][0]) - b * (p[1] - tri[0][1])) / i,
          v = (a * (p[1] - tri[0][1]) - c * (p[0] - tri[0][0])) / i;

      /* If we're outside the tri, fail. */
      if(u < 0.0 || v < 0.0 || (u + v) > 1.0)
        return null;

      return [u, v];
    }
  };

  if(typeof module !== "undefined")
    module.exports = Delaunay;
})();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章