Where is threshold measured from in LOD?

I’m doing LOD rendering for multiple objects. Im confused about where the threshold is measured from.

I have a demo that works except the high and low resolution meshes are swapped out for both the red and blue dots at the same camera position, despite them having different bounding areas and origins.

import { Canvas } from "@react-three/fiber";
import { generateCubePoints } from "./generateCubePoints";
import {
  CameraControls,
  PerspectiveCamera,
  Detailed,
  GizmoHelper,
  GizmoViewport,
} from "@react-three/drei";

export const ITEMS_PER_ROW = 3;

const mockBounds = {
  minX: -40,
  maxX: 40,
  minY: -40,
  maxY: 40,
  minZ: -40,
  maxZ: 40,
};
const mockBounds1 = {
  minX: mockBounds.minX,
  maxX: 0,
  minY: mockBounds.minY,
  maxY: mockBounds.maxY,
  minZ: mockBounds.minZ,
  maxZ: mockBounds.maxZ,
};
const mockBounds2 = {
  minX: 0,
  maxX: mockBounds.maxX,
  minY: mockBounds.minY,
  maxY: mockBounds.maxY,
  minZ: mockBounds.minZ,
  maxZ: mockBounds.maxZ,
};

const mockPoints = [
  {
    color: "red",
    bounds: mockBounds1,
    points: [
      generateCubePoints({
        bounds: mockBounds1,
        numPoints: 1000,
      }),
      generateCubePoints({
        bounds: mockBounds1,
        numPoints: 100,
      }),
    ],
  },
  {
    color: "blue",
    bounds: mockBounds2,
    points: [
      generateCubePoints({
        bounds: mockBounds2,
        numPoints: 1000,
      }),
      generateCubePoints({
        bounds: mockBounds2,
        numPoints: 100,
      }),
    ],
  },
] as const;

function App() {
  return (
      <Canvas>
        {mockPoints.map((pGroup, pGroupI) => {
          return (
            <Detailed distances={[0, 100]} key={pGroupI}>
              {pGroup.points.map((p, pI) => {
                return (
                  <points key={`${pGroupI}-${pI}`} renderOrder={0}>
                    <bufferGeometry>
                      <bufferAttribute
                        attach="attributes-position"
                        args={[p, ITEMS_PER_ROW]}
                        count={p.length / ITEMS_PER_ROW}
                      />
                    </bufferGeometry>
                    <pointsMaterial size={4} color={pGroup.color} />
                  </points>
                );
              })}
            </Detailed>
          );
        })}
      </Canvas>
  );
}

https://codesandbox.io/p/devbox/damp-rgb-forked-57783t?workspaceId=ws_ER7skizgVvGCRcwppmiBu

I got it working by setting position on the Detailed component, however this moved the points. So I then needed to set the negative of these values as the position on points:

{mockPoints.map((pGroup, pGroupI) => {
          const position = [
            (pGroup.bounds.minX + pGroup.bounds.maxX) / 2,
            (pGroup.bounds.minY + pGroup.bounds.maxY) / 2,
            (pGroup.bounds.minZ + pGroup.bounds.maxZ) / 2,
          ] as const;
          const positionNegative = [
            -position[0],
            -position[1],
            -position[2],
          ] as const;
          return (
            <Detailed distances={[0, 100]} key={pGroupI} position={position}>
              {pGroup.points.map((p, pI) => {
                return (
                  <points
                    key={`${pGroupI}-${pI}`}
                    renderOrder={0}
                    position={positionNegative}
                  >

https://codesandbox.io/p/devbox/damp-rgb-forked-r2z2fw?workspaceId=ws_ER7skizgVvGCRcwppmiBu

This seems to work but feels messy. Is there a better way?

Also I’m very concerned my performance. My real scene has over a million points and I’m really pushing the limits of what the browser can handle. So any performance savings I can do would be a great help.

Where is the threshold measured from in LOD?

From camera world position to object world position.

Only the origin matters - and “origin” in this case means the world position of the LOD object itself (not the objects contained as children of that LOD level.) Bboxes are irrelevant.

So is the world position of the LOD object ( in my case) always the centre of the scene by default?

If that is the case, is it possible to set its origin without moving its contents?

This feels like strange DX to me but I’m quite new to three.js.

That’s how LODs work everywhere - the distance is measured from the origin / centre of gravity of a mesh.

Unless you set position prop in Detailed - yup.

The way you’re doing it - ie. setting position of Detailed to actual position, then subtract the offset by setting the negative of that value in <points position /> would be the correct way. Alternatively, subtract that offset directly during points’ calculations - since it shouldn’t have been there in the first place :eyes:

1 Like