目录
结构概览
Vaa3D的3d viewer中,所有跟图像渲染和标注相关的代码,基本都在3drenderer文件夹内,基础数据结构、IO函数、部分类的规范定义在basic_c_fun文件夹内,主要代码结构概览本人整理如下几幅图用以直观理解。




注:笔记中出现的代码,都经过一定的删减。
UI
3d viewer窗口类
3drenderer/v3dr_mainwindow.h中,定义了3d viewer窗口类。
class V3dR_MainWindow : public QWidget
QWidget窗口实例可以通过下面语句激活,
mainwindow_sample->activateWindow();
3d viewer窗口中,定义了,
V3dR_GLWidget * getGLWidget() {
return glWidget;}
是图形窗口。
GL窗口类
3drenderer/v3dr_glwidget.h中,定义了gl窗口类,用来显示、标注图像。
class V3dR_GLWidget : public QOpenGLWidget, protected QOpenGLFunctions , public View3DControl
这里的View3DControl,定义在basic_c_fun/basic_view3d.h中,里面声明了3D图像基础操作的一系列虚函数。
V3dR_GLWidget中定义的主要对象有,
iDrawExternalParameter* _idep;//
QWidget *mainwindow;
Renderer* renderer;//
QString data_title;
QString dropUrl;
static V3dr_colormapDialog* colormapDlg;
static V3dr_surfaceDialog* surfaceDlg;
int neuronIndex;
bool show_progress_bar;
MainWindow *v3d_mainwindow;
int currentPluginState;
map<int, void(*)(void*)> pluginLeftMouseFuncs;
此外,注意所有包含在,
#ifdef _NEURON_ASSEMBLER_
/*一堆代码*/
#endif
中的代码,都是跟Terafly相关的。
渲染器相关的成员函数
V3dR_GLWidget类中,首先声明了一些列跟渲染器相关的方法。
void V3dR_GLWidget::deleteRenderer() {
makeCurrent(); DELETE_AND_ZERO(renderer);} //删除渲染器
void V3dR_GLWidget::createRenderer() {
makeCurrent(); deleteRenderer(); initializeGL();} //创建渲染器(初始化)
void V3dR_GLWidget::choiceRenderer()//根据OpenGL的版本选择渲染器
{
/*...*/
if (1 && supported_GLSL())
{
renderer = new Renderer_gl2(this);
}
else // this comment for special version without GL 2.0 support
if (1) //strlen(glversion)>3 && glversion[0]>='1' && glversion[1]=='.' && glversion[2]>='0')
{
renderer = new Renderer_gl1(this);
}
else
{
renderer = new Renderer(this);
}
}
void V3dR_GLWidget::settingRenderer()//在渲染器导入数据(renderer->setupData)前需要先设置参数
void V3dR_GLWidget::preparingRenderer()//渲染器导入数据
视图窗口相关的成员函数
之后是视图窗口的各种方法。
void V3dR_GLWidget::initializeGL()
这个方法是视图窗口的初始化,该方法最后调用了choiceRenderer()、settingRenderer()和preparingRenderer()。
void V3dR_GLWidget::resizeGL(int width, int height)
这个方法用于调整视图窗口的大小,里面调用了renderer->setupView()。
void V3dR_GLWidget::paintGL()
暂时还没学过OpenGL,只知道里面有旋转和平移。
void V3dR_GLWidget::customEvent(QEvent* e)
应该涉及自定义事件的控制。
bool V3dR_GLWidget::event(QEvent* e)
应该涉及鼠标悬停事件的处理,里面用pos保存了鼠标位置。
void V3dR_GLWidget::enterEvent(QEvent*)
鼠标进入视图。
void V3dR_GLWidget::leaveEvent(QEvent*)
鼠标离开视图。
void V3dR_GLWidget::focusInEvent(QFocusEvent*)
猜测是,鼠标在拖动中(点击移动,例如绘画等)。
void V3dR_GLWidget::focusOutEvent(QFocusEvent*)
猜测是,鼠标离开拖动状态。
绘图相关的成员函数
void V3dR_GLWidget::paintEvent(QPaintEvent *event)
{
//QOpenGLWidget_proxy::paintEvent(event);
// if (! mouse_in_view) //TODO: use change of viewing matrix
// {
// _still = true;
// QOpenGLWidget_proxy::paintEvent(event);
// _still = false;
// }
// else
{
_still = false;
QOpenGLWidget::paintEvent(event);
if (needStillPaint()) //pending
{
_stillpaint_pending=true;
}
}
}
绘图事件,注释掉的部分是因为不需要判断鼠标是否在视图窗口内。猜测是在一个绘图步骤结束后调用触发的事件,内部调用了QOpenGLWidget::paintEvent。
bool V3dR_GLWidget::needStillPaint()
{
return (renderer && renderer->tryTexStream == 1);
}
//注释了
void V3dR_GLWidget::stillPaint()
{
if (_still) return; // avoid re-enter
if (! _stillpaint_pending) return;
// if (QCoreApplication::hasPendingEvents())
// {
// _still = false;
// _stillpaint_pending = true;
// return; //continue pending if event loop is busy
// }
// else // here system must be idle
{
qDebug()<<"debug in v3dr_glwidget.cpp V3dR_GLWidget::stillPaint()";
still_timer.stop();
_still = true;
DO_updateGL(); // update at once, stream texture for full-resolution
_still = false;
_stillpaint_pending = false;
still_timer.start(still_timer_interval); //restart timer
}
}
这里,涉及到的变量,
bool _still, _stillpaint_pending;
还没弄懂,猜测stillpaint是指静态绘画,也就是执行完完整的鼠标移动步骤后进行绘画,猜测这三部分代码,将一个绘画步骤分为多个stillpaint,_still变量代表是否动作未完成,_stillpaint_pending变量代表是否stillpaint未完成(待定)。但还需要看应用的代码,这里实在不确定。
鼠标事件相关的成员函数
void V3dR_GLWidget::mousePressEvent(QMouseEvent *event)
{
mouse_held = 1;
if (event->button()==Qt::LeftButton)
{
lastPos = event->pos();
t_mouseclick_left = clock();
if(pluginLeftMouseFuncs.find(currentPluginState) != pluginLeftMouseFuncs.end())
{
void(*mouse_func)(void*);
mouse_func = pluginLeftMouseFuncs[currentPluginState];
(*mouse_func)((void*)this);
}
}
if (!isoperating&&event->button()==Qt::RightButton && renderer) //right-click
{
int x = event->x();
int y = event->y();
#ifdef _ENABLE_MACX_DRAG_DROP_FIX_
x = 2 * x;
y = 2 * y;
#endif
if (renderer->hitPoint(x,y)) //pop-up menu (selectObj) or marker definition (hitPen)
{
updateTool();
//POST_updateGL();
}
//updateTool();
POST_updateGL(); //display result after menu //csz solve the blue screen don't know the reason
}
}
鼠标点击事件,左键点击时,调用鼠标左键点击反应函数列表中,对应当前状态的函数。右键点击时,打开工具栏。
void V3dR_GLWidget::mouseReleaseEvent(QMouseEvent *event)
{
mouse_held = 0;
if (event->button()==Qt::RightButton && renderer) //right-drag end
{
(renderer->movePen(event->x(), event->y(), false)); //create curve or nothing
//qDebug() << "done drawing\n";
updateTool();
POST_updateGL(); //update display of curve
}
}
鼠标松开事件,如果是右键移动松开触发的,创建曲线,更新工具栏,显示曲线。
void V3dR_GLWidget::mouseMoveEvent(QMouseEvent *event)
{
int dx = event->x() - lastPos.x();
int dy = event->y() - lastPos.y();
lastPos = event->pos();
if ((event->buttons() & Qt::RightButton) && renderer) //right-drag for 3d curve
if ( ABS(dx) + ABS(dy) >=2 )
{
/*一些代码*/
}
if (event->buttons() & Qt::LeftButton)
{
int xRotStep = MOUSE_ROT(dy, MIN(viewW,viewH));
int yRotStep = MOUSE_ROT(dx, MIN(viewW,viewH));
int xShiftStep = MOUSE_SHIFT(dx, viewW);
int yShiftStep = MOUSE_SHIFT(dy, viewH);
alt_rotation = (IS_ALT_MODIFIER); // alt+mouse control alternate marker center rotation, 081104
// mouse control view space, transformed to model space, 081026
if (IS_TRANSLATE_MODIFIER) // shift+mouse control view space translation, 081104
{
setXShift(_xShift + xShiftStep);// move +view -model
setYShift(_yShift - yShiftStep);// move -view +model
}
else if (IS_MODEL_MODIFIER) // ctrl+mouse control model space rotation, 081104
{
//modelRotation(yRotStep, xRotStep, 0); //swap y,x
modelRotation(xRotStep, yRotStep, 0);
}
else // default mouse controls view space rotation
{
viewRotation(xRotStep, yRotStep, 0);
}
}
}
鼠标移动事件,如果是鼠标右键按住移动则创建曲线,如果是鼠标左键按住移动则先计算旋转移动角度和平移移动长度,之后根据情况,判断是旋转标记中心,还是平移,还是旋转,还是普通的视角转动。
void V3dR_GLWidget::wheelEvent(QWheelEvent *event)
{
/*一大堆代码*/
}
滚轮事件,一般是触发缩放。但按住shift或alt则触发z轴平移或旋转。
键盘事件相关的成员函数
键盘事件分为键盘按压事件和键盘释放事件,但只有数字键有释放事件。
void V3dR_GLWidget::handleKeyPressEvent(QKeyEvent * e)
{
switch (e->key())
{
/*一堆case语句*/
}
default:
QOpenGLWidget_proxy::keyPressEvent(e);
break;
}
update(); //must be here for correct MarkerPos's view matrix
}
e->key()的值有如下几种情况,
基础操作
case Qt::Key_BracketLeft:
{
if (IS_MODEL_MODIFIER) // alt-mouse to control model space rotation
modelRotation(0, 0, +5);
else
viewRotation(0, 0, +5);
}
break;
case Qt::Key_BracketRight:
/*一串代码*/
左方括号键,视角沿z方向旋转,或IS_MODEL_MODIFIER条件下,模型沿z方向旋转。与之对应的有Qt::Key_BracketRight。
case Qt::Key_Left: //arrows key must use WITH_?_MODIFIER
{
if (WITH_MODEL_MODIFIER)
modelRotation(0, -5, 0);
else if (WITH_TRANSLATE_MODIFIER)
setXShift(_xShift -1);// move -model
else
setXShift(_xShift +1);// move +view
}
break;
case Qt::Key_Right:
/*一串代码*/
case Qt::Key_Up:
/*一串代码*/
case Qt::Key_Down:
/*一串代码*/
左方向键,注释中提到,方向键必须用WITH_?_MODIFIER。WITH_MODEL_MODIFIER下模型沿y方向旋转,WITH_TRANSLATE_MODIFIER下模型沿x方向平移,否则视角沿x方向平移。与之对应的有Qt::Key_Right、Qt::Key_Up、Qt::Key_Down。
case Qt::Key_Minus:
{
setZoom(_zoom - 10); // zoom out
}
break;
case Qt::Key_Equal:
/*一串代码*/
减号键(-),缩小。与之对应的有 Qt::Key_Equal。
case Qt::Key_Underscore:
{
emit changeMarkerSize(_markerSize - 1);
}
break;
case Qt::Key_Plus:
/*一串代码*/
下划线键,缩小标记尺寸。与之对应的有Qt::Key_Plus。
还有一些按键不一一列举解释,见下表。
| Qt对象 | 按键 |
|---|---|
| Qt::Key_Backspace | 退格键 |
| Qt::Key_Backslash | 反斜杠键 |
| Qt::Key_Comma | 逗号键 |
| Qt::Key_Period | 句号键 |
| Qt::Key_Slash | 斜杠键 |
| Qt::Key_Less | 小于号键 |
| Qt::Key_Greater | 大于号键 |
| Qt::Key_Question | 问号键 |
这些按键在定义的时候,很多会通过发送信号来执行对应操作(emit语句)。
之后是一些快捷键的定义,
OpenGL快捷键
case Qt::Key_B:
if (IS_CTRL_MODIFIER)
{
setBright();
}else if (IS_ALT_MODIFIER)
{
emit changeEditinput("Alt+B: Drawing BBox");
if(!isoperating)
isoperating=true;
callStrokeCurveDrawingBBoxes();//For serial BBoxes curve drawing shortcut
}
break;
alt+B时,发送 changeEditinput(“Alt+B: Drawing BBox”) 信号(使右下角的文本框显示输入的字符串),进入标记模式。
case Qt::Key_R:
if (IS_CTRL_MODIFIER)
{
reloadData();
}
else
{
returncheckmode();
}
break;
按R键进入检查模型(我自己用的时候显示没找到文件),ctrl+R重新载入数据。
case Qt::Key_U:
if (IS_CTRL_MODIFIER)
{
updateWithTriView();
}
break;
ctrl+U更新三视图。
高级OpenGL快捷键
case Qt::Key_I:
if ( WITH_SHIFT_MODIFIER && //advanced
WITH_CTRL_MODIFIER
)
{
showGLinfo();
}
else if (renderer)
{
Renderer_gl1* thisRenderer = static_cast<Renderer_gl1*>(this->getRenderer());
if (thisRenderer->selectMode == Renderer::smDeleteMultiNeurons)
{
thisRenderer->setDeleteKey(1);
thisRenderer->deleteMultiNeuronsByStroke();
}
}
break;
shift+ctrl+I显示GL窗口信息,其他有什么用暂时不知道。
case Qt::Key_G:
if ( WITH_SHIFT_MODIFIER && //advanced
WITH_CTRL_MODIFIER
)
{
toggleShader();
}else if (IS_ALT_MODIFIER)
{
emit changeEditinput("Alt+G: Drawing Global");
if(!isoperating)
isoperating=true;
callStrokeCurveDrawingGlobal();//For Global optimal curve drawing shortcut
}else
{
emit changeEditinput("Alt+G: GDTraing");
if(!isoperating)
isoperating=true;
callGDTracing();
}
break;
shift+ctrl+G对图像做toggleShader(切换着色器)并显示。alt+G也是标注神经元,但目前只知道是global模式的标注,具体是什么还不知道。其他方式按G进入GDTracing标注模式,但具体怎么用还是不知道。
case Qt::Key_F:
if (IS_CTRL_MODIFIER)
{
toggleTexFilter();
}
else if (IS_ALT_MODIFIER)
{
/*非常长的一大串代码*/
}
break;
纹理操作
ctrl+F对图像做toggleTexFilter(切换纹理过滤器)并显示。alt+F跟Terafly有关。
case Qt::Key_F1:
/*一串代码*/
case Qt::Key_F2:
/*一串代码*/
case Qt::Key_F3:
/*一串代码*/
这三个也都跟Terafly有关,暂时不看。
case Qt::Key_E:
if (IS_ALT_MODIFIER)
{
emit changeEditinput("Alt+E");
if(!isoperating)
isoperating=true;
toggleEditMode();
}
else if (IS_SHIFT_MODIFIER)
{
/*一串代码*/
}
else
{
callcheckmode();
}
break;
alt+E切换编辑/非编辑模式,shift+E跟Terafly有关,暂时不看。
case Qt::Key_T:
if ( WITH_SHIFT_MODIFIER && //advanced
WITH_CTRL_MODIFIER
)
{
toggleTex2D3D();
}else if (IS_ALT_MODIFIER)
{
emit changeEditinput("Alt+T");
if(!isoperating)
isoperating=true;
callStrokeRetypeMultiNeurons();//For multiple segments retyping shortcut
}
else if (renderer)
{
/*一串代码*/
}
else
callAutoTracers();
break;
shift+ctrl+T调用toggleTex2D3D()但暂时不知道什么用,alt+T进入多类型的标注模式,可以画线后选择标记的类型(官方叫法是多神经元片段重新标注类型)。
case Qt::Key_D:
if (IS_ALT_MODIFIER)
{
emit changeEditinput("Alt+D: Deleting");
if(!isoperating)
isoperating=true;
callStrokeDeleteMultiNeurons(); //For multiple segments deleting shortcut,
}
else
{
// delete connected segments that have been highlighted,
Renderer_gl1* thisRenderer = static_cast<Renderer_gl1*>(this->getRenderer());
if (thisRenderer->selectMode == Renderer::smShowSubtree)
{
/*一串代码*/
}
}
break;
alt+D进入删除模式。
case Qt::Key_S:
if (IS_ALT_MODIFIER)
{
emit changeEditinput("Alt+S");
if(!isoperating)
isoperating=true;
callStrokeSplitMultiNeurons();//For multiple segments spliting shortcut, by ZZ,02212018
}
/*一串代码*/
break;
alt+S激活多神经元片段分割函数。
case Qt::Key_C:
if ( WITH_SHIFT_MODIFIER && //advanced
WITH_CTRL_MODIFIER
)
{
toggleTexCompression();
}else if (IS_ALT_MODIFIER)
{
emit changeEditinput("Alt+C: Connecting");
if(!isoperating)
isoperating=true;
callStrokeConnectMultiNeurons();//For multiple segments connection shortcut
}
else if (IS_SHIFT_MODIFIER)
{
/*一串代码*/
}
else
{
neuronColorMode = (neuronColorMode==0)?5:0; //0 default display mode, 5 confidence level mode
updateColorMode(neuronColorMode);
}
break;
shift+ctrl+C调用toggleTexCompression(),alt+C激活多神经元片段连接函数。
case Qt::Key_V:
if ( WITH_SHIFT_MODIFIER && //advanced
WITH_CTRL_MODIFIER
)
{
toggleTexStream();
}
else if (IS_ALT_MODIFIER)
{
emit changeEditinput("Alt+V");
if(!isoperating)
isoperating=true;
changeVolShadingOption();
}
else if (IS_CTRL_MODIFIER)
{
emit changeEditinput("Ctl+V");
if(!isoperating)
isoperating=true;
updateImageData();
}
else
{
callLoadNewStack(

本文主要介绍了Vaa3D的3D Viewer中与图像渲染和标注相关的代码结构,涵盖UI、渲染器、数据结构等方面。详细分析了GL窗口类、Renderer_gl类的成员函数,以及部分函数的具体代码,如V3dR_GLWidget的旋转函数和Renderer的渲染函数等。
最低0.47元/天 解锁文章
3万+

被折叠的 条评论
为什么被折叠?



