vtkRenderer中Render()函数解析

巫马正卿
2023-12-01
void vtkRenderer::Render(void)
{
  if(this->Delegate!=0 && this->Delegate->GetUsed())
    {
      this->Delegate->Render(this);
      return;
    }

  double   t1, t2;
  int      i;
  vtkProp  *aProp;
  int *size;

  // If Draw is not on, ignore the render.
  if (!this->Draw)
    {
    vtkDebugMacro("Ignoring render because Draw is off.");
    return;
    }

以上是一些初始化及判断,不用细讲

 t1 = vtkTimerLog::GetUniversalTime();

  this->InvokeEvent(vtkCommand::StartEvent,NULL);

  size = this->RenderWindow->GetSize();
ti为初始时间。代表渲染开始。

// if backing store is on and we have a stored image
  if (this->BackingStore && this->BackingImage &&
      this->MTime < this->RenderTime &&
      this->ActiveCamera->GetMTime() < this->RenderTime &&
      this->RenderWindow->GetMTime() < this->RenderTime &&
      this->BackingStoreSize[0] == size[0] &&
      this->BackingStoreSize[1] == size[1])
    {
    int mods = 0;
    vtkLight *light;
如果有backing store并且有srored image那么执行下面的代码。

 // now we just need to check the lights and actors
    vtkCollectionSimpleIterator sit;
    for(this->Lights->InitTraversal(sit);
        (light = this->Lights->GetNextLight(sit)); )
      {
      if (light->GetSwitch() &&
          light->GetMTime() > this->RenderTime)
        {
        mods = 1;
        goto completed_mod_check;
        }
      }
    vtkCollectionSimpleIterator pit;
    for (this->Props->InitTraversal(pit);
         (aProp = this->Props->GetNextProp(pit)); )
      {
      // if it's invisible, we can skip the rest
      if (aProp->GetVisibility())
        {
        if (aProp->GetRedrawMTime() > this->RenderTime)
          {
          mods = 1;
          goto completed_mod_check;
          }
        }
      }

    completed_mod_check:
这段代码非常简单,就是检查light和Prop如果有问题,也就是修改时间大于渲染命令发出的时间。说明不是最新的。则直接跳出,不执行下面的代码,如果过没有问题则执行下面的代码,使用到前面讲的backing的相关内容。

 if (!mods)
      {
      int rx1, ry1, rx2, ry2;

      // backing store should be OK, lets use it
      // calc the pixel range for the renderer
      rx1 = static_cast<int>(this->Viewport[0]*
                             (this->RenderWindow->GetSize()[0] - 1));
      ry1 = static_cast<int>(this->Viewport[1]*
                             (this->RenderWindow->GetSize()[1] - 1));
      rx2 = static_cast<int>(this->Viewport[2]*
                             (this->RenderWindow->GetSize()[0] - 1));
      ry2 = static_cast<int>(this->Viewport[3]*
                             (this->RenderWindow->GetSize()[1] - 1));
      this->RenderWindow->SetPixelData(rx1,ry1,rx2,ry2,this->BackingImage,0);
      this->InvokeEvent(vtkCommand::EndEvent,NULL);
      return;
      }
    }
上面可以看到是往整个RenderWindow上加上Backing Image。然后直接结束渲染事件。这应该是事先已经画好了?

到这里关于backing store的结束了。

 // Create the initial list of visible props
  // This will be passed through AllocateTime(), where
  // a time is allocated for each prop, and the list
  // maybe re-ordered by the cullers. Also create the
  // sublists for the props that need ray casting, and
  // the props that need to be rendered into an image.
  // Fill these in later (in AllocateTime) - get a
  // count of them there too
  if ( this->Props->GetNumberOfItems() > 0 )
    {
    this->PropArray = new vtkProp *[this->Props->GetNumberOfItems()];
    }
  else
    {
    this->PropArray = NULL;
    }
初始可视的一列props。这个列将会通过AllocateTime()函数传递,在这个函数中,他将会给每一个prop分配时间。并且这个list可能会被cullers重新排序。同样的可以给这些需要光线投射的props创建子列,并且这些prop都需要被渲染进图像之中。在AllocateTime中填充他们,并且统计它们的数量。
 this->PropArrayCount = 0;
  vtkCollectionSimpleIterator pit;
  for ( this->Props->InitTraversal(pit);
        (aProp = this->Props->GetNextProp(pit)); )
    {
    if ( aProp->GetVisibility() )
      {
      this->PropArray[this->PropArrayCount++] = aProp;
      }
    }

  if ( this->PropArrayCount == 0 )
    {
    vtkDebugMacro( << "There are no visible props!" );
    }
  else
    {
把每个prop放进PropArray这个数组中去。

   // Call all the culling methods to set allocated time
    // for each prop and re-order the prop list if desired

    this->AllocateTime();
对每个prop分配时间和重新排序。

  // do the render library specific stuff
  this->DeviceRender();

  // If we aborted, restore old estimated times
  // Setting the allocated render time to zero also sets the
  // estimated render time to zero, so that when we add back
  // in the old value we have set it correctly.
  if ( this->RenderWindow->GetAbortRender() )
    {
    for ( i = 0; i < this->PropArrayCount; i++ )
      {
      this->PropArray[i]->RestoreEstimatedRenderTime();
      }
    }
如果放弃现在的渲染,那么需要重新恢复之前的预估时间。设置allocated render时间为0,并且设置estimated render 时间为0以保证当我们需要加回以前的值是,我们已经设置正确了。

 // Clean up the space we allocated before. If the PropArray exists,
  // they all should exist
  delete [] this->PropArray;
  this->PropArray = NULL;

  if (this->BackingStore)
    {
    delete [] this->BackingImage;

    int rx1, ry1, rx2, ry2;

    // backing store should be OK, lets use it
    // calc the pixel range for the renderer
    rx1 = static_cast<int>(this->Viewport[0]*(size[0] - 1));
    ry1 = static_cast<int>(this->Viewport[1]*(size[1] - 1));
    rx2 = static_cast<int>(this->Viewport[2]*(size[0] - 1));
    ry2 = static_cast<int>(this->Viewport[3]*(size[1] - 1));
    this->BackingImage = this->RenderWindow->GetPixelData(rx1,ry1,rx2,ry2,0);
    this->BackingStoreSize[0] = size[0];
    this->BackingStoreSize[1] = size[1];
    }
渲染完了,清除之前的分配的内存。
  // If we aborted, do not record the last render time.
  // Lets play around with determining the accuracy of the
  // EstimatedRenderTimes.  We can try to adjust for bad
  // estimates with the TimeFactor.
  if ( ! this->RenderWindow->GetAbortRender() )
    {
    // Measure the actual RenderTime
    t2 = vtkTimerLog::GetUniversalTime();
    this->LastRenderTimeInSeconds = static_cast<double>(t2 - t1);

    if (this->LastRenderTimeInSeconds == 0.0)
      {
      this->LastRenderTimeInSeconds = 0.0001;
      }
    this->TimeFactor = this->AllocatedRenderTime/this->LastRenderTimeInSeconds;
    }
  this->InvokeEvent(vtkCommand::EndEvent,NULL);
}
计算时间。

看完整个代码不禁想问,下一级的渲染在哪里?

void vtkRenderer::AllocateTime()
{
  int          initialized = 0;
  double        renderTime;
  double        totalTime;
  int          i;
  vtkCuller    *aCuller;
  vtkProp      *aProp;

  // Give each of the cullers a chance to modify allocated rendering time
  // for the entire set of props. Each culler returns the total time given
  // by AllocatedRenderTime for all props. Each culler is required to
  // place any props that have an allocated render time of 0.0
  // at the end of the list. The PropArrayCount value that is
  // returned is the number of non-zero, visible actors.
  // Some cullers may do additional sorting of the list (by distance,
  // importance, etc).
  //
从这段注释我们可以看出这个函数的作用,上面我们已经提到过了,是给每一个cullers一个机会去修改整个一列props的分配的渲染时间。每一个culler返回对于所有的props通过AllocatedRendeTime给的整个的时间。每一个culler需要设置一些props,他们所分配的时间是0.0,这些props在list的最后。PropArrayCount返回不是0的个数,即可视的actors。一些cullers将会做一些排序这个列的工作。

 // The first culler will initialize all the allocated render times.
  // Any subsequent culling will multiply the new render time by the
  // existing render time for an actor.

  totalTime = this->PropArrayCount;
  this->ComputeAspect();
第一个culler将会初始化所有的分配的渲染时间,所有随后的culling将会乘以这个新的渲染时间。通过把这个已经存在的render time 作为一个因子。

  // It is very likely that the culler framework will call our
  // GetActiveCamera (say, to get the view frustrum planes for example).
  // This does not reset the camera anymore. If no camera has been
  // created though, we want it not only to be created but also reset
  // so that it behaves nicely for people who never bother with the camera
  // (i.e. neither call GetActiveCamera or ResetCamera). Of course,
  // it is very likely that the camera has already been created
  // (guaranteed if this renderer is being rendered as part of a
  // vtkRenderWindow).
很可能这个culler的框架将会调用GetActiveCamera(l例如想要获得锥内面的视图)。这将不会再重置这个相机。如果还没有创建任何的camera,我们不仅需要创建这个相机,还需要重置他。以保证他能够很好的表现。当然大部分的情况下,camera都已经创建了。(保证如果这个renderer正在被渲染陈vtkRenderWindow的一部分)。

 if ( this->Cullers->GetNumberOfItems())
    {
    this->GetActiveCameraAndResetIfCreated();
    }

  vtkCollectionSimpleIterator sit;
  for (this->Cullers->InitTraversal(sit);
       (aCuller=this->Cullers->GetNextCuller(sit));)
    {
    totalTime =
      aCuller->Cull(this,this->PropArray, this->PropArrayCount,initialized );
    }
  // loop through all props and set the AllocatedRenderTime
  for ( i = 0; i < this->PropArrayCount; i++ )
    {
    aProp = this->PropArray[i];

    // If we don't have an outer cull method in any of the cullers,
    // then the allocated render time has not yet been initialized
    renderTime = (initialized)?(aProp->GetRenderTimeMultiplier()):(1.0);

    // We need to divide by total time so that the total rendering time
    // (all prop's AllocatedRenderTime added together) would be equal
    // to the renderer's AllocatedRenderTime.
    aProp->
      SetAllocatedRenderTime(( renderTime / totalTime ) *
                             this->AllocatedRenderTime,
                             this );
    }
}
分配时间。
下面来分析一段之前计算渲染时间的代码:

// Returns the elapsed number of seconds since January 1, 1970. This
// is also called Universal Coordinated Time.
double vtkTimerLog::GetUniversalTime()
{
  double currentTimeInSeconds;

#ifdef _WIN32
#ifdef _WIN32_WCE
  FILETIME CurrentTime;
  SYSTEMTIME st;
  GetLocalTime(&st);
  SystemTimeToFileTime(&st, &CurrentTime);
  currentTimeInSeconds = CurrentTime.dwHighDateTime;
  currentTimeInSeconds *= 429.4967296;
  currentTimeInSeconds = currentTimeInSeconds +
        CurrentTime.dwLowDateTime / 10000000.0;
#else
  timeb CurrentTime;
  static double scale = 1.0/1000.0;
  ::ftime( &CurrentTime );
  currentTimeInSeconds = CurrentTime.time + scale * CurrentTime.millitm;
#endif
#else
  timeval CurrentTime;
  static double scale = 1.0/1000000.0;
  gettimeofday( &CurrentTime, NULL );
  currentTimeInSeconds = CurrentTime.tv_sec + scale * CurrentTime.tv_usec;
#endif

  return currentTimeInSeconds;
}
这段代码是获取从1970年1月1日到现在的时间,我们是在linux环境下,所以计算的结果是由最后一段代码实现的。经过实际应用,我发现它是以微秒为单位的。

















 类似资料: