Paraview与VTK学习笔记(五)
2015-03-26 16:38
387 查看
上一节最后执行到:
如果是在中止的中间过程,则check并且返回
上面这段代码我们可以看出,主要是为了确保AccumulationBuffer的正确性,如果过不存在或者比bufferSize小。则给它删除原有的,重新赋值并且分配空间。
释放内存
我们可以看到上面真正渲染的代码是this->DoAARender()。那么我们继续分析这个函数
获得size,然后对于AA帧,抖动相机?
接下来,不论左眼右眼,我们都可以看到,它调用了this->Renders->Render();
Renders是vtkRendererCollection类的一个对象。
初始化rsit,然后获取第一个renderer。然后再获取RenderWindow和Layer的数量。
this->GetRenderWindow()->Render();也就是执行到了vtkRenderWindow::Render()了,我们可以看到这个函数是告诉这个RenderWindow下的每一个renderer去渲染他的图像,并且保持进程同步
// Ask each renderer owned by this RenderWindow to render its image and // synchronize this process
void vtkRenderWindow::Render() { int *size; int x,y; float *p1; // if we are in the middle of an abort check then return now if (this->InAbortCheck) { return; }
如果是在中止的中间过程,则check并且返回
// if we are in a render already from somewhere else abort now if (this->InRender) { return; }如果从其他某个地方现在已经在渲染了,那么立即中止
// if SetSize has not yet been called (from a script, possible off // screen use, other scenarios?) then call it here with reasonable // default values if (0 == this->Size[0] && 0 == this->Size[1]) { this->SetSize(300, 300); }如果SetSize还没有被使用(通过一个脚本,或者关闭屏幕,或者其他情况),那么在这里调用它,并赋值默认值
// reset the Abort flag this->AbortRender = 0; this->InRender = 1; vtkDebugMacro(<< "Starting Render Method.\n"); this->InvokeEvent(vtkCommand::StartEvent,NULL); this->NeverRendered = 0; if ( this->Interactor && ! this->Interactor->GetInitialized() ) { this->Interactor->Initialize(); }重置中止符号,开始渲染,设置InRender为1。调用开始事件。并且初始化关联器
// CAUTION: // This method uses this->GetSize() and allocates buffers using that size. // Remember that GetSize() will returns a size scaled by the TileScale factor. // We should use GetActualSize() when we don't want the size to be scaled. // if there is a reason for an AccumulationBuffer if ( this->SubFrames || this->AAFrames || this->FDFrames) { // check the current size size = this->GetSize(); unsigned int bufferSize = 3*size[0]*size[1]; // If there is not a buffer or the size is too small // re-allocate it if( !this->AccumulationBuffer || bufferSize > this->AccumulationBufferSize) { // it is OK to delete null, no sense in two if's delete [] this->AccumulationBuffer; // Save the size of the buffer this->AccumulationBufferSize = 3*size[0]*size[1]; this->AccumulationBuffer = new float [this->AccumulationBufferSize];<span style="font-family: Arial, Helvetica, sans-serif;">memset(this->AccumulationBuffer,0,this->AccumulationBufferSize*sizeof(float));}}</span>这个方法使用this->GetSize(),并且分配buffers从而使用这个size。这个GetSize()函数会根据TileScale调整比例。如果我们不希望这个size被调整,那么调用GetActualSize()。
上面这段代码我们可以看出,主要是为了确保AccumulationBuffer的正确性,如果过不存在或者比bufferSize小。则给它删除原有的,重新赋值并且分配空间。
// handle any sub frames if (this->SubFrames) { // get the size size = this->GetSize(); // draw the images this->DoAARender(); // now accumulate the images if ((!this->AAFrames) && (!this->FDFrames)) { p1 = this->AccumulationBuffer; unsigned char *p2; unsigned char *p3; if (this->ResultFrame) { p2 = this->ResultFrame; } else { p2 = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); } p3 = p2; for (y = 0; y < size[1]; y++) { for (x = 0; x < size[0]; x++) { *p1 += *p2; p1++; p2++; *p1 += *p2; p1++; p2++; *p1 += *p2; p1++; p2++; } } delete [] p3; }控制子窗口,首先获得size,然后画出图形。把图像集成起来,如果当前window不是AAFrames且不是FDFrames。
// if this is the last sub frame then convert back into unsigned char this->CurrentSubFrame++; if (this->CurrentSubFrame >= this->SubFrames) { double num; unsigned char *p2 = new unsigned char [3*size[0]*size[1]]; num = this->SubFrames; if (this->AAFrames) { num *= this->AAFrames; } if (this->FDFrames) { num *= this->FDFrames; } this->ResultFrame = p2; p1 = this->AccumulationBuffer; for (y = 0; y < size[1]; y++) { for (x = 0; x < size[0]; x++) { *p2 = static_cast<unsigned char>(*p1/num); p1++; p2++; *p2 = static_cast<unsigned char>(*p1/num); p1++; p2++; *p2 = static_cast<unsigned char>(*p1/num); p1++; p2++; } } this->CurrentSubFrame = 0; this->CopyResultFrame();如果这是最后的子帧,那么重新转换成unsigned char。
// free any memory delete [] this->AccumulationBuffer; this->AccumulationBuffer = NULL; } }
释放内存
else // no subframes { // get the size size = this->GetSize(); this->DoAARender(); // if we had some accumulation occur if (this->AccumulationBuffer) { double num; unsigned char *p2 = new unsigned char [3*size[0]*size[1]]; if (this->AAFrames) { num = this->AAFrames; } else { num = 1; } if (this->FDFrames) { num *= this->FDFrames; } this->ResultFrame = p2; p1 = this->AccumulationBuffer; for (y = 0; y < size[1]; y++) { for (x = 0; x < size[0]; x++) { *p2 = static_cast<unsigned char>(*p1/num); p1++; p2++; *p2 = static_cast<unsigned char>(*p1/num); p1++; p2++; *p2 = static_cast<unsigned char>(*p1/num); p1++; p2++; } } delete [] this->AccumulationBuffer; this->AccumulationBuffer = NULL; } this->CopyResultFrame(); }如果没有子帧。则直接执行。
delete [] this->ResultFrame; this->ResultFrame = NULL; this->InRender = 0; this->InvokeEvent(vtkCommand::EndEvent,NULL); }结束渲染事件。
我们可以看到上面真正渲染的代码是this->DoAARender()。那么我们继续分析这个函数
// Handle rendering any antialiased frames. void vtkRenderWindow::DoAARender() { int i; // handle any anti aliasing控制任何抗锯齿 if (this->AAFrames) { int *size; int x,y; float *p1; vtkRenderer *aren; vtkCamera *acam; double *dpoint; double offsets[2]; double origfocus[4]; double worldOffset[3];这个函数显然我们可以看到,它是用来控制渲染抗锯齿帧的。
// get the size size = this->GetSize(); origfocus[3] = 1.0; for (i = 0; i < this->AAFrames; i++) { // jitter the cameras offsets[0] = vtkMath::Random() - 0.5; offsets[1] = vtkMath::Random() - 0.5; vtkCollectionSimpleIterator rsit; for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { acam = aren->GetActiveCamera();
获得size,然后对于AA帧,抖动相机?
// calculate the amount to jitter acam->GetFocalPoint(origfocus); aren->SetWorldPoint(origfocus); aren->WorldToDisplay(); dpoint = aren->GetDisplayPoint(); aren->SetDisplayPoint(dpoint[0] + offsets[0], dpoint[1] + offsets[1], dpoint[2]); aren->DisplayToWorld(); dpoint = aren->GetWorldPoint(); dpoint[0] /= dpoint[3]; dpoint[1] /= dpoint[3]; dpoint[2] /= dpoint[3]; acam->SetFocalPoint(dpoint); worldOffset[0] = dpoint[0] - origfocus[0]; worldOffset[1] = dpoint[1] - origfocus[1]; worldOffset[2] = dpoint[2] - origfocus[2]; acam->GetPosition(dpoint); acam->SetPosition(dpoint[0]+worldOffset[0], dpoint[1]+worldOffset[1], dpoint[2]+worldOffset[2]); } // draw the images this->DoFDRender();计算抖动的值,然后继续渲染
// restore the jitter to normal for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { acam = aren->GetActiveCamera(); // calculate the amount to jitter acam->GetFocalPoint(origfocus); aren->SetWorldPoint(origfocus); aren->WorldToDisplay(); dpoint = aren->GetDisplayPoint(); aren->SetDisplayPoint(dpoint[0] - offsets[0], dpoint[1] - offsets[1], dpoint[2]); aren->DisplayToWorld(); dpoint = aren->GetWorldPoint(); dpoint[0] /= dpoint[3]; dpoint[1] /= dpoint[3]; dpoint[2] /= dpoint[3]; acam->SetFocalPoint(dpoint); worldOffset[0] = dpoint[0] - origfocus[0]; worldOffset[1] = dpoint[1] - origfocus[1]; worldOffset[2] = dpoint[2] - origfocus[2]; acam->GetPosition(dpoint); acam->SetPosition(dpoint[0]+worldOffset[0], dpoint[1]+worldOffset[1], dpoint[2]+worldOffset[2]); }然后把抖动恢复成正常值
// now accumulate the images p1 = this->AccumulationBuffer; if (!this->FDFrames) { unsigned char *p2; unsigned char *p3; if (this->ResultFrame) { p2 = this->ResultFrame; } else { p2 = this->GetPixelData(0,0,size[0]-1,size[1]-1,!this->DoubleBuffer); } p3 = p2; for (y = 0; y < size[1]; y++) { for (x = 0; x < size[0]; x++) { *p1 += static_cast<float>(*p2); p1++; p2++; *p1 += static_cast<float>(*p2); p1++; p2++; *p1 += static_cast<float>(*p2); p1++; p2++; } } delete [] p3; } } }然后再组装图像。
else { this->DoFDRender(); } }如果没有AA帧,就直接执行下一级渲染。
// Handle rendering any focal depth frames. void vtkRenderWindow::DoFDRender() { int i; // handle any focal depth if (this->FDFrames) {...this->DoStereoRender()....<span style="font-family: Arial, Helvetica, sans-serif;">}</span>
else { this->DoStereoRender(); }这个函数是用来控制渲染所有焦点深度的帧的。其基本过程和上面一样。就没什么细说的,只是算法不一样。再看下一级渲染:
void vtkRenderWindow::DoStereoRender() { vtkCollectionSimpleIterator rsit; this->Start();//初始化渲染进程 this->StereoUpdate();//更新整个系统,如果需要,还要控制立体渲染。对于一些立体方法,在这里子类需要选择硬件支持 if (this->StereoType != VTK_STEREO_RIGHT) { // render the left eye vtkRenderer *aren; for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) {首先渲染左眼。一个安全的方式通过集合去进行迭代,没一次传递相同的cookie值。这里定义一个for循环,对于每一个Render循环。
// Ugly piece of code - we need to know if the camera already // exists or not. If it does not yet exist, we must reset the // camera here - otherwise it will never be done (missing its // oppportunity to be reset in the Render method of the // vtkRenderer because it will already exist by that point...) if ( !aren->IsActiveCameraCreated() ) { aren->ResetCamera(); } aren->GetActiveCamera()->SetLeftEye(1); } this->Renderers->Render(); }我们需要知道相机是否已经存在。如果过不存在,我们需要reser它。否则我们把它设置为左眼使用。然后进行渲染。
if (this->StereoRender) { this->StereoMidpoint(); if (this->StereoType != VTK_STEREO_LEFT) { // render the right eye vtkRenderer *aren; for (this->Renderers->InitTraversal(rsit); (aren = this->Renderers->GetNextRenderer(rsit)); ) { // Duplicate the ugly code here too. Of course, most // times the left eye will have been rendered before // the right eye, but it is possible that the user sets // everything up and renders just the right eye - so we // need this check here too. if ( !aren->IsActiveCameraCreated() ) { aren->ResetCamera(); } aren->GetActiveCamera()->SetLeftEye(0); } this->Renderers->Render(); } this->StereoRenderComplete(); } }这段代码与上面基本一样,其实就是再渲染右眼,但中间有一个this->Steromidpoint(),这个方法使用来渲染从左眼到右眼的对参数的一些改变操作。
接下来,不论左眼右眼,我们都可以看到,它调用了this->Renders->Render();
Renders是vtkRendererCollection类的一个对象。
void vtkRendererCollection::Render() { vtkRenderer *ren, *firstRen; vtkRenderWindow *renWin; int numLayers, i; vtkCollectionSimpleIterator rsit; this->InitTraversal(rsit); firstRen = this->GetNextRenderer(rsit); if (firstRen == NULL) { // We cannot determine the number of layers because there are no // renderers. No problem, just return. return; } renWin = firstRen->GetRenderWindow(); numLayers = renWin->GetNumberOfLayers();
初始化rsit,然后获取第一个renderer。然后再获取RenderWindow和Layer的数量。
// Only have the renderers render from back to front. This is necessary // because transparent renderers clear the z-buffer before each render and // then overlay their image. for (i = 0; i < numLayers; i++) { for (this->InitTraversal(rsit); (ren = this->GetNextRenderer(rsit)); ) { if (ren->GetLayer() == i) { ren->Render(); } } }从后到前,对于每一层Layer,使每一个renderer渲染。
// Let the user know if they have put a renderer at an unused layer. for (this->InitTraversal(rsit); (ren = this->GetNextRenderer(rsit)); ) { if (ren->GetLayer() < 0 || ren->GetLayer() >= numLayers) { vtkErrorMacro(<< "Invalid layer for renderer: not rendered."); } } }报错,使用户知道他是否使一个renderer放到了不会用到的layer上。
相关文章推荐
- Paraview与VTK学习笔记(三)
- Paraview与VTK学习笔记(六)//representation篇
- Paraview与VTK学习笔记(四)
- Paraview和vtk的学习笔记(一)
- Paraview与vtk学习笔记(二)
- Paraview与VTK学习笔记(七)sources篇
- VTK学习笔记-2-TIFF图像数据的重切片
- VTK学习笔记1—VTK安装及源码编译(Winxp + VS2010 + CMake2.8.6 + VTK5.8)
- VTK学习笔记(1)
- VTK 学习笔记 - 天行健
- VTK学习笔记-1
- VTK学习笔记:可视化模型
- VTK学习笔记:使用VTK交互功能
- VTK学习笔记:数据集之非结构化网格集
- VTK学习笔记之图像处理
- VTK学习笔记:数据集和单元集合介绍
- VTK学习笔记之使用vtkMarchingCubes
- VTk学习笔记--vtkInteractorStyleRubberBand2D
- VTK学习笔记:数据集之结构化点集
- VTK学习笔记:数据集之多边形数据集