Контрольные точки находятся внутри многоугольника - не работают правильно - PullRequest
0 голосов
/ 27 апреля 2019

Я создаю комнату на основе любого массива с точками.Объекты, которые можно перемещать, добавляются в комнату.Цель состоит в том, чтобы заблокировать возможность перемещения объекта из комнаты.

Когда объект перемещается, я проверяю, принадлежат ли все 4 нижние точки полу - если это так, вы можете переместить объект дальше -в противном случае это означает, что объект будет находиться за стеной, поэтому вам необходимо восстановить его в предыдущую позицию.

Функция, отвечающая за создание комнаты (wallPoint - это массив с точками)

var wallPoint = [
 {
   "X": 0,
   "Y": 0
 },
 {
   "X": 5,
   "Y": 0
},
 {
  "X": 5,
  "Y": 3
},
{
  "X": 7,
  "Y": 3
},
{
  "X": 7,
  "Y": 5
},
{
  "X": 5,
  "Y": 5
},
{
  "X": 5,
  "Y": 7
},
{
  "X": 0,
  "Y": 7
}
 ];

function createRoom() {

// create a walls
var walls = new THREE.Geometry();
var floorPoints = [];


wallsPoint.forEach(r => {
    walls.vertices.push(new THREE.Vector3(r.X, r.Y, 0));
walls.vertices.push(new THREE.Vector3(r.X, r.Y, 3));
floorPoints.push(new THREE.Vector3(r.X, r.Y, 0));

walls.name = "wall";
});
    var previousVertexIndex = walls.vertices.length - 2;
    for (i = 0; i < walls.vertices.length; i += 2) {
        walls.faces.push(new THREE.Face3(i + 1, i, 
previousVertexIndex));
       walls.faces.push(new THREE.Face3(previousVertexIndex + 1, i + 
1, previousVertexIndex));
       previousVertexIndex = i;

    }
    walls.computeFaceNormals();

var wallsTexture = new THREE.TextureLoader().load( 'walls.jpg' );//  
var mesh = new THREE.Mesh(walls, new THREE.MeshBasicMaterial({
    map: wallsTexture
}));
mesh.rotation.x= -Math.PI /2;

//create a floor
var floorShape = new THREE.Shape(floorPoints);
var floorGeometry = new THREE.ShapeGeometry(floorShape);
var floorTexture = new THREE.TextureLoader().load( 'wood.jpg' ); 
floor = new THREE.Mesh(floorGeometry, new THREE.MeshBasicMaterial({
    map: floorTexture,
    side: THREE.DoubleSide
}));


floor.geometry.vertices = floorPoints;
floor.geometry.name = "floor";
floor.rotation.x =-Math.PI/2;

group = new THREE.Object3D();
group.add(mesh);
group.add( floor );
group.add(ceiling) ;
scene.add( group );
  }

Функция, ответственная за проверку наличия точек на полу.Точки - это helperBox.geometry.attributes.position.array (вспомогательный блок для объекта, который мы перемещаем мышью)на полу или нет.В настоящее время в большинстве случаев функция работает хорошо.К сожалению, не все из них.Каждый раз, когда он работает плохо - речь идет о пункте 3 и / или 4.

Как это исправить?В качестве альтернативы, как еще не следует позволять объекту (модель имеет формат obj - такой неправильной формы) выходить за пределы пола?

1 Ответ

0 голосов
/ 29 апреля 2019

Очень грубая концепция с реализацией алгоритма, взятая из https://github.com/substack/point-in-polygon:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(3.5, 10, 3.5);
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);
controls.target.set(3.5, 0, -3.5);
controls.update();

var grid = new THREE.GridHelper(20, 20, 0x44ff44);
grid.position.set(0, -0.01, 0);
scene.add(grid);

var wallPoints = wallsPoint.map(w => {
  return new THREE.Vector3(w.X, 0, -w.Y)
});
var geom = new THREE.BufferGeometry().setFromPoints(wallPoints);
var points = new THREE.Points(geom, new THREE.PointsMaterial({
  size: 1,
  color: "red"
}));
var lines = new THREE.LineLoop(geom, new THREE.LineBasicMaterial({
  color: "yellow"
}));

scene.add(points, lines);

var marker = new THREE.Mesh(new THREE.SphereBufferGeometry(0.25, 8, 2), new THREE.MeshBasicMaterial({
  color: "aqua"
}));
marker.position.set(3.5, 3.5, 0);
scene.add(marker);

document.addEventListener("mousemove", onMouseMove, false);

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
var iPoint = new THREE.Vector3();

function onMouseMove(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  raycaster.setFromCamera(mouse, camera);
  raycaster.ray.intersectPlane(plane, marker.position);
  marker.material.color.set(isInside(marker.position, wallPoints) ? "aqua" : "magenta");
}

function isInside(point, vs) {

  var x = point.x,
    y = point.z;

  var inside = false;
  for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
    var xi = vs[i].x,
      yi = vs[i].z;
    var xj = vs[j].x,
      yj = vs[j].z;

    var intersect = ((yi > y) != (yj > y)) &&
      (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
    if (intersect) inside = !inside;
  }

  return inside;
}

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera)
});
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script>
  var wallsPoint = [{
      "X": 0,
      "Y": 0
    },
    {
      "X": 5,
      "Y": 0
    },
    {
      "X": 5,
      "Y": 3
    },
    {
      "X": 7,
      "Y": 3
    },
    {
      "X": 7,
      "Y": 5
    },
    {
      "X": 5,
      "Y": 5
    },
    {
      "X": 5,
      "Y": 7
    },
    {
      "X": 0,
      "Y": 7
    }
  ];
</script>
...