#pragma once /** * @file visualization_quality.h * @brief 网格可视化增强与质量评估 * * 提供环境光遮蔽、硬边检测/高亮、线框叠加、法线可视化等渲染辅助数据。 * 所有函数输出纯数据(颜色数组、线段数组等),由渲染管线消费。 * * @ingroup mesh */ #include "vde/mesh/halfedge_mesh.h" #include "vde/core/point.h" #include #include #include #include namespace vde::mesh { using core::Point3D; using core::Vector3D; // ═══════════════════════════════════════════════════════════ // 数据结构 // ═══════════════════════════════════════════════════════════ /// 逐顶点 AO 值 struct AOResult { std::vector vertex_ao; ///< 逐顶点环境光遮蔽因子 [0,1](1=完全暴露) double min_ao; ///< 最小 AO 值 double max_ao; ///< 最大 AO 值 double avg_ao; ///< 平均 AO 值 int samples; ///< 实际采样数 }; /// 硬边检测结果 struct EdgeHighlightResult { std::vector> hard_edges; ///< 硬边:(vA, vB) 顶点索引对 std::vector edge_angles; ///< 对应二面角(弧度) double angle_threshold; ///< 使用的角度阈值 int total_edges; ///< 检测总边数 int hard_count; ///< 硬边数 }; /// 线框叠加线段 struct WireframeOverlay { std::vector> wire_edges; ///< 线框边:(vA, vB) std::vector vertices; ///< 顶点坐标 }; /// 法线可视化数据 struct NormalVisData { std::vector face_centers; ///< 面中心 std::vector face_normals; ///< 面法线 std::vector vertex_positions; ///< 顶点位置 std::vector vertex_normals; ///< 顶点法线(平均面法线) }; // ═══════════════════════════════════════════════════════════ // 环境光遮蔽 // ═══════════════════════════════════════════════════════════ /** * @brief 计算逐顶点环境光遮蔽(Ambient Occlusion) * * 对每个顶点在其上半球采样 `samples` 条射线,统计被遮挡比例。 * AO = 1 - (被遮挡射线数 / 总射线数)。 * * @param mesh 三角网格 * @param samples 每顶点采样射线数(默认 128,越多越精确) * @return AOResult 包含逐顶点 AO 值及统计信息 * * @ingroup mesh */ AOResult ambient_occlusion(const HalfedgeMesh& mesh, int samples = 128); // ═══════════════════════════════════════════════════════════ // 边高亮(硬边检测) // ═══════════════════════════════════════════════════════════ /** * @brief 检测硬边(二面角超过阈值的边) * * 遍历网格所有边,计算相邻两面的二面角, * 角度超过 angle_threshold(弧度)的边标记为硬边。 * * @param mesh 三角网格 * @param angle_threshold 硬边阈值(弧度),默认 π/4 = 45° * @return EdgeHighlightResult * * @ingroup mesh */ EdgeHighlightResult edge_highlighting(const HalfedgeMesh& mesh, double angle_threshold = 0.785398163); // ═══════════════════════════════════════════════════════════ // 线框叠加 // ═══════════════════════════════════════════════════════════ /** * @brief 提取线框叠加数据 * * 从实体网格提取所有唯一边,生成线框表示。 * 可选地排除与 solid_mesh 重合的边(只显示差异边)。 * * @param mesh 三角网格 * @param solid_mesh 实体网格(空网格 = 忽略) * @return WireframeOverlay * * @ingroup mesh */ WireframeOverlay wireframe_overlay(const HalfedgeMesh& mesh, const HalfedgeMesh& solid_mesh = HalfedgeMesh()); // ═══════════════════════════════════════════════════════════ // 法线可视化 // ═══════════════════════════════════════════════════════════ /** * @brief 生成法线可视化数据 * * 计算每个面的中心点与法线、每个顶点法线(相邻面法线的面积加权平均)。 * * @param mesh 三角网格 * @return NormalVisData * * @ingroup mesh */ NormalVisData normal_visualization(const HalfedgeMesh& mesh); } // namespace vde::mesh