SAM 场景、显示表示与渲染 API / SAM Scene, Display Representation, and Rendering APIs
本篇解释为什么“计算出了面积或点坐标”不等于“视口中出现图形”,以及 SAM 如何从 Part/Mesh 走到 Scene 和 Renderer。
1. 模型数据与显示数据
basNewModel / ptoKPart / ftrFeatureList / bmeMesh
|
`-- 生成 gdyDisplayRep
|
`-- gdyScene
|
`-- gdyEditor
+-- gdyGeomEditor
+-- gdyNonPageGeomEditor
`-- Adapter / Page Editor
|
`-- gdrRenderer
+-- g3dPoint
`-- g3dVector模型层决定对象是否可保存、可编辑、可网格化;显示层决定对象如何被画出来、选择和高亮。
2. 三种不同需求
2.1 只显示计算结果文字
使用 Dialog、CLI 或 Message Area,不需要渲染类。
2.2 显示临时预览或辅助标记
可使用临时 DisplayRep、Editor、Highlight 或 Annotation。它们通常不进入持久 Model。
2.3 创建可保存的真实图形
必须创建或修改 Part/Feature/Mesh,然后让场景根据新模型生成显示表示。直接调用 Renderer 画顶点只会形成一次显示过程,不会自动创建 Part。
3. gdyScene
表示某个 Viewport/Layer 的场景。
gdyScene(int viewport);
gdyScene(int viewport,
const QString& layerName,
const gdyScene& copy);
virtual const ftrPrimaryObject*
GetPrimaryObject() const = 0;
gdyEditor* GetGdyEditor() const;
gdyEditor* Editor();
void SetDisplayOptions(const sesCDisplayOptions&);
gdyDisplayRep* GetDisplayRepresentation() const;
virtual void ClearScene() = 0;
virtual void UpdateScene() = 0;
virtual void RefreshScene() = 0;
void UpdateTimestamp();
virtual QString InstanceName(int instanceId) const;
static gdyScene* GetCurrentScene(bool force = true);UpdateScene():根据模型或显示状态更新场景内容。RefreshScene():刷新当前显示。ClearScene():清除显示数据。GetCurrentScene():取得当前视口场景,必须检查返回对象和上下文。
4. gdyEditor
一个 Scene 内的显示编辑器总控,管理多个几何编辑器、Adapter、页面、选择和高亮。
bool Load(const gdyDisplayRep&);
bool LoadPageToEditor(const gdyDisplayRep&,
gdyPageGeomEditor*);
bool PreviewLoad(const gdyDisplayRep&);
void UnloadAll();
void PreviewUnload();
void ProcessDisplayOptions();
void ProcessSetChanges();
void AddGeomEditor(gdyGeomEditor*);
uint NumGeomEditors() const;
gdyGeomEditor* GetGeomEditor(uint) const;
gdyGeomEditor* GetGeomEditorByType(uint) const;
gdyGeomEditor* GetGeomEditorByType(const char*) const;
void AddAdapter(gdyAdapter*);
void Sketch(gdrRenderer&);
void Draft(gdrRenderer&, uint options);
void Paint(gdrRenderer&, uint options);
void Highlight(gdrRenderer&);
void ClearAllHighlights();
void UpdateHighlights();
void DisplayText(gdrRenderer&);
void ASelect(gdrASelector&);
void DSelect(gdrASelector&);
void FetchHighlightedItems(gdyCompositeHitSet&);Sketch、Draft、Paint 是不同显示阶段;选择和高亮也有独立通道。
5. gdyGeomEditor
某种几何显示数据的抽象编辑器。
virtual const omuAtom& Type() const = 0;
virtual void Unload() = 0;
virtual bool IsPageGeomEditor() const;
virtual void UpdateDisplayOptions(
const sesCDisplayOptions&);
void DisplayText(gdrRenderer&,
const g3dPoint&) const;
virtual gdyGeomEditor* Copy() const;
virtual void ClearAllHighlights();
virtual void DrawAnnotations(gdrRenderer&) const;它通常负责一种 DisplayRep 的加载、绘制、选择和高亮规则。
6. gdyNonPageGeomEditor
非分页几何编辑器基础类。
virtual const omuAtom& Type() const = 0;
virtual bool IsPageGeomEditor() const;
virtual void Load(const gdyDisplayRep*, g3dSphere*);
virtual void Unload();
virtual void Sketch(gdrRenderer&) const;
virtual void Draft(gdrRenderer&) const = 0;
virtual void Paint(gdrRenderer&) const = 0;
virtual void ASelect(gdrASelector&) const = 0;
virtual void DSelect(gdrASelector&) const;
virtual void Highlight(gdrRenderer&) const;派生类必须至少实现 Draft、Paint 和 ASelect。
7. gdrRenderer
底层抽象渲染器,接口风格类似图元流。
virtual void SetRenderMode(gdrRenderMode);
virtual void SetRenderFlags(unsigned int);
virtual void ClearColorBuffer();
virtual void ClearDepthBuffer();
virtual void ClearAllBuffers();
virtual void Camera(const g3dCamera&);
virtual void Studio(const g3dStudio&);
virtual void ModelXForm(const g3dXForm&,
float scale = 1.0f,
int flag = 1) = 0;
virtual void Begin(g3dPrimitiveEnum) = 0;
virtual void Color(const g3dColor&) = 0;
virtual void Normal(const g3dVector&) = 0;
virtual void Vertex(const g3dPoint&) = 0;
virtual void End(bool quiet = false) = 0;
virtual void DrawArrays(g3dPrimitiveEnum,
int start,
int count);
virtual void Lighting(bool);
virtual bool Translucency(bool on,
float visible = 1.0f,
bool passThrough = false);
virtual bool ClipPlane(int,
const g3dVector&,
float);典型图元绘制概念:
renderer.Begin(primitiveType);
renderer.Color(color);
renderer.Normal(normal);
renderer.Vertex(point0);
renderer.Vertex(point1);
renderer.Vertex(point2);
renderer.End();业务插件通常不直接实现整个 Renderer,而是实现或复用 SAM 的 DisplayRep/GeomEditor。
8. g3dPoint
四分量图形点:
float& X();
float GetX() const;
float& Y();
float GetY() const;
float& Z();
float GetZ() const;
float& W();
float GetW() const;
g3dPoint& Set(float x,
float y,
float z,
float w = 1.f);
g3dPoint& Set(double x,
double y,
double z,
double w = 1.0);
g3dPoint& HNormalize();9. g3dVector
三维向量:
float GetX() const;
float GetY() const;
float GetZ() const;
g3dVector& Set(float x, float y, float z);
g3dVector& SetZero();
g3dVector& SetI();
g3dVector& SetJ();
g3dVector& SetK();
float Length() const;
g3dVector& Normalize();
float AngleWith(const g3dVector&,
bool bothNormalized) const;自由函数 g3dDot() 和 g3dCross() 分别执行点积与叉积。
10. 为什么只出现红色线,没有填充面
常见原因:
- DisplayRep 只生成了线图元,没有生成三角形/面图元;
- 面连接顺序错误,法向朝向或背面剔除导致不可见;
- 没有提供有效法向;
- 面颜色透明度或显示选项不正确;
- 图形仅作为 Highlight 绘制,因此只显示轮廓;
- 模型存在轮廓 Feature,但没有形成面 Feature;
- 更新了数据,却没有让 Scene 重新 Load/Update。
11. 模型更新后的推荐显示流程
修改 Model/Part/Feature/Mesh
-> 更新有效性、时间戳和再生状态
-> ptoKPart::UpdateScene 或对应模型通知
-> gdyScene::UpdateScene
-> gdyScene::RefreshScene
-> SAMApp/MainWindow refresh(如仍需要)不要无条件连续调用所有刷新函数。应先查明当前修改 API 是否已经发送模型通知,避免重复刷新和性能下降。
12. 选择与高亮
显示、选择和高亮是三套相关但不同的通道:
Paint/Draft:正常显示;ASelect/DSelect:选择检测;Highlight:选择后的视觉反馈。
一个对象能显示但不能选中,通常是 ASelect/DSelect 没有实现或对象 ID 映射不正确;能选中但高亮异常,则检查 Highlight 和选择集映射。