Paraview与VTK学习笔记(五)

上一节最后执行到:

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];memset(this->AccumulationBuffer,0,this->AccumulationBufferSize*sizeof(float));}}
这个方法使用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(*p1/num);
          p1++;
          p2++;
          *p2 = static_cast(*p1/num);
          p1++;
          p2++;
          *p2 = static_cast(*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(*p1/num);
          p1++;
          p2++;
          *p2 = static_cast(*p1/num);
          p1++;
          p2++;
          *p2 = static_cast(*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(*p2);
            p1++;
            p2++;
            *p1 += static_cast(*p2);
            p1++;
            p2++;
            *p1 += static_cast(*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()....}
  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学习笔记(五))