---
name: surface_plot_3d
kind: component
lang: cpp
domain: viz
version: "2.0.0"
purity: pure
signature: "void surface_plot_3d(const char* title, const fn::SurfacePlot3DConfig& cfg)"
description: "Superficie 3D ImPlot3D — malla z[nx*ny] row-major + ranges X/Y, eje rotatorio drag-to-orbit"
tags: [implot3d, chart, visualization, gpu, surface, 3d]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: [imgui, implot3d]
tested: false
tests: []
test_file_path: ""
file_path: "cpp/functions/viz/surface_plot_3d.cpp"
framework: imgui
params:
  - name: title
    desc: "Titulo / id interno del plot"
  - name: cfg
    desc: "fn::SurfacePlot3DConfig — z (nx*ny row-major), nx, ny, x/y_min, x/y_max, labels, size, show_colormap"
output: "Renderiza una superficie 3D dentro del frame ImGui actual; soporta orbit (drag), zoom (wheel) y pan via ImPlot3D"
notes: "scaffolding/demo en primitives_gallery"
---

# surface_plot_3d

Superficie 3D renderizada con [ImPlot3D](https://github.com/brenocq/implot3d) (vendoreado en `cpp/vendor/implot3d/`, pinned v0.4 commit `41ae3e44`).

La API toma una malla densa `z[nx*ny]` en row-major (`z[j*nx + i]` es la altura en el vertice `(x_i, y_j)`) y ranges para los ejes X / Y. Las coordenadas X / Y por vertice se generan internamente en lineal entre `[x_min, x_max]` y `[y_min, y_max]` — el caller solo necesita pasar el grid de alturas.

Llamar dentro de un frame ImGui activo (lambda de `fn::run_app` o similar). El contexto de ImPlot3D lo crea / destruye `app_base` junto al de ImPlot.

## Caracteristicas

- **Orbit**: drag con LMB rota la camara alrededor del centro del plot.
- **Zoom**: scroll wheel.
- **Pan**: drag con MMB.
- **Colormap**: ImPlot3D aplica el colormap activo segun la altura Z. `show_colormap` esta reservado como contrato API por si se anyade colorbar externa.

## Ejemplo

```cpp
#include "viz/surface_plot_3d.h"
#include <vector>
#include <cmath>

constexpr int N = 64;
std::vector<float> z(N * N);
for (int j = 0; j < N; ++j)
    for (int i = 0; i < N; ++i)
        z[j*N + i] = std::sin(0.2f * i) * std::cos(0.2f * j);

fn::SurfacePlot3DConfig cfg{};
cfg.z = z.data();
cfg.nx = N; cfg.ny = N;
cfg.x_min = 0; cfg.x_max = float(N);
cfg.y_min = 0; cfg.y_max = float(N);
fn::surface_plot_3d("##terreno", cfg);
```

## Limites practicos

- Mallas hasta ~256×256 son fluidas a 60 FPS en GPUs modernas. Por encima de eso conviene downsamplear.
- ImPlot3D dibuja los triangulos en CPU y los empuja al ImDrawList — no es shader-based.
