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环境下,所以计算的结果是由最后一段代码实现的。经过实际应用,我发现它是以微秒为单位的。