pnext / three-loader

Point cloud loader for ThreeJS, based on the core parts of Potree
Other
194 stars 88 forks source link

Provide a minimum example #4

Closed Ailrun closed 6 years ago

Ailrun commented 6 years ago

I tried following code, but it didn't work.

const renderer = new THREE.WebGLRenderer();
renderer.setSize(0, 0);

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, NaN, 0.1, 1000);

const potree = new Potree();

const el = document.getElementById('target');
const { width, height } = el.getBoundingClientRect();
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
el.appendChild(renderer.domElement);

potree.loadPointCloud('', (url) => `http://localhost:4000/${url}`)
  .then((pco) => {
    scene.add(pco);
    scene.updateMatrix();
  })
  .catch((err) => {
    console.log(err);
  });

Observable.interval(0, Scheduler.animationFrame)
  .map(() => {
    renderer.render(scene, camera);
  })
  .subscribe();

(My server (on localhost:4000) works fine and client get r.hrc and r.bin successfully, so it's probably client-side problem...)

Could you please provide a minimum example? Or could you give me hints to fix my invalid code?

Ailrun commented 6 years ago

Now I know How can display it (after long time of inspecting repo codes... :( ).

const renderer = new THREE.WebGLRenderer();
renderer.setSize(0, 0);

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, NaN, 0.1, 1000);

const potree = new Potree();

const el = document.getElementById('target');
const { width, height } = el.getBoundingClientRect();
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
el.appendChild(renderer.domElement);

potree.loadPointCloud('', (url) => `http://localhost:4000/${url}`)
  .then((pco) => {
    pco.material = new Potree.PointCloudMaterial({
      // Some options... (I use `size`s)
    });
    pco.toTreeNode(pco.root);
    scene.add(pco);
    scene.updateMatrix();
  })
  .catch((err) => {
    console.log(err);
  });

Observable.interval(0, Scheduler.animationFrame)
  .map(() => {
    renderer.render(scene, camera);
  })
  .subscribe();

I doubt that this is best way to do this. It looks like there may exist a simpler way to do it

    pco.material = new Potree.PointCloudMaterial({
      // Some options... (I use `size`s)
    });
    pco.toTreeNode(pco.root);
    scene.add(pco);

since it updates pco.root by passing pco.root.

and I still don't know how can load things hierarchically in valid way...

Ailrun commented 6 years ago

https://github.com/Ailrun/three-potree-loader-example

hccampos commented 6 years ago

Hi @Ailrun, I am glad you found a way to make some of it work and really appreciate you trying to come up with an example.

What seems to be missing in your code is calling potree.updatePointClouds([pco], camera, renderer) every frame, or at least whenever your camera moves/changes. This is the method which keeps the octree and update-to-date by updating node visibilities and loading/unloading necessary nodes.

That being said, there should probably be some refactoring to support calling update directly on a single PointCloudOctree. The original Potree doesn't do it because it keeps track of the maximum number of points and keeps a global LRU queue to check which nodes need to be unloaded.

Ailrun commented 6 years ago

@hccampos Thank you for your kind and detail answer! I really appriciate it. I will try it and if it works greatly I will update example too!

Also, can I send a PR for including example to readme?

hccampos commented 6 years ago

@Ailrun No problem, am I really happy to help. And a PR for the example would be super great. Could you try to remove the rxjs dependency and instead just use requestAnimationFrame? We are also using rxjs at Pix4D but I felt like it was nicer to keep the potree loader as independent as possible.

Ailrun commented 6 years ago

Of course! It's just added for simplicity for my try-and-error experiments. When I update it I also remove the dependency.

hccampos commented 6 years ago

@Ailrun Cool! In the meantime I updated some stuff in your example and made it work on CodeSandbox. It also has some comments.

https://codesandbox.io/s/yw2p3446j9?autoresize=1&view=preview

Ailrun commented 6 years ago

@hccampos Can I make one more question? ~How can I load other binaries (r[numbers].bins)? Should I use pcoGeometry.root.traverse?~

(After trying some more things) Or, more accurate question is, how can I set valid camera position for specific point cloud?

const renderer = new THREE.WebGLRenderer();
const camera = new THREE.PerspectiveCamera(45, NaN, 0.001, 100000);
camera.position.set(0, 0, 0);
camera.up = new THREE.Vector3(0, 0, 1);
camera.updateMatrixWorld();

const orbitControls = new OrbitControls(camera, el);
const scene = new THREE.Scene();

updateSize(renderer, camera, el); // also updates aspect of camera

// ...

const { frustums, priorityQueue } = potree.updateVisibilityStructures([pco], camera);
const [ frustum ] = frustums;
const element = priorityQueue.pop();
const node = element.node;
console.log(frustum.intersectsBox(node.boundingBox));

Logs false for my point cloud.... (I also tried with camera of position/quaternian that was able to see whole point cloud when I call manually pco.toTreeNode(pco.root);)

Ailrun commented 6 years ago

Can I use something like https://github.com/potree/potree/blob/916e388069adc962d40fbf30209c0be704878675/src/scenegraph/Camera.js#L177 this one?

hccampos commented 6 years ago

Yes, you can use something like that, but it is more of a generic ThreeJS thing. I have seen some examples on StackOverflow and/or on the ThreeJS forum.

https://discourse.threejs.org/t/camera-zoom-to-fit-object/936/2

Ailrun commented 6 years ago

@hccampos Actually I made that question because potree makes its frustom in somewhat different way from normal three.js way.

Usually in three.js, frustom set from camera.projectionMatrix times camera.matrixWordlInverse, where in potree, we mutliply pco.matrixWorld too, so I though it's not general question about three.js.

Ailrun commented 6 years ago

To make it equal (A B C = A B, so if A B is inversible, C should be the identity matrix), I should make pco.matrixWorld equal to identity matrix, i.e. set pco.position to (0, 0, 0). So, finally I make a working example...