Archer Render 使用说明
Archer Render是面向几何有限元模型的专用渲染引擎,使用C++, OpenGL, GLSL编写
功能介绍
-
大规模几何模型渲染
-
大规模网格模型渲染
-
点云绘制
-
绘制文本
-
交互
- 旋转/平移/缩放/居中
- 七视图
- 旋转中心/局部放大
-
点/线/三角形/四边形的拾取
-
基本图元绘制
-
3D/2D 空间坐标转换
-
脚本化数据返回(旋转,平移,缩放等)
目录说明
编译运行Demo
- 前提 (windows平台为例,linux平台类似,需编译相应第三方库)
- QT5.12
- CMake
- VS2019
- 编译
- cmake(vs2019 x64)
- configure
- build
- 运行
- 在bin路径Debug或者Release下运行相关exe
Demo功能使用介绍
Archer Render中的若干概念
-
画布
画布是Archer Render里的顶层对象,所有的API调用都是从画布调用的,包括初始化,添加可渲染对象,渲染,拾取,鼠标事件响应,交互状态设置等等API,在后面将详细介绍。
-
可渲染对象,可渲染部件,可渲染组
可渲染对象是顶层抽象,如名字所示,代表了所有可渲染的对象;可渲染部件是实例化渲染对象,完成了实际的绘制工作,相当于渲染对象管理中的最小单元;可渲染组是可渲染对象的集合;ArcherRender中的模型管理使用组合模式,如图所示,可以管理复杂的模型场景。
-
ViewData
ArcherRender可以说是数据驱动的,这个数据就是ViewData,每一个可渲染部件的渲染内容就来自于ViewData,ViewData是对可渲染数据的抽象,外部调用通过填充ViewData来实现数据的可视化。ViewData包含基本信息,节点信息,顶点信息,线段信息,面片信息几个部分。
-
基本信息
std::string name; /*名字*/ double color[3]; /*颜色*/ double trans; /*透明度*/ bool point_cloud; /*点云数据*/ bool mesh; /*false:几何数据;true:网格数据*/ bool flynode; /*无引用点数据*/ bool wireframe; /*线框数据*/ bool selection; /*选择集数据*/ bool polygon; /*多边形数据*/ bool featureLines; /*特征线数据*/ bool freeEdges; /*自由边数据*/
-
节点信息
std::vector<float> nodes; /*节点坐标*/ std::vector<float> node_normals; /*节点法向,仅几何和点云数据有效*/ std::vector<float> node_colors; /*节点颜色,仅点云数据有效*/ std::vector<float> node_scalars; /*节点scalar值,用于节点云图*/
-
顶点信息
std::vector<int> verts; /*顶点索引*/ unsigned int vert_type; /*顶点类型,用于拾取分类*/ unsigned int vert_identity; /*顶点一级标识,用于拾取*/ float vert_size; /*顶点大小*/ float vert_color[4]; /*顶点颜色*/ std::vector<int> vert_identities; /*顶点二级标识,用于拾取*/ std::vector<std::string> vert_text; /*顶点文本*/ std::vector<float> vert_scalars; /*顶点scalar值*/
-
线段信息
std::vector<int> lines; /*线段索引*/ unsigned int line_type; /*线段类型,用于拾取分类*/ unsigned int line_identity; /*线段一级标识,用于拾取*/ float line_width; /*线段宽度*/ float line_color[4]; /*线段颜色*/ std::vector<int> line_identities; /*线段二级标识,用于拾取*/ std::vector<float> line_scalars; /*线段scalar值*/
-
面片信息
std::vector<int> trias; /*三角形索引*/ unsigned int tria_type; /*三角形类型,用于拾取分类*/ unsigned int tria_identity; /*三角形一级标识,用于拾取*/ std::vector<int> tria_identities; /*三角形二级标识,用于拾取*/ std::vector<float> tria_scalars; /*三角形scalar值,用于单元云图*/ std::vector<int> quads; /*四边形索引*/ unsigned int quad_type; /*四边形类型,用于拾取分类*/ unsigned int quad_identity; /*四边形一级标识,用于拾取*/ std::vector<int> quad_identities; /*四边形二级标识,用于拾取*/ std::vector<float> quad_scalars; /*四边形scalar值,用于单元云图*/
-
-
鼠标状态
该结构对鼠标状态进行抽象,在画布canvas的鼠标事件处理以及交互状态中都有使用。
struct MouseState { int x; /*鼠标位置x*/ int y; /*鼠标位置y*/ int delta; /*滚轴delta值*/ bool ctrlDown; /*control键是否落下*/ bool shiftDown; /*shift键是否落下*/ bool altDown; /*alt键是否落下*/ bool isDragging; /*是否在拖拽*/ bool leftDown; /*左键是否按下*/ bool middleDown; /*中键是否按下*/ bool rightDown; /*右键是否按下*/ };
-
交互状态
交互状态是对渲染引擎可能面对的交互需求的抽象,需要自定义并通过画布API设置当前交互状态。交互状态在画布中采用堆栈进行管理,最顶层的交互状态有效,通过出栈的方式恢复到之前的交互状态,在画布设置交互状态时会默认设置成可堆栈的;不可堆栈的交互状态有最高优先级。最典型的应用就是拾取操作。
class InteractorState { public: /** * 处理左键按下消息 */ virtual void OnLeftDown(const MouseState& ms) {} /** * 处理左键抬起消息 */ virtual void OnLeftUp(const MouseState& ms) {} /** * 处理左键双击消息 */ virtual void OnLeftDClick(const MouseState& ms) {} /** * 处理中键按下消息 */ virtual void OnMiddleDown(const MouseState& ms) {} /** * 处理中键抬起消息 */ virtual void OnMiddleUp(const MouseState& ms) {} /** * 处理中键双击消息 */ virtual void OnMiddleDClick(const MouseState& ms) {} /** * 处理右键按下消息 */ virtual void OnRightDown(const MouseState& ms) {} /** * 处理右键抬起消息 */ virtual void OnRightUp(const MouseState& ms) {} /** * 处理右键双击消息 */ virtual void OnRightDClick(const MouseState& ms) {} /** * 处理鼠标移动消息 */ virtual bool OnMotion(const MouseState& ms) { return false; } /** * 在该交互状态激活时执行的操作,比如设置鼠标形状 */ virtual void OnActivate() {} /** * 在该交互状态弹出时执行的操作,比如恢复鼠标形状 */ virtual void OnDeactive() {} public: /** * 查询该交互状态是否为可堆栈的 */ bool stackable() const { return _stackable; } /** * 设置该交互状态是否为可堆栈的 */ void setStackable(bool flag) { _stackable = flag; } };
SDK接入流程
接入流程如下:

具体操作步骤如下:
-
包含头文件
include_directories( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/public )
-
设置库路径
link_directories(${CMAKE_SOURCE_DIR}/lib)
target_link_libraries(${MODULE_NAME} ArcherRender)
-
自定义画布并实例化
#include "canvas.h" namespace my { namespace modelrender { class mrCanvas : public render::Canvas { public: static mrCanvas* s_instance; public: static mrCanvas* Instance(); void Delete(); void loadModel(); protected: virtual void refresh(); private: mrCanvas(); mrCanvas(const mrCanvas&); mrCanvas& operator=(const mrCanvas&); }; } }
-
在QT事件中调用画布实例API
-
自定义QOpenGLWidget
#include <QOpenGLWidget> #include <QOpenGLFunctions> class QMouseEvent; class SceneWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: static SceneWidget* Instance(); static void setInstance(SceneWidget* w); explicit SceneWidget(QWidget* parent = 0); ~SceneWidget(); protected: void initializeGL() override; void resizeGL(int w, int h) override; void paintGL() override; virtual void mousePressEvent(QMouseEvent* event); virtual void mouseReleaseEvent(QMouseEvent* event); virtual void mouseDoubleClickEvent(QMouseEvent* event); virtual void mouseMoveEvent(QMouseEvent* event); #if QT_CONFIG(wheelevent) virtual void wheelEvent(QWheelEvent* event); #endif };
-
初始化
void SceneWidget::initializeGL() { initializeOpenGLFunctions(); if (!my::modelrender::mrCanvas::Instance()->Initialize()) { qCritical() << "rendering engine initialize failed!"; return; } }
-
渲染事件
void SceneWidget::paintGL() { my::modelrender::mrCanvas::Instance()->Render(0); }
-
窗口大小变化事件
void SceneWidget::resizeGL(int w, int h) { my::modelrender::mrCanvas::Instance()->OnSize(w, h); }
-
鼠标事件
void SceneWidget::mousePressEvent(QMouseEvent* event) { my::render::MouseState ms; ms.ctrlDown = event->modifiers() & Qt::ControlModifier; ms.shiftDown = event->modifiers() & Qt::ShiftModifier; ms.altDown = event->modifiers() && Qt::AltModifier; ms.x = event->pos().x(); ms.y = event->pos().y(); if (event->button() == Qt::LeftButton) { my::modelrender::mrCanvas::Instance()->OnLeftDown(ms); } else if (event->button() == Qt::RightButton) { my::modelrender::mrCanvas::Instance()->OnRightDown(ms); } else if (event->button() == Qt::MiddleButton) { my::modelrender::mrCanvas::Instance()->OnMiddleDown(ms); } } void SceneWidget::mouseReleaseEvent(QMouseEvent* event) { my::render::MouseState ms; ms.ctrlDown = event->modifiers() & Qt::ControlModifier; ms.shiftDown = event->modifiers() & Qt::ShiftModifier; ms.altDown = event->modifiers() && Qt::AltModifier; ms.x = event->pos().x(); ms.y = event->pos().y(); if (event->button() == Qt::LeftButton) { my::modelrender::mrCanvas::Instance()->OnLeftUp(ms); #if 0 //脚本记录以回放旋转平移操作 if (ms.ctrlDown) { float quat[4]; my::modelrender::mrCanvas::Instance()->quaternion(quat); QString cmd = QString::asprintf("view.rotate(%f, %f, %f, %f)", quat[0], quat[1], quat[2], quat[3]); script::ScriptManager::Instance()->record(cmd); } else if (ms.shiftDown) { float pan[2]; my::modelrender::mrCanvas::Instance()->translation(pan); QString cmd = QString::asprintf("view.translate(%f, %f)", pan[0], pan[1]); script::ScriptManager::Instance()->record(cmd); } #endif } else if (event->button() == Qt::RightButton) { #if 0 //脚本记录以回放缩放 if (ms.ctrlDown || ms.shiftDown) { float zoom; my::modelrender::mrCanvas::Instance()->scaling(zoom); QString cmd = QString::asprintf("view.scale(%f)", zoom); script::ScriptManager::Instance()->record(cmd); } #endif } else if (event->button() == Qt::MiddleButton) { #if 0 //脚本记录以平移 if (ms.ctrlDown || ms.shiftDown) { float pan[2]; my::modelrender::mrCanvas::Instance()->translation(pan); QString cmd = QString::asprintf("view.translate(%f, %f)", pan[0], pan[1]); script::ScriptManager::Instance()->record(cmd); } #endif } } void SceneWidget::mouseMoveEvent(QMouseEvent* event) { my::render::MouseState ms; ms.ctrlDown = event->modifiers() & Qt::ControlModifier; ms.shiftDown = event->modifiers() & Qt::ShiftModifier; ms.altDown = event->modifiers() && Qt::AltModifier; ms.leftDown = event->buttons() & Qt::LeftButton; ms.middleDown = event->buttons() & Qt::MiddleButton; ms.rightDown = event->buttons() & Qt::RightButton; ms.isDragging = true; ms.x = event->pos().x(); ms.y = event->pos().y(); my::modelrender::mrCanvas::Instance()->OnMotion(ms); } #if QT_CONFIG(wheelevent) void SceneWidget::wheelEvent(QWheelEvent* event) { my::render::MouseState ms; ms.ctrlDown = event->modifiers() & Qt::ControlModifier; ms.shiftDown = event->modifiers() & Qt::ShiftModifier; ms.altDown = event->modifiers() && Qt::AltModifier; ms.leftDown = event->buttons() & Qt::LeftButton; ms.middleDown = event->buttons() & Qt::MiddleButton; ms.rightDown = event->buttons() & Qt::RightButton; ms.isDragging = true; ms.x = event->pos().x(); ms.y = event->pos().y(); ms.delta = event->delta(); if (ms.ctrlDown || ms.shiftDown) { float dxs = (float)(ms.x - this->width() / 2) / (float)this->width(); float dys = -(float)(ms.y - this->height() / 2) / (float)this->height(); my::modelrender::mrCanvas::Instance()->scaleHere(dxs, dys, ms.delta); } } #endif
-
添加/更新可渲染部件
void mrCanvas::loadModel() { //清除所有部件 Clear(); //演示云图功能 #define _FRINGE_MODE__ 1 #ifdef _FRINGE_MODE__ this->setColorBarVisibility(true); this->setColorBarRange(0.0, 5.0); this->setColorBarLevel(10); this->setColorBarHueRange(360, 240); this->setColorBarUpdate(); //节点云图 //this->toggleNodalFringeModeOn(); //单元云图 this->toggleElemFringeModeOn(); #endif //填充可视化数据 my::render::ViewData vd; vd.color[0] = 1.0; vd.color[1] = 0.0; vd.color[2] = 0.0; vd.trans = 1.0; //网格数据,自行计算单元法向 vd.mesh = true; vd.nodes.push_back(0.0); vd.nodes.push_back(0.0); vd.nodes.push_back(0.0); vd.node_scalars.push_back(0.0); ... //数据类型,用于拾取分类 vd.tria_type = eElem; //一级标识 vd.tria_identity = 2; vd.trias.push_back(0); vd.trias.push_back(2); vd.trias.push_back(1); //二级标识 vd.tria_identities.push_back(0); vd.tria_scalars.push_back(0.0); ... //创建新的可视化部件 my::render::RenderablePart* p = new my::render::RenderablePart(1); //更新数据 p->Update(vd); //添加到场景中 Add(p); //重新计算包围盒 RecomputeBoundingBox(); //刷新 refresh(); }
Canvas接口详解
- 初始化
/**
* 在所有Canvas操作之前调用,初始化渲染引擎,失败返回false,成功返回true
* 例如在QT QOpenGLWidget的intializeGL中调用
*/
static bool Initialize();
- 渲染
/**
* 绘制API
* @param ist 为后处理预留
* 例如在QT QOpenGLWidget的paintGL中调用
*/
void Render(int ist);
/**
* 窗口大小变化响应API,
* @param w 窗口宽度
* @param h 窗口高度
*/
void OnSize(int w, int h);
/**
* 返回canvas宽度
*/
int width() const;
/**
* 返回canvas高度
*/
int height() const;
/**
* 需要在子类中重载,并调用相关平台的refresh函数刷新
*/
virtual void refresh() {}
- 鼠标事件处理
/**
* 处理鼠标左/中/右键按下/抬起/双击事件,处理鼠标移动事件,处理鼠标滚轴事件
*/
void OnLeftDown(const MouseState& ms);
void OnLeftUp(const MouseState& ms);
void OnLeftDClick(const MouseState& ms);
void OnMiddleDown(const MouseState& ms);
void OnMiddleUp(const MouseState& ms);
void OnMiddleDClick(const MouseState& ms);
void OnRightDown(const MouseState& ms);
void OnRightUp(const MouseState& ms);
void OnRightDClick(const MouseState& ms);
void OnMotion(const MouseState& ms);
void OnWheel(const MouseState& ms);
- 添加可渲染对象
/**
* 添加一个可渲染对象到canvas中,通常这里应该是添加一个可渲染组,因为主程序应该会对可渲染对象管理,所以仅添加根节点即可,
* 也就是一个渲染组。
*/
void Add(Renderable* ren);
/**
* 清空可渲染对象集合
*/
void Clear();
/**
* 重新计算包围盒
*/
void RecomputeBoundingBox();
- 视图操作
/**
* 居中
*/
void viewFit();
/**
* 左/右/上/下/前/后/等视图
*/
void viewLeft();
void viewRight();
void viewTop();
void viewBottom();
void viewFront();
void viewBack();
void viewIso();
/**
* 缩放到指定框内,四个参数为屏幕坐标归一化值
*/
void zoomIn(float x0, float y0, float x1, float y1);
/**
* 设置旋转中心
*/
void setRotateCenter(float x, float y, float z);
/**
* 根据鼠标位置和滚轴delta值进行缩放
*/
void scaleHere(float dxs, float dys, int delta);
- 拾取接口, 通常与自定义交互状态配合以达到拾取状态的保存恢复
/**
* 在ms指定位置拾取指定类型type的一级标识pid
*/
bool pick(const MouseState& ms, unsigned type, int& pid);
/**
* 在ms指定位置拾取指定类型type的一级标识pid,以及三维的位置信息xyz
*/
bool pick(const MouseState& ms, unsigned type, int& pid, std::array<double, 3>& xyz);
/**
* 在ms指定位置拾取指定类型type的一级标识pid以及二级标识fid
*/
bool pick(const MouseState& ms, unsigned type, int& pid, int& fid);
- 交互状态设置
/**
* 设置交互状态,默认是可堆栈的;如果不可堆栈,该交互状态将拥有最高优先级
*/
void setInteractorState(InteractorState* state, bool stackable = true);
/**
* 弹出交互状态,并恢复之前的交互状态;与前者配对使用
*/
void popInteractorState(bool stackable = true);
- 挂载绘制routine,与下面的基本对象绘制配合使用,即在设置的routine中调用基本对象绘制API
/**
* 设置当前的绘制routinue,使用[](){}设置将清空
*/
void setRenderRoutine(std::function<void()> routine);
/**
* 添加命名绘制routine
*/
void addRenderRoutine(const std::string& name, std::function<void()> routine);
/**
* 查询命名绘制routine
*/
bool hasRenderRoutine(const std::string& name);
/**
* 删除命名绘制routine
*/
void delRenderRoutine(const std::string& name);
/**
* 清空命名绘制routine
*/
void clrRenderRoutine();
- 基本对象绘制
/**
* 绘制点/线
* @param points 坐标
* @param drawLines 是否连成线
*/
void drawPoints(const std::vector<std::array<double, 3>> & points, bool drawLines = false);
/**
* 绘制点
* @param points 坐标
* @param colors 颜色
*/
void drawPoints(const std::vector<std::array<double, 3>> & points,
const std::vector<std::array<float, 3>> & colors);
/**
* 绘制点球
* @param points 坐标
* @param colors 颜色
* @param radius 半径
*/
void drawPoints(const std::vector<std::array<double, 3>> & points,
const std::vector<std::array<float, 3>> & colors,
const std::vector<float>& radius);
/**
* 绘制线
* @param type 类型,可选GL_LINES,GL_LINE_STRIP,GL_LINE_LOOP
* @param points 坐标
* @param lineColor 颜色
* @param lineWidth 线宽
*/
void drawLine(unsigned type,
const std::vector<std::array<double, 3>> & points,
float lineColor[3],
float lineWidth);
/**
* 绘制平面
* @param pos 位置
* @param dir 法线
*/
void drawPlane(const std::array<double, 3> & pos, const std::array<double, 3> & dir);
/**
* 绘制字符串
* @param x,y,z 坐标
* @param str 待绘制字符串
* @param fontSize 字体大小
*/
void drawString(double x, double y, double z, const char* str, int fontSize);
/**
* 绘制箭头
* @param points 坐标
* @param directions 方向
* @param color 颜色
*/
void drawArrow(const std::vector<std::array<float, 3>>& points,
const std::vector<std::array<float, 3>>& directions,
std::array<float, 3> color);
/**
* 绘制箭头
* @param points 坐标
* @param direction 方向
* @param color 颜色
*/
void drawArrow(const std::vector<std::array<float, 3>>& points,
std::array<float, 3> direction,
std::array<float, 3> color);
/**
* 绘制圆锥
* @param points 坐标
* @param direction 方向
* @param color 颜色
*/
void drawCone(const std::vector<std::array<float, 3>>& points,
std::array<float, 3> direction,
std::array<float, 3> color);
/**
* 绘制两个首尾相接圆锥
* @param points 坐标
* @param direction 方向
* @param drawHead/drawTail 头尾是否绘制
* @param colorHead/colorTail 头尾颜色
*/
void drawTwoCones(const std::vector<std::array<float, 3>>& points,
std::array<float, 3> direction,
bool drawHead, std::array<float, 3> colorHead,
bool drawTail, std::array<float, 3> colorTail);
/**
* 绘制圆
* @param c 圆心
* @param n 方向
* @param r 半径
* @param color 颜色
* @param lineWidth 线宽
*/
void drawCircle(const std::array<float, 3>& c,
const std::array<float, 3>& n,
float r,
const std::array<float, 3>& color,
float lineWidth = 1.0f);
- 显示模式设置
unsigned mode() const;
void toggleGeomMode();
void toggleGeomModeOn();
void toggleGeomModeOff();
void toggleVertMode();
void toggleVertModeOn();
void toggleVertModeOff();
void toggleEdgeMode();
void toggleEdgeModeOn();
void toggleEdgeModeOff();
void toggleFaceMode();
void toggleFaceModeOn();
void toggleFaceModeOff();
void toggleMeshMode();
void toggleMeshModeOn();
void toggleMeshModeOff();
void toggleShadeModeOn();
void toggleWireframeMode();
void toggleWireframeModeOn();
void toggleWireframeModeOff();
void toggleSkinWireframeMode();
void toggleSkinWireframeModeOn();
void toggleSkinWireframeModeOff();
void toggleFeatureLineMode();
void toggleFeatureLineModeOn();
void toggleFeatureLineModeOff();
void toggleMeshLineMode();
void toggleMeshLineModeOn();
void toggleMeshLineModeOff();
void toggleNormCheckMode();
void toggleNormMode();
void toggleElemFringeMode();
void toggleElemFringeModeOn();
void toggleElemFringeModeOff();
void toggleQualityCheckMode();
void toggleQualityCheckModeOn();
void toggleQualityCheckModeOff();
void toggleFreeEdgeMode();
void toggleFreeEdgeModeOn();
void toggleFreeEdgeModeOff();
- 设置颜色条参数
/**
* 设置颜色条开关
*/
void setColorBarVisibility(bool v);
/**
* 设置颜色条最大值最小值
*/
void setColorBarRange(float min, float max);
/**
* 设置颜色条起始颜色和结束颜色hue值,360-蓝色, 240-红色
*/
void setColorBarHueRange(int min, int max);
/**
* 设置颜色条标题
*/
void setColorBarTitle(const std::string& title);
/**
* 设置颜色条级数
*/
void setColorBarLevel(int level);
/**
* 设置颜色条门槛值,用于质量检查
*/
void setColorBarThreshold(float threshold);
/**
* 设置颜色条门槛值显示与否,用于质量检查
*/
void setColorBarShowThresholdOnly(bool flag);
/**
* 设置颜色条更新
*/
void setColorBarUpdate();
- 光照调节
void setLightEnable(int index, int enable);
void setLightPosition(int index, float x, float y, float z, float w);
void setLightAmbient(int index, float r, float g, float b, float a);
void setLightDiffuse(int index, float r, float g, float b, float a);
void setLightSpecular(int index, float r, float g, float b, float a);
void setLightShininess(float s);
- 坐标系开关
void setAxesVisibility(bool v);
- 全局颜色设置
void setBackgroundGroundColor(float c[3]);
void setBackgroundSkyColor(float c[3]);
void setMeshLineColor(float c[4]);
- 三维到屏幕二维坐标变换
void toScreen(double x, double y, double z, double& wx, double& wy);
- 脚本驱动相关API
/**
* 返回旋转四元数
*/
void quaternion(float quat[4]);
/**
* 使用记录的四元数进行旋转
*/
void rotate(float q0, float q1, float q2, float q3);
/**
* 返回平移二元数
*/
void translation(float pan[2]);
/**
* 使用记录的二元数进行平移
*/
void translate(float p0, float p1);
/**
* 返回缩放系数
*/
void scaling(float& z);
/**
* 使用记录的缩放系数进行缩放
*/
void scale(float z);