npm install, then npm start to open the development demo at http://localhost:5200.npm run build:example from the repository root to build the example into build/, including index.html, the bundled code, and point-cloud data. Serve that directory over HTTP at the server root with support for byte-range requests.PointShape), opacity type (PointOpacityType), and color type (PointColorType).
npm install and npm run build.const scene = new Scene();
const camera = new PerspectiveCamera(60, 1, 0.1, 10000);
const canvas = document.getElementById("canvas");
const renderer = new WebGLRenderer({canvas:canvas});
const geometry = new BoxGeometry(1, 1, 1);
const material = new MeshBasicMaterial({color: 0x00ff00});
const cube = new Mesh(geometry, material);
scene.add(cube);
const controls = new OrbitControls(camera, canvas);
camera.position.z = 10;
const pointClouds = [];
const baseUrl = "data/test/";
const potree = new Potree();
potree.loadPointCloud("cloud.js", baseUrl).then(function(pco) {
scene.add(pco);
pointClouds.push(pco);
});
function loop()
{
potree.updatePointClouds(pointClouds, camera, renderer);
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(loop);
};
loop();
PointShape.CLOSED reconstructs small gaps between points with screen-space binary closing. Use PotreeRenderer to run its multiple passes:
import { PointShape, PotreeRenderer } from 'potree-core';
pco.material.shape = PointShape.CLOSED;
const pointRenderer = new PotreeRenderer({
closed: { radius: 2, depthThreshold: 0.02 },
edl: { enabled: false },
});
// Each animation frame:
pointRenderer.updateAndRender(potree, pointClouds, camera, renderer, scene);
// Change settings at runtime:
pointRenderer.setClosed({ radius: 3 });
// When finished (clouds and the three.js renderer remain caller-owned):
pointRenderer.dispose();
renderer.render() directly displays only these samples; closing requires PotreeRenderer.radius defaults to 2 physical pixels, rounds to an integer, and clamps to 1–4. Larger radii fill larger gaps and cost more GPU time. Viewport padding preserves samples at image boundaries.depthThreshold of the closest depth contribute; the default 0.02 means 2% of that depth. The tolerance is nonnegative and does not change the binary mask. Separate clouds never interpolate together.PointColorType.NORMAL displays them as view-space RGB (normal * 0.5 + 0.5). If a cloud lacks normals, this mode estimates them from neighbouring reconstructed depths, falling back to a camera-facing normal for isolated points.EXT_color_buffer_float; an unsupported context throws an explicit error. Four RGBA32F attribute textures, an R8 mask, and a depth buffer are reused between clouds (roughly 137 MiB at 1920×1080, plus padding and any EDL target). Release them with PotreeRenderer.dispose().Select Closed in the demo’s Points → Shape control. Closing Radius (px) and Closing Depth Tolerance adjust reconstruction.
Run npm run build followed by node tests/run-browser-checks.mjs for the Chromium GPU regression checks. Set BROWSER_PATH if Chromium is installed outside the detected paths. The checks compare the GPU mask against a binary morphology reference, exercise interpolation, depth, clipping and renderer state, and load both bundled cloud formats. Preview images and results are written to build/browser-checks/. To also exercise the demo, first run npm run build:example, then set CHECK_DEMO=1 when running the checks.
createClipBox(size, position, mode?) to build an IClipBox.mode?: "include" | "exclude".include: clip-outside semantics for that volume (inside can stay visible).exclude: clip-inside semantics for that volume (inside is removed).mode is undefined, that volume inherits the global material clipMode.ClipMode.DISABLED is a global master off switch and disables all clipping/highlighting.B = (!hasIncludeVolumes || insideAnyInclude) && !insideAnyExcludeP = insideAllPlanesS = hasBoxOrSphereCLIP_OUTSIDE: visible = B && PCLIP_INSIDE: visible = (S && B) || !PClipMode.HIGHLIGHT_INSIDE is still supported through inheritance (mode undefined) and only highlights without changing visibility.insideAllPlanes (point is on the positive side of all planes).P, so plane-only behavior falls out naturally from the same equations.import { ClipMode, createClipBox } from 'potree-core';
import { Vector3 } from 'three';
pco.material.clipMode = ClipMode.CLIP_OUTSIDE; // global fallback for undefined volume modes
const includeA = createClipBox(new Vector3(10, 10, 10), new Vector3(0, 0, 0), 'include');
const excludeB = createClipBox(new Vector3(4, 4, 4), new Vector3(0, 0, 0), 'exclude');
const inheritedD = createClipBox(new Vector3(3, 3, 3), new Vector3(-3, 0, 0)); // inherits CLIP_OUTSIDE
pco.material.setClipBoxes([includeA, excludeB, inheritedD]);
createClipSphere(center, radius, mode?) to build an IClipSphere.mode?: "include" | "exclude".mode is undefined, the sphere inherits the global material clipMode.P = insideAllPlanes in the visibility formulas above.import { ClipMode, createClipSphere } from 'potree-core';
import { Vector3 } from 'three';
pco.material.clipMode = ClipMode.HIGHLIGHT_INSIDE;
const sphereA = createClipSphere(new Vector3(0, 1, 0), 3, 'exclude');
const sphereB = createClipSphere(new Vector3(5, 1, 0), 2); // inherits HIGHLIGHT_INSIDE
pco.material.setClipSpheres([sphereA, sphereB]);
class CustomRequestManager implements RequestManager
{
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
throw new Error("Method not implemented.")
}
async getUrl(url: string): Promise<string> {
return url;
}
}
PotreeRenderer with edl: {enabled: true}, see example/main.ts..\PotreeConverter '..\input.laz' -o ../output.\txt2las64 -i input.pts -ipts -parse xyziRGB -set_scale 0.001 0.001 0.001 -set_version 1.4 -o output.laz### To Do