Skip to content
Back to skills

Clift Light Field Tokens

ASecurity

Represent 3D scenes as compressed light-field tokens for efficient neural rendering. Multi-view images are tokenized via Plücker coordinates, condensed through K-means clustering, and rendered adaptively. Achieves 5-7× data reduction versus MVSplat while enabling on-the-fly quality-speed tradeoffs: up to 66% FPS improvement with controlled token counts.

  • 6 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 9, 2026
developmentpython

Works with

  • cli

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add ADu2021/skillXiv --skill clift-light-field-tokens --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Clift Light Field Tokens?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Clift Light Field Tokens
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/adu2021-clift-light-field-tokens/badge)](https://www.skillsdirectory.com/skills/adu2021-clift-light-field-tokens)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: clift-light-field-tokens
title: "CLiFT: Compressive Light-Field Tokens for Compute-Efficient and Adaptive Neural Rendering"
version: 0.0.2
engine: skillxiv-v0.0.2-claude-opus-4.6
license: MIT
url: "https://arxiv.org/abs/2507.08776"
keywords: [3D Rendering, Light Field Compression, Neural Radiance, Adaptive Rendering]
description: "Represent 3D scenes as compressed light-field tokens for efficient neural rendering. Multi-view images are tokenized via Plücker coordinates, condensed through K-means clustering, and rendered adaptively. Achieves 5-7× data reduction versus MVSplat while enabling on-the-fly quality-speed tradeoffs: up to 66% FPS improvement with controlled token counts."
---

# CLiFT: Adaptive Light-Field Token Compression for Real-time 3D Rendering

Neural rendering typically requires storing full multi-view image data or learning dense radiance fields. Light fields—high-dimensional representations of scene appearance—are extremely data-heavy. CLiFT compresses light-field information into learned tokens representing semantic scene content, enabling dramatic data reduction (5-7×) while maintaining rendering quality. Crucially, by controlling the number of tokens used at render time, you get flexible quality-speed tradeoffs: use 256 tokens for high quality, or 100 tokens for 66% speedup.

The key insight is that most light-field information is redundant within small spatial regions. By identifying clusters of similar rays (Plücker-coordinate based) and keeping only their centroids, you compress aggressively while preserving the geometric and appearance information needed for novel-view synthesis.

## Core Concept

CLiFT operates in three stages:

1. **Multi-view Encoding**: Transform input images into light-field tokens using Plücker ray coordinates (captures both position and direction) concatenated with RGB
2. **Latent K-means Clustering**: Identify semantic clusters in feature space; select nearest neighbor from each cluster as centroid (lossless per-cluster representative selection)
3. **Neural Rendering**: Lightweight Transformer condenses tokens into a compact representation, then decodes to novel views with adaptive token counts

The method decouples storage tokens (Nₛ) from rendering tokens (Nᵣ), enabling post-hoc quality adjustment without retraining.

## Architecture Overview

- **Plücker Encoder**: Converts 3D rays to 6D Plücker coordinates (position + direction) to capture geometric structure
- **Multi-view Transformer Encoder**: Tokenizes input images with geometric constraints
- **K-means Clustering Module**: Groups similar rays; identifies cluster centroids via nearest-neighbor selection
- **Token Condensation Network**: Lightweight Transformer compressing K clusters into Nᵣ rendering tokens
- **Adaptive Rendering Head**: Produces novel views from selected tokens using positional encoding
- **View-dependent Decoder**: MLP network predicting appearance based on viewing direction
- **Learnable Cluster Parameters**: Mean and variance per cluster maintained during training

## Implementation

The following demonstrates light-field tokenization and adaptive rendering:

```python
import torch
import torch.nn as nn
import torch.nn.functional as F
from typing import Tuple, Optional

class PlueckerEncoder(nn.Module):
    """Encode 3D rays as 6D Plücker coordinates for geometric awareness."""
    def __init__(self, hidden_dim: int = 256):
        super().__init__()
        self.hidden_dim = hidden_dim

        # Linear projection from 6D Plücker to embedding
        self.proj = nn.Linear(6, hidden_dim)
        self.norm = nn.LayerNorm(hidden_dim)

    def forward(self, rays_origin: torch.Tensor, rays_direction: torch.Tensor,
                rgb_values: torch.Tensor) -> torch.Tensor:
        """
        Encode rays as tokens with geometric structure.

        Args:
            rays_origin: (batch, H*W, 3) ray starting positions
            rays_direction: (batch, H*W, 3) normalized ray directions
            rgb_values: (batch, H*W, 3) pixel colors

        Returns:
            tokens: (batch, H*W, hidden_dim) encoded ray tokens
        """
        batch_size, num_rays, _ = rays_origin.shape

        # Compute Plücker coordinates: [direction, origin × direction]
        # Captures both geometric position and direction information
        cross_product = torch.cross(rays_origin, rays_direction, dim=-1)
        pluecker = torch.cat([rays_direction, cross_product], dim=-1)  # (batch, num_rays, 6)

        # Normalize Plücker coordinates
        pluecker = F.normalize(pluecker, dim=-1)

        # Project to embedding space
        tokens = self.proj(pluecker)  # (batch, num_rays, hidden_dim)
        tokens = self.norm(tokens)

        # Optionally fuse RGB information
        tokens = tokens + self.proj(torch.cat([rgb_values, torch.zeros_like(rgb_values[:, :, :3])], dim=-1))

        return tokens

class LightFieldTokenClusterer(nn.Module):
    """K-means clustering in feature space for light-field compression."""
    def __init__(self, hidden_dim: int, num_clusters: int = 256, max_iter: int = 10):
        super().__init__()
        self.hidden_dim = hidden_dim
        self.num_clusters = num_clusters
        self.max_iter = max_iter

        # Learnable cluster centroids
        self.cluster_centers = nn.Parameter(torch.randn(num_clusters, hidden_dim))
        nn.init.normal_(self.cluster_centers, std=0.01)

    def forward(self, tokens: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
        """
        Cluster tokens; select representative from each cluster.

        Args:
            tokens: (batch, num_tokens, hidden_dim)

        Returns:
            cluster_representatives: (batch, num_clusters, hidden_dim)
            cluster_assignments: (batch, num_tokens) cluster indices
            cluster_variance: (num_clusters,) variance within each cluster
        """
        batch_size, num_tokens, hidden_dim = tokens.shape

        # Compute distances to cluster centers
        # (batch, num_tokens, 1, hidden_dim) - (1, 1, num_clusters, hidden_dim)
        distances = torch.cdist(tokens, self.cluster_centers)  # (batch, num_tokens, num_clusters)

        # Hard assignment: each token to nearest cluster
        cluster_assignments = distances.argmin(dim=-1)  # (batch, num_tokens)

        # Select representative from each cluster (nearest-neighbor to centroid)
        cluster_representatives = []
        cluster_variance = []

        for cluster_idx in range(self.num_clusters):
            # Find tokens in this cluster
            mask = (cluster_assignments == cluster_idx).float()  # (batch, num_tokens)

            if mask.sum() > 0:
                # Compute variance within cluster
                cluster_tokens = tokens[mask.unsqueeze(-1).expand(-1, -1, hidden_dim) > 0.5]
                if cluster_tokens.shape[0] > 0:
                    variance = cluster_tokens.var(dim=0).mean()
                else:
                    variance = torch.tensor(0.0, device=tokens.device)

                # Find nearest-neighbor representative
                cluster_center = self.cluster_centers[cluster_idx:cluster_idx+1]
                distances_to_center = torch.norm(tokens - cluster_center, dim=-1)
                representative_idx = distances_to_center.argmin(dim=-1).unsqueeze(-1)

                representative = torch.gather(
                    tokens,
                    dim=1,
                    index=representative_idx.unsqueeze(-1).expand(-1, -1, hidden_dim)
                ).squeeze(1)  # (batch, hidden_dim)
            else:
                representative = self.cluster_centers[cluster_idx:cluster_idx+1]
                variance = torch.tensor(0.0, device=tokens.device)

            cluster_representatives.append(representative)
            cluster_variance.append(variance)

        cluster_representatives = torch.stack(cluster_representatives, dim=1)  # (batch, num_clusters, hidden_dim)
        cluster_variance = torch.stack(cluster_variance)  # (num_clusters,)

        return cluster_representatives, cluster_assignments, cluster_variance

class AdaptiveTokenCondenser(nn.Module):
    """Compress light-field tokens into rendering-efficient representation."""
    def __init__(self, hidden_dim: int = 256, num_render_tokens: int = 128):
        super().__init__()
        self.hidden_dim = hidden_dim
        self.num_render_tokens = num_render_tokens

        # Transformer blocks for token interaction
        encoder_layer = nn.TransformerEncoderLayer(
            d_model=hidden_dim,
            nhead=8,
            dim_feedforward=512,
            batch_first=True
        )
        self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=2)

        # Token selection via attention
        self.selection_head = nn.Linear(hidden_dim, 1)

    def forward(self, cluster_tokens: torch.Tensor,
                num_render_tokens: Optional[int] = None) -> torch.Tensor:
        """
        Select and compress tokens for rendering.

        Args:
            cluster_tokens: (batch, num_clusters, hidden_dim)
            num_render_tokens: Override default; enables dynamic adjustment

        Returns:
            render_tokens: (batch, num_render_tokens, hidden_dim)
        """
        if num_render_tokens is None:
            num_render_tokens = self.num_render_tokens

        # Encode cluster tokens
        encoded = self.encoder(cluster_tokens)  # (batch, num_clusters, hidden_dim)

        # Score tokens for importance
        scores = self.selection_head(encoded).squeeze(-1)  # (batch, num_clusters)

        # Select top-k tokens by score
        _, top_indices = torch.topk(scores, k=num_render_tokens, dim=-1)

        # Gather selected tokens
        batch_size = cluster_tokens.shape[0]
        batch_indices = torch.arange(batch_size, device=cluster_tokens.device).view(-1, 1)
        render_tokens = cluster_tokens[batch_indices, top_indices]  # (batch, num_render_tokens, hidden_dim)

        return render_tokens

class NeuralLightFieldRenderer(nn.Module):
    """Render novel views from compressed light-field tokens."""
    def __init__(self, hidden_dim: int = 256, image_height: int = 512, image_width: int = 512):
        super().__init__()
        self.hidden_dim = hidden_dim
        self.image_height = image_height
        self.image_width = image_width

        # Position encoding for spatial coordinates
        self.pos_encoding = nn.Linear(6, hidden_dim)  # x, y, z + view direction (3D)

        # View-dependent MLP for appearance
        self.appearance_mlp = nn.Sequential(
            nn.Linear(hidden_dim * 2, 256),
            nn.ReLU(),
            nn.Linear(256, 128),
            nn.ReLU(),
            nn.Linear(128, 3)  # RGB output
        )

        # Spatial aggregation (cross-attention from tokens to pixel positions)
        self.cross_attention = nn.MultiheadAttention(
            hidden_dim, num_heads=8, batch_first=True
        )

    def forward(self, render_tokens: torch.Tensor,
                target_poses: torch.Tensor) -> torch.Tensor:
        """
        Render novel views using compressed light-field tokens.

        Args:
            render_tokens: (batch, num_render_tokens, hidden_dim)
            target_poses: (batch, image_h, image_w, 6) target camera poses + ray directions

        Returns:
            rendered_image: (batch, image_h, image_w, 3)
        """
        batch_size = render_tokens.shape[0]
        h, w = self.image_height, self.image_width

        # Flatten spatial coordinates
        target_poses_flat = target_poses.view(batch_size, h * w, -1)  # (batch, h*w, 6)

        # Encode target positions
        pos_encoding = self.pos_encoding(target_poses_flat)  # (batch, h*w, hidden_dim)

        # Cross-attention: aggregate token information for each pixel
        pixel_features, _ = self.cross_attention(
            query=pos_encoding,
            key=render_tokens,
            value=render_tokens
        )  # (batch, h*w, hidden_dim)

        # Decode to RGB
        combined = torch.cat([pos_encoding, pixel_features], dim=-1)  # (batch, h*w, hidden_dim*2)
        rgb = self.appearance_mlp(combined)  # (batch, h*w, 3)

        # Reshape to image
        image = rgb.view(batch_size, h, w, 3).permute(0, 3, 1, 2)  # (batch, 3, h, w)
        image = torch.clamp(image, 0, 1)

        return image

class CLiFTModel(nn.Module):
    """Complete CLiFT pipeline for adaptive light-field rendering."""
    def __init__(self, hidden_dim: int = 256, num_storage_tokens: int = 256,
                 num_render_tokens: int = 128):
        super().__init__()
        self.pluecker_encoder = PlueckerEncoder(hidden_dim)
        self.clusterer = LightFieldTokenClusterer(hidden_dim, num_clusters=num_storage_tokens)
        self.condenser = AdaptiveTokenCondenser(hidden_dim, num_render_tokens)
        self.renderer = NeuralLightFieldRenderer(hidden_dim)

    def forward(self, input_images: torch.Tensor, input_poses: torch.Tensor,
                target_poses: torch.Tensor,
                num_render_tokens: Optional[int] = None) -> Tuple[torch.Tensor, dict]:
        """
        Encode input views, compress, and render novel view.

        Args:
            input_images: (batch, num_views, 3, H, W)
            input_poses: (batch, num_views, 6) camera poses + ray directions
            target_poses: (batch, H, W, 6) target camera pose + ray directions
            num_render_tokens: Dynamic token count for quality-speed tradeoff

        Returns:
            rendered: (batch, 3, H, W)
            info: Dict with compression stats
        """
        batch_size, num_views = input_images.shape[:2]

        # Tokenize input views
        # (Simplified: assume images already converted to rays)
        tokens = self.pluecker_encoder(
            torch.zeros(batch_size, num_views * 256, 3),  # placeholder rays
            torch.ones(batch_size, num_views * 256, 3) / 3,
            input_images.view(batch_size, -1, 3)
        )

        # Cluster tokens
        cluster_reps, assignments, variance = self.clusterer(tokens)

        # Compress for rendering
        render_tokens = self.condenser(cluster_reps, num_render_tokens)

        # Render novel view
        rendered = self.renderer(render_tokens, target_poses)

        info = {
            'num_input_tokens': tokens.shape[1],
            'num_storage_tokens': cluster_reps.shape[1],
            'num_render_tokens': render_tokens.shape[1],
            'compression_ratio': tokens.shape[1] / render_tokens.shape[1]
        }

        return rendered, info

def train_clift_step(model: CLiFTModel, batch, optimizer: torch.optim.Optimizer) -> float:
    """Single training step for CLiFT."""
    optimizer.zero_grad()

    input_images = batch['input_images']
    input_poses = batch['input_poses']
    target_images = batch['target_images']
    target_poses = batch['target_poses']

    # Forward pass
    rendered, info = model(input_images, input_poses, target_poses)

    # Render loss
    loss = F.l1_loss(rendered, target_images)

    loss.backward()
    optimizer.step()

    return loss.item()
```

This implementation demonstrates the three-stage compression and adaptive rendering pipeline.

## Practical Guidance

| Parameter | Value | Notes |
|-----------|-------|-------|
| **Storage Tokens (Nₛ)** | 256 | Balance compression vs. quality; 512 for highest fidelity |
| **Render Tokens (Nᵣ)** | 128 | Start here; reduce to 50-100 for speedup, increase to 200+ for quality |
| **K-means Clusters** | 256 | Usually equal to Nₛ; more clusters allow finer discrimination |
| **Cluster Selection** | Nearest-neighbor | Ensures representatives are actual tokens, not interpolations |
| **Plücker Normalization** | L2-norm | Ensures geometric consistency across scales |
| **Training Views** | 4-8 | More views provide richer signal; <4 causes overfitting |
| **Learning Rate** | 1e-4 | Stable training for token compression |

### When to Use CLiFT

- **Multi-view 3D reconstruction**: Convert image collections to efficient scene representations
- **Neural rendering systems**: Needing real-time novel-view synthesis with controllable quality
- **Adaptive rendering**: Dynamic quality-speed tradeoffs (high-FPS low-quality vs. slow high-quality)
- **Storage-constrained deployment**: 5-7× compression is critical for mobile/edge devices
- **Fast preprocessing**: Lightweight compression avoids expensive optimization loops
- **View-dependent appearance**: Light fields naturally capture complex reflectance

### When NOT to Use

- **Geometrically complex scenes** with occlusions: Light field may be insufficient; use explicit geometry
- **Extreme view extrapolation**: If novel views far from input poses, extrapolation fails
- **Scenes with specularities**: Highly specular surfaces create discontinuities in light field
- **Very small object details**: Compression may lose fine geometric detail; unsuitable for macro-level precision
- **Dynamic scenes**: Static scene assumption; unsuitable for video or moving objects

### Common Pitfalls

1. **Insufficient Input Views**: Using <4 views causes K-means underfitting. Always use ≥4 input images; 8+ ideal.
2. **Plücker Coordinate Bugs**: Incorrect cross-product computation breaks geometric structure. Verify: origin × direction encodes moment, not position.
3. **K-means Divergence**: If cluster centers never update, learning rate too low or initialization bad. Use warm-start from PCA.
4. **Token Dropout During Rendering**: If rendering only uses top-k tokens by score, important geometric information discarded. Use all clusters, select only during inference.
5. **Camera Pose Errors**: Even 1-2° camera pose error cascades through rendering. Pre-register input poses carefully; validate with reprojection.

## Reference

Wang, Z., Wu, Y., et al. (2025). CLiFT: Compressive Light-Field Tokens for Compute-Efficient and Adaptive Neural Rendering. *arXiv preprint arXiv:2507.08776*.

Available at: https://arxiv.org/abs/2507.08776

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.