three.jsbuffer-geometry

Three.js. Get localToWorld from BufferGeometry vertices


  1. I get faces from geometry attributes
  2. get the coordinates for each point of the face
  3. draw lines for each edge of the face

And everything is fine if the object is not moved: without moving

But if you move, then the lines remain in place: after moving

If I try to get the world coordinates of points after moving, then I see the same picture: after moving + localToWorld

If I update matrix world for cube, then I see this: after moving + localToWorld + updateMatrixWorld

var scene = new THREE.Scene();
scene.background = new THREE.Color().setStyle('#e0e0e0');
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 100000);
camera.position.set(0, 500, 3000);
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);

///////////////////////CREATE CUBE////////////////////////////////

const cube = new THREE.Mesh(
  new THREE.BoxBufferGeometry(1000, 1000, 1000),
  new THREE.MeshBasicMaterial({
    color: 'red',
    transparent: true,
    opacity: 0.4
  })
);
scene.add(cube);
//MOVE
cube.position.set(100, 100, 100);
//UPDATE
cube.updateMatrixWorld(true);

//GET EDGE LINES(THREE.Line3) FOR EDGES OF FACES 
const lines = getLinesFromFaces(cube);

//CONVERT FROM LOCAL TO WORLD
 lines.map(l => {
        //l.applyMatrix4(cube.matrixWorld);
        //l.start.applyMatrix4(cube.matrixWorld);
    //l.end.applyMatrix4(cube.matrixWorld);
    cube.localToWorld(l.start);
    cube.localToWorld(l.end);
  });

//DRAW
drawLines(lines);

function drawLines(lines) {
  for (let i = 0; i < lines.length; i += 1) {
    addLine(lines[i].start, lines[i].end);
  }
}

function addLine(p1, p2) {
  const material = new THREE.LineBasicMaterial({
    color: 0x0000ff
  });
  const points = [p1, p2];
  const geometry = new THREE.BufferGeometry().setFromPoints(points);

  const line = new THREE.Line(geometry, material);
  scene.add(line);
}

function getLinesFromFaces(object) {
  const facesWithPos = getFacesWithPos(object.geometry);
  const lines = [];
  for (let i = 0; i < facesWithPos.length; i += 1) {
    const f = facesWithPos[i];

    const lineAB = new THREE.Line3(f.a, f.b);
    let isExist = false;
    isExist = lines.some(l => {
      return (l.start.equals(lineAB.start) && l.end.equals(lineAB.end)) ||
        (l.start.equals(lineAB.end) && l.end.equals(lineAB.start));
    });
    if (!isExist) lines.push(lineAB);

    const lineBC = new THREE.Line3(f.b, f.c);
    isExist = false;
    isExist = lines.some(l => {
      return (l.start.equals(lineBC.start) && l.end.equals(lineBC.end)) ||
        (l.start.equals(lineBC.end) && l.end.equals(lineBC.start));
    });
    if (!isExist) lines.push(lineBC);

    const lineCA = new THREE.Line3(f.c, f.a);
    isExist = false;
    isExist = lines.some(l => {
      return (l.start.equals(lineCA.start) && l.end.equals(lineCA.end)) ||
        (l.start.equals(lineCA.end) && l.end.equals(lineCA.start));
    });
    if (!isExist) lines.push(lineCA);
  }

  return lines;
}

function getFacesWithPos(geometry) {
  const faces = getFaces(geometry);
  const facesWithPos = [];
  const position = geometry.getAttribute('position');
  for (let i = 0; i < faces.length; i += 1) {
    const f = faces[i];

    facesWithPos.push({
      a: new THREE.Vector3(position.array[f.a * 3], position.array[f.a * 3 + 1], position.array[f.a * 3 + 2]),
      b: new THREE.Vector3(position.array[f.b * 3], position.array[f.b * 3 + 1], position.array[f.b * 3 + 2]),
      c: new THREE.Vector3(position.array[f.c * 3], position.array[f.c * 3 + 1], position.array[f.c * 3 + 2])
    });
  }
  return facesWithPos;
}

function getFaces(geometry) {
  const faces = [];
  const index = geometry.getIndex();
  for (let i = 0; i < index.count; i += 3) {
    faces.push({
      a: index.getX(i),
      b: index.getX(i + 1),
      c: index.getX(i + 2)
    });
  }
  return faces;
}


render();

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.117.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.117.0/examples/js/controls/OrbitControls.js"></script>

How to get world coordinates? what am I doing wrong?


Solution

  • Some of the line points were common objects. If you apply localToWorld to them, then the method was applied to them several times and the result was not correct. Below is the solution

    var scene = new THREE.Scene();
    scene.background = new THREE.Color().setStyle('#e0e0e0');
    var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 100000);
    camera.position.set(0, 500, 3000);
    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);
    
    ///////////////////////CREATE CUBE////////////////////////////////
    
    const cube = new THREE.Mesh(
      new THREE.BoxBufferGeometry(1000, 1000, 1000),
      new THREE.MeshBasicMaterial({
        color: 'red',
        transparent: true,
        opacity: 0.4
      })
    );
    scene.add(cube);
    //MOVE
    cube.position.set(100, 100, 100);
    //UPDATE
    cube.updateMatrixWorld(true);
    
    //GET EDGE LINES(THREE.Line3) FOR EDGES OF FACES 
    const lines = getLinesFromFaces(cube);
    
    //CONVERT FROM LOCAL TO WORLD
     lines.map(l => {
            //l.applyMatrix4(cube.matrixWorld);
            //l.start.applyMatrix4(cube.matrixWorld);
        //l.end.applyMatrix4(cube.matrixWorld);
        cube.localToWorld(l.start);
        cube.localToWorld(l.end);
      });
    
    //DRAW
    drawLines(lines);
    
    function drawLines(lines) {
      for (let i = 0; i < lines.length; i += 1) {
        addLine(lines[i].start, lines[i].end);
      }
    }
    
    function addLine(p1, p2) {
      const material = new THREE.LineBasicMaterial({
        color: 0x0000ff
      });
      const points = [p1, p2];
      const geometry = new THREE.BufferGeometry().setFromPoints(points);
    
      const line = new THREE.Line(geometry, material);
      scene.add(line);
    }
    
    function getLinesFromFaces(object) {
      const facesWithPos = getFacesWithPos(object.geometry);
      const lines = [];
      for (let i = 0; i < facesWithPos.length; i += 1) {
        const f = facesWithPos[i];
    
        const lineAB = new THREE.Line3(f.a, f.b);
        let isExist = false;
        isExist = lines.some(l => {
          return (l.start.equals(lineAB.start) && l.end.equals(lineAB.end)) ||
            (l.start.equals(lineAB.end) && l.end.equals(lineAB.start));
        });
        if (!isExist) lines.push(lineAB.clone());
    
        const lineBC = new THREE.Line3(f.b, f.c);
        isExist = false;
        isExist = lines.some(l => {
          return (l.start.equals(lineBC.start) && l.end.equals(lineBC.end)) ||
            (l.start.equals(lineBC.end) && l.end.equals(lineBC.start));
        });
        if (!isExist) lines.push(lineBC.clone());
    
        const lineCA = new THREE.Line3(f.c, f.a);
        isExist = false;
        isExist = lines.some(l => {
          return (l.start.equals(lineCA.start) && l.end.equals(lineCA.end)) ||
            (l.start.equals(lineCA.end) && l.end.equals(lineCA.start));
        });
        if (!isExist) lines.push(lineCA.clone());
      }
    
      return lines;
    }
    
    function getFacesWithPos(geometry) {
      const faces = getFaces(geometry);
      const facesWithPos = [];
      const position = geometry.getAttribute('position');
      for (let i = 0; i < faces.length; i += 1) {
        const f = faces[i];
    
        facesWithPos.push({
          a: new THREE.Vector3(position.array[f.a * 3], position.array[f.a * 3 + 1], position.array[f.a * 3 + 2]),
          b: new THREE.Vector3(position.array[f.b * 3], position.array[f.b * 3 + 1], position.array[f.b * 3 + 2]),
          c: new THREE.Vector3(position.array[f.c * 3], position.array[f.c * 3 + 1], position.array[f.c * 3 + 2])
        });
      }
      return facesWithPos;
    }
    
    function getFaces(geometry) {
      const faces = [];
      const index = geometry.getIndex();
      for (let i = 0; i < index.count; i += 3) {
        faces.push({
          a: index.getX(i),
          b: index.getX(i + 1),
          c: index.getX(i + 2)
        });
      }
      return faces;
    }
    
    
    render();
    
    function render() {
      requestAnimationFrame(render);
      renderer.render(scene, camera);
    }
    body {
      overflow: hidden;
      margin: 0;
    }
    <script src="https://cdn.jsdelivr.net/npm/three@0.117.0/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.117.0/examples/js/controls/OrbitControls.js"></script>