feat/vtk-3d-view #7
|
|
@ -1318,6 +1318,34 @@ geopro::core::ColorScale makeJetColorScale(double vmin, double vmax) {
|
|||
return cs;
|
||||
}
|
||||
|
||||
// 调亮版 seismic:与 makeSeismicColorScale 同红-白-蓝走向,但把蓝端提亮、整体抬白,
|
||||
// 弱信号也落在更亮的色域(强负不再是深蓝、零附近纯白、强正亮红),整体更醒目不发暗。
|
||||
geopro::core::ColorScale makeBrightSeismicColorScale(double vmin, double vmax) {
|
||||
geopro::core::ColorScale cs;
|
||||
const double span = (vmax > vmin) ? (vmax - vmin) : 1.0;
|
||||
auto at = [&](double t) { return vmin + span * t; };
|
||||
cs.addStop(at(0.00), geopro::core::Rgba{70, 130, 255, 255}); // 亮蓝(强负)
|
||||
cs.addStop(at(0.30), geopro::core::Rgba{170, 210, 255, 255}); // 浅亮蓝
|
||||
cs.addStop(at(0.50), geopro::core::Rgba{255, 255, 255, 255}); // 纯白(零)
|
||||
cs.addStop(at(0.70), geopro::core::Rgba{255, 200, 150, 255}); // 亮浅橙
|
||||
cs.addStop(at(1.00), geopro::core::Rgba{255, 80, 60, 255}); // 亮红(强正)
|
||||
return cs;
|
||||
}
|
||||
|
||||
// 增强灰度:黑→白单调,但中段抬亮、两端拉满,弱反射也落在中亮灰,层界面/竖纹对比醒目。
|
||||
// GPR 内部水平层叠/基底反射用灰度往往最干净直读(不被多色相干扰)。
|
||||
geopro::core::ColorScale makeGrayEnhancedColorScale(double vmin, double vmax) {
|
||||
geopro::core::ColorScale cs;
|
||||
const double span = (vmax > vmin) ? (vmax - vmin) : 1.0;
|
||||
auto at = [&](double t) { return vmin + span * t; };
|
||||
cs.addStop(at(0.00), geopro::core::Rgba{20, 25, 40, 255}); // 强负:近黑带冷调
|
||||
cs.addStop(at(0.30), geopro::core::Rgba{120, 125, 135, 255}); // 中负:中灰(抬亮)
|
||||
cs.addStop(at(0.50), geopro::core::Rgba{180, 182, 188, 255}); // 零附近:亮灰
|
||||
cs.addStop(at(0.70), geopro::core::Rgba{225, 222, 210, 255}); // 中正:暖亮灰
|
||||
cs.addStop(at(1.00), geopro::core::Rgba{255, 252, 240, 255}); // 强正:近白
|
||||
return cs;
|
||||
}
|
||||
|
||||
// 「实体感」不透明度包络(Task 12d gallery):与 structural 双端斜坡不同,这里让
|
||||
// 中高值段普遍可见——背景(近零)仍压低但不归零,中高段从 floorOpacity 平滑升到
|
||||
// maxOpacity,使体读起来像半透明实心块、内部层次(而非只剩两端薄壳)可见。
|
||||
|
|
@ -2916,7 +2944,13 @@ enum class OpacityProfile {
|
|||
kSolid, // V 形实体感:中高值段普遍可见,半透明实心块
|
||||
kStructural, // 现有双端斜坡:仅正负两端不透明(对照基线)
|
||||
};
|
||||
enum class ColorChoice { kStructural, kSeismic, kJet };
|
||||
enum class ColorChoice {
|
||||
kStructural,
|
||||
kSeismic,
|
||||
kJet,
|
||||
kBrightSeismic, // 调亮版 seismic
|
||||
kGrayEnhanced, // 增强灰度
|
||||
};
|
||||
|
||||
struct GalleryVariant {
|
||||
const char* name; // 文件名后缀:view-<name>.png
|
||||
|
|
@ -2934,42 +2968,55 @@ struct GalleryVariant {
|
|||
// ---- C4 视觉调优(梯度不透明度 + 光照),默认关 → 不改既有变体行为 ----
|
||||
bool useGradientOpacity = false; // SetGradientOpacity:均匀层透明、界面/异常显形
|
||||
bool useShade = false; // SetShade:层界面带立体明暗
|
||||
// ---- P4 调亮/调清晰 ----
|
||||
// 梯度门松弛度 0~1:0=严格(均匀层全透、偏暗) 1=宽松(均匀层保留底不透明、更亮更满)。
|
||||
// 宽松时降低梯度阈值并抬高「低梯度区」的不透明度地板,让横向层叠/基底反射等弱结构保留。
|
||||
double gradGateRelax = 0.0;
|
||||
double ambient = 0.30; // 光照环境项(别太低,否则体面偏暗);useShade 时生效。
|
||||
};
|
||||
|
||||
// C4 视觉调优:4 组对照(纯标量 / +梯度不透明度 / +光照 / 全开)。
|
||||
// 同一局部段、同一 seismic 配色、同一斜穿俯视取景(El45/Az30,视线穿进体内部而非
|
||||
// 只看端面)——唯一变量是「梯度不透明度 / 光照」,供肉眼直读"内部结构是否透出"。
|
||||
// maxOpacity 字段:纯标量组用低峰值(0.45,避免均匀积分糊成实心);开了梯度门的组用
|
||||
// 高峰值(0.6)——均匀区被梯度门压透明后,层界面的净不透明度(标量×梯度)才够高、浮成实面。
|
||||
// 末项 var4(全开) = kViewDefaultVariant → 交互窗口默认走全开。
|
||||
// P4 调亮/调清晰:4 组对照(暗版基线 / 提亮 / 高对比 / 灰度增强)。
|
||||
// 同一局部段、同一斜穿取景(El45/Az30)。P3 默认(seismic+严格梯度门+低 ambient)整体
|
||||
// 偏暗、均匀层被门全透成空。本组在「消雾」与「够亮够满」间放宽门控、抬 ambient、换更亮
|
||||
// 配色,让横向层叠/竖纹/基底反射醒目。所有端点按该体 2/98 分位自适应(runGalleryVariant
|
||||
// 内标定),非写死单一数据。末项 = kViewDefaultVariant → 交互窗口默认取最清晰醒目组。
|
||||
//
|
||||
// 字段:floorOpacity/midOpacity/maxOpacity(V 形标量包络)、gradGateRelax(梯度门松弛
|
||||
// 0~1)、ambient(光照环境项)。提亮组抬高 floor/mid 让均匀层保留底不透明、抬 ambient
|
||||
// 防体面发暗、放宽梯度门保留弱结构。
|
||||
const GalleryVariant kGalleryVariants[] = {
|
||||
// var1:纯标量不透明度(基线)——无梯度门、无光照。GPR 均匀层段沿射线积分糊成
|
||||
// 半透明实心块,只外表面/端面可读,内部水平分层难分辨(对照基准)。
|
||||
// var1:暗版基线(= P3 默认)——seismic + 严格梯度门(relax0) + 低 ambient0.3 + 暗背景。
|
||||
// 均匀层几乎全透、整体偏暗偏空,仅作对照。
|
||||
{"var1", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
||||
0.04, 0.30, 0.45, 8.0, 45.0, 30.0, 1.5, {0.05, 0.05, 0.09},
|
||||
"纯标量不透明度(基线):V形包络(floor0.04/mid0.30/max0.45)+seismic,"
|
||||
"无梯度门/无光照,均匀层积分糊成半透明块、仅端面可读",
|
||||
/*useGradientOpacity=*/false, /*useShade=*/false},
|
||||
// var2:+梯度不透明度——低梯度(均匀层)透明、高梯度(层界面/异常)显形,射线穿透
|
||||
// 均匀雾、内部界面浮出。标量峰值提到 0.6(梯度门压透明后层面才够实)。
|
||||
{"var2", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
||||
0.04, 0.30, 0.60, 8.0, 45.0, 30.0, 1.5, {0.05, 0.05, 0.09},
|
||||
"+梯度不透明度:低梯度(均匀层)透明、高梯度(界面/异常)显形,标量峰值0.6,"
|
||||
"射线穿透均匀雾、内部界面浮出",
|
||||
/*useGradientOpacity=*/true, /*useShade=*/false},
|
||||
// var3:+光照——在梯度门基础上 ShadeOn,层界面带立体明暗(非纯平涂)。
|
||||
{"var3", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
||||
0.04, 0.30, 0.60, 8.0, 45.0, 30.0, 1.5, {0.05, 0.05, 0.09},
|
||||
"+光照(梯度门+Shade):层界面带立体明暗(Ambient0.3/Diffuse0.7/Specular0.2),"
|
||||
"界面起伏更有体积感",
|
||||
/*useGradientOpacity=*/true, /*useShade=*/true},
|
||||
// var4:全开——梯度不透明度 + 光照 + seismic 双端斜坡配色 + 略亮冷灰背景。
|
||||
// 综合最佳,选作交互窗口默认(kViewDefaultVariant)。
|
||||
{"var4", OpacityProfile::kSolid, ColorChoice::kSeismic,
|
||||
0.04, 0.30, 0.60, 8.0, 45.0, 30.0, 1.5, {0.07, 0.08, 0.11},
|
||||
"全开(综合最佳):梯度不透明度+光照+seismic+略亮冷灰背景,内部分层界面/异常"
|
||||
"从均匀块透出 → 交互窗口默认",
|
||||
/*useGradientOpacity=*/true, /*useShade=*/true},
|
||||
"暗版基线(P3默认):seismic+严格梯度门+低ambient+暗背景,均匀层近全透、偏暗偏空",
|
||||
/*useGradientOpacity=*/true, /*useShade=*/true,
|
||||
/*gradGateRelax=*/0.0, /*ambient=*/0.30},
|
||||
// var2:提亮——调亮版 seismic + 放宽梯度门(relax0.6) + 抬 floor/mid/max + 高 ambient
|
||||
// + 略亮背景。均匀层保留底不透明、横向层叠透出、整体明显更亮更实。
|
||||
{"var2", OpacityProfile::kSolid, ColorChoice::kBrightSeismic,
|
||||
0.10, 0.45, 0.75, 8.0, 45.0, 30.0, 1.5, {0.12, 0.13, 0.17},
|
||||
"提亮:调亮版seismic+放宽梯度门(relax0.6)+抬不透明度(floor0.10/mid0.45/max0.75)"
|
||||
"+高ambient0.5,均匀层保留、层叠透出、明显更亮",
|
||||
/*useGradientOpacity=*/true, /*useShade=*/true,
|
||||
/*gradGateRelax=*/0.6, /*ambient=*/0.50},
|
||||
// var3:高对比——jet 高饱和配色 + 放宽梯度门(relax0.5) + 抬不透明度 + ambient0.45 +
|
||||
// 暗背景衬高饱和。弱信号也映到鲜明色相,层界面/异常对比最狠。
|
||||
{"var3", OpacityProfile::kSolid, ColorChoice::kJet,
|
||||
0.08, 0.42, 0.78, 8.0, 45.0, 30.0, 1.5, {0.04, 0.04, 0.07},
|
||||
"高对比:jet高饱和+放宽梯度门(relax0.5)+抬不透明度+ambient0.45+暗背景衬色,"
|
||||
"弱信号映鲜明色相、层界面对比最狠",
|
||||
/*useGradientOpacity=*/true, /*useShade=*/true,
|
||||
/*gradGateRelax=*/0.5, /*ambient=*/0.45},
|
||||
// var4:灰度增强(默认)——增强灰度 + 放宽梯度门(relax0.7) + 抬不透明度 + 高 ambient
|
||||
// + 中性背景。GPR 内部水平层叠/竖纹/基底反射用增强灰度最干净直读,选作交互默认。
|
||||
{"var4", OpacityProfile::kSolid, ColorChoice::kGrayEnhanced,
|
||||
0.12, 0.48, 0.80, 8.0, 45.0, 30.0, 1.5, {0.14, 0.15, 0.18},
|
||||
"灰度增强(默认/综合最佳):增强灰度+放宽梯度门(relax0.7)+抬不透明度"
|
||||
"(floor0.12/mid0.48/max0.80)+高ambient0.5+中性背景,层叠/竖纹/基底反射干净醒目"
|
||||
" → 交互窗口默认",
|
||||
/*useGradientOpacity=*/true, /*useShade=*/true,
|
||||
/*gradGateRelax=*/0.7, /*ambient=*/0.50},
|
||||
};
|
||||
|
||||
// 交互窗口(无 flag 的 view)的默认视觉变体 = var4(kGalleryVariants 末项)。
|
||||
|
|
@ -2981,6 +3028,10 @@ geopro::core::ColorScale pickColor(ColorChoice c, double vmin, double vmax) {
|
|||
switch (c) {
|
||||
case ColorChoice::kSeismic: return makeSeismicColorScale(vmin, vmax);
|
||||
case ColorChoice::kJet: return makeJetColorScale(vmin, vmax);
|
||||
case ColorChoice::kBrightSeismic:
|
||||
return makeBrightSeismicColorScale(vmin, vmax);
|
||||
case ColorChoice::kGrayEnhanced:
|
||||
return makeGrayEnhancedColorScale(vmin, vmax);
|
||||
case ColorChoice::kStructural:
|
||||
default: return makeStructuralColorScale(vmin, vmax);
|
||||
}
|
||||
|
|
@ -3005,22 +3056,34 @@ vtkSmartPointer<vtkVolumeProperty> makeVariantProperty(
|
|||
prop = makeTunedVolumeProperty(q, cs, vmin, vmax, maxOpacity);
|
||||
}
|
||||
|
||||
// 梯度不透明度:均匀层(低梯度)透明,层界面/异常边缘(高梯度)显形。阈值按实测分布:
|
||||
// median 处仍 0(压住均匀积分雾),p90 升到 0.5,p99 到 0.9。无 gs(未测)则跳过。
|
||||
// 梯度不透明度:均匀层(低梯度)半透/透明,层界面/异常边缘(高梯度)显形。阈值按实测
|
||||
// 分布,并按 gradGateRelax 松弛:
|
||||
// - relax=0(严格,暗版):median→0、p90→0.5、p99→0.9,均匀层全透 → 偏暗偏空。
|
||||
// - relax>0(调亮):低梯度地板抬到 floorG(均匀层保留底不透明、更亮更满),阈值
|
||||
// 整体左移(更早升起),让横向层叠/基底反射等弱结构保留可见。
|
||||
// 无 gs(未测)则跳过。
|
||||
if (v.useGradientOpacity && gs != nullptr && gs->samples > 0) {
|
||||
const double relax = std::clamp(v.gradGateRelax, 0.0, 1.0);
|
||||
const double floorG = 0.30 * relax; // 低梯度区不透明度地板(均匀层保留度)
|
||||
const double midG = 0.5 + 0.25 * relax;
|
||||
const double hiG = 0.9;
|
||||
// 阈值左移:松弛越大,门越早从低梯度升起(结构保留越多)。
|
||||
const double tLo = std::max(1.0, gs->median * (1.0 - 0.7 * relax));
|
||||
const double tMid = std::max(2.0, gs->p90 * (1.0 - 0.6 * relax));
|
||||
const double tHi = std::max(3.0, gs->p99 * (1.0 - 0.4 * relax));
|
||||
vtkNew<vtkPiecewiseFunction> grad;
|
||||
grad->AddPoint(0.0, 0.0);
|
||||
grad->AddPoint(std::max(1.0, gs->median), 0.0);
|
||||
grad->AddPoint(std::max(2.0, gs->p90), 0.5);
|
||||
grad->AddPoint(std::max(3.0, gs->p99), 0.9);
|
||||
grad->AddPoint(0.0, floorG);
|
||||
grad->AddPoint(tLo, floorG);
|
||||
grad->AddPoint(tMid, midG);
|
||||
grad->AddPoint(tHi, hiG);
|
||||
prop->SetGradientOpacity(grad);
|
||||
}
|
||||
|
||||
// 光照:ShadeOn + Ambient/Diffuse,保留立体明暗;Specular 压到 0.05(近乎关)避免
|
||||
// 旋转时视角相关的高光在体表游走形成「移动白斑」。保留 ambient/diffuse 立体感。
|
||||
// 旋转时视角相关的高光在体表游走形成「移动白斑」。Ambient 由变体控(别太低否则偏暗)。
|
||||
if (v.useShade) {
|
||||
prop->ShadeOn();
|
||||
prop->SetAmbient(0.3);
|
||||
prop->SetAmbient(v.ambient);
|
||||
prop->SetDiffuse(0.7);
|
||||
prop->SetSpecular(0.05);
|
||||
prop->SetSpecularPower(10.0);
|
||||
|
|
@ -3298,8 +3361,9 @@ std::size_t viewSetupDefaultFrame(ViewState* st, vtkRenderer* ren) {
|
|||
}
|
||||
|
||||
// 渲一组画廊变体并存 PNG,报告 结构像素 / 平均亮度 / fps。返回 0=OK。
|
||||
// shotDirOverride 非空 → PNG 存到该目录(P4 让 gallery 出图落在 store 同目录,便于对照)。
|
||||
int runGalleryVariant(const std::string& dir, const GalleryVariant& v,
|
||||
int frames) {
|
||||
int frames, const std::string& shotDirOverride = "") {
|
||||
const int winW = 1280, winH = 800;
|
||||
geopro::data::ChunkedVolumeStore store(dir);
|
||||
const geopro::data::StoreMeta& m = store.meta();
|
||||
|
|
@ -3369,7 +3433,9 @@ int runGalleryVariant(const std::string& dir, const GalleryVariant& v,
|
|||
rw->Render();
|
||||
|
||||
const fs::path shotDir =
|
||||
fs::path("docs") / "superpowers" / "plans" / "poc-lod-shots";
|
||||
shotDirOverride.empty()
|
||||
? fs::path("docs") / "superpowers" / "plans" / "poc-lod-shots"
|
||||
: fs::path(shotDirOverride);
|
||||
fs::create_directories(shotDir);
|
||||
const std::string pngPath =
|
||||
(shotDir / (std::string("view-") + v.name + ".png")).string();
|
||||
|
|
@ -3430,9 +3496,12 @@ int runGalleryVariant(const std::string& dir, const GalleryVariant& v,
|
|||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
// view --gallery:依次渲全部 4 组变体。
|
||||
int cmdViewGallery(const std::string& dir, int frames) {
|
||||
// view --gallery:依次渲全部 4 组变体。shotDir 空 → 默认 docs/.../poc-lod-shots;
|
||||
// 否则存到 shotDir(P4:默认传 store 目录,4 张图落在 tmp/line001_proc)。
|
||||
int cmdViewGallery(const std::string& dir, int frames,
|
||||
const std::string& shotDir = "") {
|
||||
std::cout << "[view --gallery] storeDir=" << dir << " frames=" << frames
|
||||
<< " shotDir=" << (shotDir.empty() ? "(默认)" : shotDir)
|
||||
<< "\n[view --gallery] 离屏闸门复检...\n";
|
||||
if (cmdOffscreenSmoke() != 0) {
|
||||
std::cout << "[view --gallery] 闸门失败,中止。\n";
|
||||
|
|
@ -3440,10 +3509,12 @@ int cmdViewGallery(const std::string& dir, int frames) {
|
|||
}
|
||||
int rc = 0;
|
||||
for (const auto& v : kGalleryVariants) {
|
||||
if (runGalleryVariant(dir, v, frames) != 0) rc = 1;
|
||||
if (runGalleryVariant(dir, v, frames, shotDir) != 0) rc = 1;
|
||||
}
|
||||
std::cout << "\n[view --gallery] 完成,4 张图存于 "
|
||||
"docs/superpowers/plans/poc-lod-shots/view-var{1..4}.png\n";
|
||||
const std::string outDesc =
|
||||
shotDir.empty() ? "docs/superpowers/plans/poc-lod-shots" : shotDir;
|
||||
std::cout << "\n[view --gallery] 完成,4 张图存于 " << outDesc
|
||||
<< "/view-var{1..4}.png\n";
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -3488,9 +3559,13 @@ int cmdView(int argc, char** argv) {
|
|||
const bool nearPreview =
|
||||
hasFlag("near") || (a.kv.count("variant") && a.get("variant", "") == "near");
|
||||
|
||||
// 画廊出图目录:--out <dir> 显式指定;否则默认存到 store 目录(P4:gallery 落在
|
||||
// tmp/line001_proc,便于控制方就地对照)。
|
||||
const std::string galleryShotDir = a.get("out", dir);
|
||||
|
||||
// 画廊模式(Task 12d):渲 4 组视觉调参图供挑选。优先于其余路径。
|
||||
if (hasFlag("gallery")) {
|
||||
return cmdViewGallery(dir, frames);
|
||||
return cmdViewGallery(dir, frames, galleryShotDir);
|
||||
}
|
||||
// 单变体:view --preview --variant N(N=1..4),只渲第 N 组(near 不走此路)。
|
||||
if (preview && a.kv.count("variant") && !nearPreview) {
|
||||
|
|
@ -3503,7 +3578,8 @@ int cmdView(int argc, char** argv) {
|
|||
}
|
||||
std::cout << "[view] storeDir=" << dir << " 单变体 variant=" << vi << "\n";
|
||||
if (cmdOffscreenSmoke() != 0) return 1;
|
||||
return runGalleryVariant(dir, kGalleryVariants[vi - 1], frames);
|
||||
return runGalleryVariant(dir, kGalleryVariants[vi - 1], frames,
|
||||
galleryShotDir);
|
||||
}
|
||||
|
||||
std::cout << "[view] storeDir=" << dir << " exagg=" << exagg
|
||||
|
|
|
|||
Loading…
Reference in New Issue