Add synthetic multi-view cue fusion

Co-authored-by: Luke The Dev <iamlukethedev@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-04-20 00:24:29 +00:00
co-authored by Luke The Dev
parent a1fd1afb7c
commit 31fba6d5d5
+89 -4
View File
@@ -385,6 +385,89 @@ const applyPortraitRelief = (intensityGrid) => {
return smoothGrid(refined, 1);
};
const estimateNormalLikeField = (intensityGrid) => {
const rows = intensityGrid.length;
const cols = intensityGrid[0]?.length ?? 0;
return intensityGrid.map((row, rowIndex) =>
row.map((value, colIndex) => {
const left = intensityGrid[rowIndex]?.[Math.max(0, colIndex - 1)] ?? value;
const right = intensityGrid[rowIndex]?.[Math.min(cols - 1, colIndex + 1)] ?? value;
const up = intensityGrid[Math.max(0, rowIndex - 1)]?.[colIndex] ?? value;
const down = intensityGrid[Math.min(rows - 1, rowIndex + 1)]?.[colIndex] ?? value;
const nx = clamp((right - left) * 0.5 + 0.5, 0, 1);
const ny = clamp((down - up) * 0.5 + 0.5, 0, 1);
return { nx, ny, depth: value };
}),
);
};
const rotateGrid180 = (grid) =>
grid
.slice()
.reverse()
.map((row) => row.slice().reverse());
const mirrorGridHorizontally = (grid) =>
grid.map((row) => row.slice().reverse());
const generateSyntheticViewSet = (intensityGrid, colorGrid) => {
const front = {
role: "front",
intensityGrid,
colorGrid,
normalGrid: estimateNormalLikeField(intensityGrid),
};
const sideIntensity = smoothGrid(mirrorGridHorizontally(intensityGrid), 1);
const sideColor = mirrorGridHorizontally(colorGrid);
const side = {
role: "side",
intensityGrid: sideIntensity,
colorGrid: sideColor,
normalGrid: estimateNormalLikeField(sideIntensity),
};
const backIntensity = smoothGrid(rotateGrid180(intensityGrid), 1);
const backColor = rotateGrid180(colorGrid);
const back = {
role: "back",
intensityGrid: backIntensity,
colorGrid: backColor,
normalGrid: estimateNormalLikeField(backIntensity),
};
return [front, side, back];
};
const fuseSyntheticViewSet = (views) => {
const fusedIntensity = fuseIntensityViews(views);
const fusedColor = fuseColorViews(views);
const fusedNormal = views[0]?.normalGrid?.map((row, rowIndex) =>
row.map((_, colIndex) => {
let totalX = 0;
let totalY = 0;
let totalDepth = 0;
let weightTotal = 0;
for (const view of views) {
const sample = view?.normalGrid?.[rowIndex]?.[colIndex];
if (!sample) continue;
const weight = roleWeight(view.role);
totalX += sample.nx * weight;
totalY += sample.ny * weight;
totalDepth += sample.depth * weight;
weightTotal += weight;
}
return {
nx: weightTotal > 0 ? totalX / weightTotal : 0.5,
ny: weightTotal > 0 ? totalY / weightTotal : 0.5,
depth: weightTotal > 0 ? totalDepth / weightTotal : 0.5,
};
}),
) ?? [];
return {
intensityGrid: fusedIntensity,
colorGrid: fusedColor,
normalGrid: fusedNormal,
};
};
const samplePalette = (params) => {
const { raster, buffer } = params;
const buckets = new Map();
@@ -748,15 +831,17 @@ const createPortraitVolumeAdapter = () => ({
};
const sampleParams = { raster, buffer: params.buffer };
const palette = samplePalette(sampleParams);
const intensityGrid = Array.isArray(params.fusedIntensityGrid) && params.fusedIntensityGrid.length > 0
const baseIntensityGrid = Array.isArray(params.fusedIntensityGrid) && params.fusedIntensityGrid.length > 0
? params.fusedIntensityGrid
: sampleIntensityGrid(sampleParams, 18);
const colorGrid = Array.isArray(params.fusedColorGrid) && params.fusedColorGrid.length > 0
const baseColorGrid = Array.isArray(params.fusedColorGrid) && params.fusedColorGrid.length > 0
? params.fusedColorGrid
: sampleColorGrid(sampleParams, 18);
const syntheticViews = generateSyntheticViewSet(baseIntensityGrid, baseColorGrid);
const fusedViews = fuseSyntheticViewSet(syntheticViews);
const glb = await createPortraitVolumeScene({
colorGrid,
intensityGrid,
colorGrid: fusedViews.colorGrid,
intensityGrid: fusedViews.intensityGrid,
palette,
width: size.width,
height: size.height,