Skip to content

Instantly share code, notes, and snippets.

@promontis
Created October 11, 2020 12:11
Show Gist options
  • Save promontis/cced5498e7fdf64e9ac0bfdb83ee2c06 to your computer and use it in GitHub Desktop.
Save promontis/cced5498e7fdf64e9ac0bfdb83ee2c06 to your computer and use it in GitHub Desktop.
interface Props {
object: three.Object3D | undefined;
}
export const Gizmo = (props: Props) => {
const [scale, setScale] = useState(new three.Vector3());
useFrame(({ camera }) => {
if (!props.object) {
return;
}
const worldPosition = new three.Vector3();
const worldQuaternion = new three.Quaternion();
const worldScale = new three.Vector3();
props.object.matrixWorld.decompose(worldPosition, worldQuaternion, worldScale);
let factor;
if (camera.type === "OrthographicCamera") {
factor = (camera.top - camera.bottom) / camera.zoom;
} else {
const worldPosition = new three.Vector3();
const worldQuaternion = new three.Quaternion();
const worldScale = new three.Vector3();
props.object.matrixWorld.decompose(worldPosition, worldQuaternion, worldScale);
factor = worldPosition.distanceTo(camera.position) * Math.min(1.9 * Math.tan(Math.PI * camera.fov / 360) / camera.zoom, 7);
}
setScale(new three.Vector3().set(1, 1, 1).multiplyScalar(factor / 7));
});
const points = useMemo(() => {
if (!props.object) {
return null;
}
const box = new three.Box3();
box.setFromObject(props.object);
const min = box.min;
const max = box.max;
const y = 0.01;
const point0 = new three.Vector3(min.x, y, max.z);
const point1 = new three.Vector3(max.x, y, max.z);
const point2 = new three.Vector3(max.x, y, min.z);
const point3 = new three.Vector3(min.x, y, min.z);
const base = [
point0, point1,
point1, point2,
point2, point3,
point3, point0
];
const centerX = (min.x + max.x) / 2;
const centerZ = (min.z + max.z) / 2;
const midDown = new three.Vector3(centerX, y, centerZ);
const midUp = new three.Vector3(centerX, max.y, centerZ);
const line = [midDown, midUp];
const midXMinZ = new three.Vector3(centerX, 0, min.z);
const midXMaxZ = new three.Vector3(centerX, 0, max.z);
const midZMinX = new three.Vector3(min.x, 0, centerZ);
const midZMaxX = new three.Vector3(max.x, 0, centerZ);
return {
point0,
point1,
point2,
point3,
base,
line,
midXMinZ,
midXMaxZ,
midZMinX,
midZMaxX
};
}, [props.object]);
const corner = useMemo(() =>
<>
<Billboard size={0.05 * 1.6} color={new three.Color("black")} />
<Billboard size={0.05} color={new three.Color("white")} />
</>, []);
const mid = useMemo(() =>
<>
<Billboard size={0.05} color={new three.Color("black")} />
</>, []);
if (!props.object || !points) {
return null;
}
return (
<group>
<lineSegments onUpdate={self => self.computeLineDistances()}>
<geometry attach="geometry" vertices={points.base} />
<lineDashedMaterial color="black" dashSize={.8} gapSize={.4} attach="material" depthTest={false} />
</lineSegments>
<lineSegments onUpdate={self => self.computeLineDistances()}>
<geometry attach="geometry" vertices={points.line} />
<lineDashedMaterial color="black" dashSize={.8} gapSize={.4} attach="material" depthTest={false} />
</lineSegments>
<EndPoint position={points.point0} scale={scale}>{corner}</EndPoint>
<EndPoint position={points.point1} scale={scale}>{corner}</EndPoint>
<EndPoint position={points.point2} scale={scale}>{corner}</EndPoint>
<EndPoint position={points.point3} scale={scale}>{corner}</EndPoint>
<EndPoint position={points.line[1]} scale={scale}>{corner}</EndPoint>
<EndPoint position={points.midXMinZ} scale={scale}>{mid}</EndPoint>
<EndPoint position={points.midXMaxZ} scale={scale}>{mid}</EndPoint>
<EndPoint position={points.midZMinX} scale={scale}>{mid}</EndPoint>
<EndPoint position={points.midZMaxX} scale={scale}>{mid}</EndPoint>
</group>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment