88 lines
3.3 KiB
Markdown
88 lines
3.3 KiB
Markdown
# Advanced Texture Mapping Detailed Reference
|
||
|
||
## Prerequisites
|
||
- Screen-space derivatives (`dFdx`, `dFdy`)
|
||
- `textureGrad()` function usage
|
||
- Basic ray marching
|
||
|
||
## Triplanar vs Biplanar Cost Analysis
|
||
|
||
| Aspect | Triplanar | Biplanar |
|
||
|--------|-----------|----------|
|
||
| Texture fetches | 3 | 2 |
|
||
| ALU operations | Lower | Higher (axis selection) |
|
||
| Bandwidth | Higher | Lower |
|
||
| Visual quality | Baseline | Equivalent (k≥8) |
|
||
| Best for | Bandwidth-rich GPUs | Mobile, bandwidth-limited |
|
||
|
||
Modern GPUs are typically bandwidth-limited rather than ALU-limited, making biplanar the better default choice.
|
||
|
||
### Weight Remapping Mathematics
|
||
|
||
The biplanar weight formula `clamp((w - 0.5773) / (1.0 - 0.5773), 0, 1)` ensures:
|
||
- At normals aligned with one axis: weight = 1.0 (clean projection)
|
||
- At 45° diagonals where 2 axes are equal: smooth transition
|
||
- At the cube diagonal (1/√3 ≈ 0.5773): weight = 0.0, but this is the point where the third (discarded) projection would be needed — biplanar's approximation error is maximal here but visually acceptable
|
||
|
||
### Gradient Propagation
|
||
|
||
Using `textureGrad()` instead of `texture()` is essential because:
|
||
1. Axis selection (`ma`, `me`) creates UV discontinuities at projection boundaries
|
||
2. Hardware `texture()` computes mip from implicit derivatives, which spike at discontinuities → visible seams
|
||
3. `textureGrad()` with manually propagated `dFdx(p)`, `dFdy(p)` bypasses this, keeping gradients smooth across boundaries
|
||
|
||
## Ray Differential Mathematics
|
||
|
||
### Problem Statement
|
||
In rasterization, `dFdx`/`dFdy` of texture coordinates work naturally because adjacent pixels map to nearby surface points. In ray marching, adjacent pixels may hit completely different objects → broken mip selection.
|
||
|
||
### Solution: Tangent Plane Intersection
|
||
|
||
Given:
|
||
- Primary ray hits surface at `pos` with normal `nor`
|
||
- Neighbor pixel ray `rd_neighbor` originates from `ro_neighbor`
|
||
|
||
The neighbor ray's intersection with the tangent plane at `pos`:
|
||
```
|
||
t_neighbor = dot(pos - ro_neighbor, nor) / dot(rd_neighbor, nor)
|
||
pos_neighbor = ro_neighbor + rd_neighbor * t_neighbor
|
||
```
|
||
|
||
The difference `pos_neighbor - pos` gives the world-space footprint of one pixel at the hit point.
|
||
|
||
### For Perspective Cameras (Common Case)
|
||
```
|
||
ro is the same for all pixels, only rd varies:
|
||
dposdx = t * (rdx * dot(rd, nor) / dot(rdx, nor) - rd)
|
||
dposdy = t * (rdy * dot(rd, nor) / dot(rdy, nor) - rd)
|
||
```
|
||
Where `rdx = rd + dFdx(rd)` and `rdy = rd + dFdy(rd)`.
|
||
|
||
### Chain Rule for Texture Coordinates
|
||
If texture mapping function is `uv = f(pos)`:
|
||
```
|
||
duvdx = Jacobian(f) × dposdx
|
||
duvdy = Jacobian(f) × dposdy
|
||
```
|
||
For simple planar mapping `uv = pos.xz`:
|
||
```
|
||
duvdx = dposdx.xz
|
||
duvdy = dposdy.xz
|
||
```
|
||
|
||
## Texture Repetition Theory
|
||
|
||
### Why Tiling is Visible
|
||
Human vision excels at detecting:
|
||
1. **Periodic patterns**: Regular grid alignment
|
||
2. **Unique features**: Distinctive spots/marks that repeat identically
|
||
3. **Phase alignment**: All tiles start at the same phase
|
||
|
||
### Breaking Repetition
|
||
Each method targets different cues:
|
||
- **Random offset** (Method A): Breaks phase alignment, 4 fetches
|
||
- **Voronoi blend**: Breaks grid structure entirely, 9 fetches (expensive)
|
||
- **Virtual pattern** (Method B): Breaks unique features cheaply, 2 fetches
|
||
|
||
Method B is preferred for real-time use — the low-frequency index variation is cache-friendly and the two texture fetches share locality.
|