Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 25 additions & 123 deletions src/SparkXr.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import * as THREE from "three";
import { SplatMesh } from "./SplatMesh";
import {
FINGER_TIPS,
HANDS,
Hand,
JOINT_IDS,
JOINT_INDEX,
JOINT_RADIUS,
JOINT_SEGMENTS,
JOINT_SEGMENT_STEPS,
JOINT_TIPS,
JointEnum,
type JointId,
NUM_JOINTS,
} from "./hands";

export interface SparkXrOptions {
renderer: THREE.WebGLRenderer;
Expand Down Expand Up @@ -123,118 +137,6 @@ export const DEFAULT_CONTROLLER_GETSLOW = (
) =>
gamepads.rightIsHand ? false : (gamepads.right?.buttons[1]?.pressed ?? false);

export enum JointEnum {
w = "wrist",
t0 = "thumb-metacarpal",
t1 = "thumb-phalanx-proximal",
t2 = "thumb-phalanx-distal",
t3 = "thumb-tip",
i0 = "index-finger-metacarpal",
i1 = "index-finger-phalanx-proximal",
i2 = "index-finger-phalanx-intermediate",
i3 = "index-finger-phalanx-distal",
i4 = "index-finger-tip",
m0 = "middle-finger-metacarpal",
m1 = "middle-finger-phalanx-proximal",
m2 = "middle-finger-phalanx-intermediate",
m3 = "middle-finger-phalanx-distal",
m4 = "middle-finger-tip",
r0 = "ring-finger-metacarpal",
r1 = "ring-finger-phalanx-proximal",
r2 = "ring-finger-phalanx-intermediate",
r3 = "ring-finger-phalanx-distal",
r4 = "ring-finger-tip",
p0 = "pinky-finger-metacarpal",
p1 = "pinky-finger-phalanx-proximal",
p2 = "pinky-finger-phalanx-intermediate",
p3 = "pinky-finger-phalanx-distal",
p4 = "pinky-finger-tip",
}
export type JointId = keyof typeof JointEnum;
export const JOINT_IDS = Object.keys(JointEnum) as JointId[];
export const NUM_JOINTS = JOINT_IDS.length;

export const JOINT_INDEX: { [key in JointId]: number } = {
w: 0,
t0: 1,
t1: 2,
t2: 3,
t3: 4,
i0: 5,
i1: 6,
i2: 7,
i3: 8,
i4: 9,
m0: 10,
m1: 11,
m2: 12,
m3: 13,
m4: 14,
r0: 15,
r1: 16,
r2: 17,
r3: 18,
r4: 19,
p0: 20,
p1: 21,
p2: 22,
p3: 23,
p4: 24,
};

export const JOINT_RADIUS: { [key in JointId]: number } = {
w: 0.02,
t0: 0.015,
t1: 0.012,
t2: 0.0105,
t3: 0.0085,
i0: 0.022,
i1: 0.012,
i2: 0.0085,
i3: 0.0075,
i4: 0.0065,
m0: 0.021,
m1: 0.012,
m2: 0.008,
m3: 0.0075,
m4: 0.0065,
r0: 0.019,
r1: 0.011,
r2: 0.0075,
r3: 0.007,
r4: 0.006,
p0: 0.012,
p1: 0.01,
p2: 0.007,
p3: 0.0065,
p4: 0.0055,
};

export const JOINT_SEGMENTS: JointId[][] = [
["w", "t0", "t1", "t2", "t3"],
["w", "i0", "i1", "i2", "i3", "i4"],
["w", "m0", "m1", "m2", "m3", "m4"],
["w", "r0", "r1", "r2", "r3", "r4"],
["w", "p0", "p1", "p2", "p3", "p4"],
];

export const JOINT_SEGMENT_STEPS: number[][] = [
[8, 10, 8, 6],
[8, 19, 14, 8, 6],
[8, 19, 14, 8, 6],
[8, 19, 14, 8, 6],
[8, 19, 14, 8, 6],
];

export const JOINT_TIPS: JointId[] = ["t3", "i4", "m4", "r4", "p4"];
export const FINGER_TIPS: JointId[] = ["i4", "m4", "r4", "p4"];

export enum Hand {
left = "left",
right = "right",
}
export const HANDS = Object.keys(Hand) as Hand[];

const XR_HEADSET_HINTS =
/Quest|OculusBrowser|VisionOS|XRBrowser|Pico|Lynx|MagicLeap/i;

Expand Down Expand Up @@ -540,17 +442,17 @@ export class SparkXr {
return !!this.xr;
}

static JointEnum = JointEnum;
static JOINT_IDS = JOINT_IDS;
static NUM_JOINTS = NUM_JOINTS;
static JOINT_INDEX = JOINT_INDEX;
static JOINT_RADIUS = JOINT_RADIUS;
static JOINT_SEGMENTS = JOINT_SEGMENTS;
static JOINT_SEGMENT_STEPS = JOINT_SEGMENT_STEPS;
static JOINT_TIPS = JOINT_TIPS;
static FINGER_TIPS = FINGER_TIPS;
static Hand = Hand;
static HANDS = HANDS;
static readonly JointEnum = JointEnum;
static readonly JOINT_IDS = JOINT_IDS;
static readonly NUM_JOINTS = NUM_JOINTS;
static readonly JOINT_INDEX = JOINT_INDEX;
static readonly JOINT_RADIUS = JOINT_RADIUS;
static readonly JOINT_SEGMENTS = JOINT_SEGMENTS;
static readonly JOINT_SEGMENT_STEPS = JOINT_SEGMENT_STEPS;
static readonly JOINT_TIPS = JOINT_TIPS;
static readonly FINGER_TIPS = FINGER_TIPS;
static readonly Hand = Hand;
static readonly HANDS = HANDS;

left() {
return this.hands[0];
Expand Down
4 changes: 2 additions & 2 deletions src/SplatAccumulator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as THREE from "three";
import { FullScreenQuad } from "three/addons/postprocessing/Pass.js";
import { Readback } from "./Readback";
import { SplatEdit } from "./SplatEdit";
import { type SplatEdit, isSplatEdit } from "./SplatEdit";
import {
type CovSplatGenerator,
type GsplatGenerator,
Expand Down Expand Up @@ -481,7 +481,7 @@ export class SplatAccumulator {

const globalEditsSet = new Set<SplatEdit>();
scene.traverseVisible((node) => {
if (node instanceof SplatEdit) {
if (isSplatEdit(node)) {
let ancestor = node.parent;
while (ancestor != null && !(ancestor instanceof SplatMesh)) {
ancestor = ancestor.parent;
Expand Down
13 changes: 12 additions & 1 deletion src/SplatEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
unindent,
unindentLines,
} from "./dyno";
import { newArray } from "./utils";

// Spark provides the ability to apply "edits" to Gsplats as part of the standard
// SplatMesh pipeline. These edits take the form of a sequence of operations,
Expand Down Expand Up @@ -127,6 +126,8 @@ export type SplatEditSdfOptions = {
};

export class SplatEditSdf extends THREE.Object3D {
readonly isSplatEditSdf = true;

type: SplatEditSdfType;
invert: boolean;
opacity: number;
Expand All @@ -146,6 +147,10 @@ export class SplatEditSdf extends THREE.Object3D {
}
}

export function isSplatEditSdf(obj: THREE.Object3D): obj is SplatEditSdf {
return (obj as SplatEditSdf).isSplatEditSdf;
}

export type SplatEditOptions = {
// Name of this edit operation. If you omit it, a default "Edit 1", "Edit 2", ...
// is assigned.
Expand All @@ -167,6 +172,8 @@ export type SplatEditOptions = {
};

export class SplatEdit extends THREE.Object3D {
readonly isSplatEdit = true;

// ordering used to apply SplatEdit operations to Gsplats. This is implicitly
// increased with each new SplatEdit. Reassigning ordering can be used to
// reorder the operations.
Expand Down Expand Up @@ -222,6 +229,10 @@ export class SplatEdit extends THREE.Object3D {
}
}

export function isSplatEdit(obj: THREE.Object3D): obj is SplatEdit {
return (obj as SplatEdit).isSplatEdit;
}

// Dyno implementation of RGBA-XYZ SDF editing.
// The SDFs are encoded in a texture while the edits are encoded
// as a uniform uvec4 array.
Expand Down
12 changes: 9 additions & 3 deletions src/SplatMesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import {
import { ExtSplats } from "./ExtSplats";
import { PackedSplats } from "./PackedSplats";
import { type RgbaArray, TRgbaArray } from "./RgbaArray";
import { SplatEdit, SplatEditSdf, SplatEdits } from "./SplatEdit";
import {
type SplatEdit,
type SplatEditSdf,
SplatEdits,
isSplatEdit,
isSplatEditSdf,
} from "./SplatEdit";
import {
type CovSplatModifier,
CovSplatTransformer,
Expand Down Expand Up @@ -946,7 +952,7 @@ export class SplatMesh extends SplatGenerator {
if (this.editable && !this.edits) {
// If we haven't set any explicit edits, add any child SplatEdits
this.traverseVisible((node) => {
if (node instanceof SplatEdit) {
if (isSplatEdit(node)) {
edits.push(node);
}
});
Expand All @@ -959,7 +965,7 @@ export class SplatMesh extends SplatGenerator {
}
const sdfs: SplatEditSdf[] = [];
edit.traverseVisible((node) => {
if (node instanceof SplatEditSdf) {
if (isSplatEditSdf(node)) {
sdfs.push(node);
}
});
Expand Down
18 changes: 9 additions & 9 deletions src/SplatSkinning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,11 +313,11 @@ export class SplatSkinning {
this.mesh.needsUpdate = true;
}

private static UNIT_SCALE = new THREE.Vector3(1, 1, 1);
private static relQuat = new THREE.Quaternion();
private static relPos = new THREE.Vector3();
private static dual = new THREE.Quaternion();
private static skinMat = new THREE.Matrix4();
private static readonly UNIT_SCALE = /*@__PURE__*/ new THREE.Vector3(1, 1, 1);
private static readonly relQuat = /*@__PURE__*/ new THREE.Quaternion();
private static readonly relPos = /*@__PURE__*/ new THREE.Vector3();
private static readonly dual = /*@__PURE__*/ new THREE.Quaternion();
private static readonly skinMat = /*@__PURE__*/ new THREE.Matrix4();
}

// dyno program definitions for SplatSkinning
Expand All @@ -326,7 +326,7 @@ export const GsplatSkinning = { type: "GsplatSkinning" } as {
type: "GsplatSkinning";
};

export const defineGsplatSkinning = unindent(`
export const defineGsplatSkinning = /*@__PURE__*/ unindent(`
struct GsplatSkinning {
int numSplats;
int numBones;
Expand All @@ -335,7 +335,7 @@ export const defineGsplatSkinning = unindent(`
};
`);

export const defineApplyGsplatSkinning = unindent(`
export const defineApplyGsplatSkinning = /*@__PURE__*/ unindent(`
void applyGsplatSkinning(
int numSplats, int numBones,
usampler2DArray skinTexture, sampler2D boneTexture,
Expand Down Expand Up @@ -426,7 +426,7 @@ function applyGsplatSkinning(
return dyno.outputs.gsplat;
}

export const defineApplyCovSplatDQSkinning = unindent(`
export const defineApplyCovSplatDQSkinning = /*@__PURE__*/ unindent(`
void applyCovSplatDQSkinning(
int numSplats, int numBones,
usampler2DArray skinTexture, sampler2D boneTexture,
Expand Down Expand Up @@ -492,7 +492,7 @@ export const defineApplyCovSplatDQSkinning = unindent(`
}
`);

export const defineApplyCovSplatLBSkinning = unindent(`
export const defineApplyCovSplatLBSkinning = /*@__PURE__*/ unindent(`
void applyCovSplatLBSkinning(
int numSplats, int numBones,
usampler2DArray skinTexture, sampler2D boneTexture,
Expand Down
Loading
Loading