# Archer Render 使用说明
Archer Render是面向几何有限元模型的专用渲染引擎,使用C++, OpenGL, GLSL编写

## 目录说明

![image-20210322165630547](C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210322165630547.png)



## 编译运行Demo

1. 前提 (windows平台为例,linux平台类似,需编译相应第三方库)
   1. QT5.12
   2. CMake
   3. VS2017
2. 编译
   1. cmake(vs2017 x64)
   2. configure
   3. build
3. 运行
   1. 在bin路径Debug或者Release下运行相关exe

## Demo功能使用介绍

1. 新建一个模型,当前是一个四面体

   ![image-20210323090939925](C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210323090939925.png)

2. 拾取四面体的一个三角面片

   ![image-20210323091023641](C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210323091023641.png)

3. 七种视图模式和居中

4. 旋转/平移/缩放操作

## Archer Render中的若干概念

1. 画布

   画布是Archer Render里的顶层对象,所有的API调用都是从画布调用的,包括初始化,添加可渲染对象,渲染,拾取,鼠标事件响应,交互状态设置等等API,在后面将详细介绍。

2. 可渲染对象,可渲染部件,可渲染组

   可渲染对象是顶层抽象,如名字所示,代表了所有可渲染的对象;可渲染部件是实例化渲染对象,完成了实际的绘制工作,相当于渲染对象管理中的最小单元;可渲染组是可渲染对象的集合;ArcherRender中的模型管理使用组合模式,如图所示,可以管理复杂的模型场景。

   ![image-20210322220229143](C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210322220229143.png)

3. ViewData

   ArcherRender可以说是数据驱动的,这个数据就是ViewData,每一个可渲染部件的渲染内容就来自于ViewData,ViewData是对可渲染数据的抽象,外部调用通过填充ViewData来实现数据的可视化。ViewData包含基本信息,节点信息,顶点信息,线段信息,面片信息几个部分。

   1. 基本信息

      ```c++
      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;   	/*自由边数据*/
      ```

   2. 节点信息

      ```c++
      std::vector<float>       nodes;         /*节点坐标*/
      std::vector<float>       node_normals;  /*节点法向,仅几何和点云数据有效*/
      std::vector<float>       node_colors;   /*节点颜色,仅点云数据有效*/
      std::vector<float>       node_scalars;  /*节点scalar值,用于节点云图*/
      ```

   3. 顶点信息

      ```c++
      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值*/
      ```

   4. 线段信息

      ```c++
      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值*/
      ```

   5. 面片信息

      ```c++
      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值,用于单元云图*/
      ```

4. 鼠标状态

   该结构对鼠标状态进行抽象,在画布canvas的鼠标事件处理以及交互状态中都有使用。

   ```c++
   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;				/*右键是否按下*/
   };
   ```

5. 交互状态

   交互状态是对渲染引擎可能面对的交互需求的抽象,需要自定义并通过画布API设置当前交互状态。交互状态在画布中采用堆栈进行管理,最顶层的交互状态有效,通过出栈的方式恢复到之前的交互状态,在画布设置交互状态时会默认设置成可堆栈的;不可堆栈的交互状态有最高优先级。最典型的应用就是拾取操作。

   ```c++
   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; }
   };
   ```

## Canvas接入流程

以QT为例,在QT QOpenGLWidget的子类中重载以下事件函数并在其中调用Canvas子类提供的相应API:

![image-20210322210920923](C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210322210920923.png)

接入流程如下:

![image-20210322215950685](C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210322215950685.png)

### Canvas接口详解

- 初始化

```c++
/**
 * 在所有Canvas操作之前调用,初始化渲染引擎,失败返回false,成功返回true
 * 例如在QT QOpenGLWidget的intializeGL中调用
 */
static bool Initialize();
```

- 渲染

```c++
/**
 * 绘制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() {}
```

- 鼠标事件处理

```c++
/**
 * 处理鼠标左/中/右键按下/抬起/双击事件,处理鼠标移动事件,处理鼠标滚轴事件
 */
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);
```

- 添加可渲染对象	

```c++
/**
 * 添加一个可渲染对象到canvas中,通常这里应该是添加一个可渲染组,因为主程序应该会对可渲染对象管理,所以仅添加根节点即可,
 * 也就是一个渲染组。
 */
void Add(Renderable* ren);
/**
 * 清空可渲染对象集合
 */
void Clear();
/**
 * 重新计算包围盒
 */
void RecomputeBoundingBox();
```

- 视图操作

```c++
/**
 * 居中
 */
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);
```

-  拾取接口, 通常与自定义交互状态配合以达到拾取状态的保存恢复

```c++
/**
 * 在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);
```

- 交互状态设置

```c++
/**
 * 设置交互状态,默认是可堆栈的;如果不可堆栈,该交互状态将拥有最高优先级
 */
void setInteractorState(InteractorState* state, bool stackable = true);
/** 
 * 弹出交互状态,并恢复之前的交互状态;与前者配对使用
 */
void popInteractorState(bool stackable = true);
```

- 挂载绘制routine,与下面的基本对象绘制配合使用,即在设置的routine中调用基本对象绘制API

```c++
/**
 * 设置当前的绘制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();
```

- 基本对象绘制  

```c++
/**
 * 绘制点/线
 * @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);
```

- 显示模式设置

```c++
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();
```

- 设置颜色条参数

```c++
/**
 * 设置颜色条开关
 */
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();
```

- 光照调节       

```c++
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);
```

- 坐标系开关

```c++
void setAxesVisibility(bool v);
```

-  全局颜色设置

```c++
void setBackgroundGroundColor(float c[3]);
void setBackgroundSkyColor(float c[3]);
void setMeshLineColor(float c[4]);
```

- 三维到屏幕二维坐标变换        

```c++
void toScreen(double x, double y, double z, double& wx, double& wy);
```
- 脚本驱动相关API

```c++
/**
 * 返回旋转四元数
 */
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);    
```