/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkRenderer.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkRenderer.h" #include "vtkAssemblyNode.h" #include "vtkAssemblyPath.h" #include "vtkCamera.h" #include "vtkCommand.h" #include "vtkCuller.h" #include "vtkCullerCollection.h" #include "vtkFrustumCoverageCuller.h" #include "vtkGraphicsFactory.h" #include "vtkLight.h" #include "vtkLightCollection.h" #include "vtkMath.h" #include "vtkMatrix4x4.h" #include "vtkOutputWindow.h" #include "vtkPicker.h" #include "vtkProp3DCollection.h" #include "vtkRenderWindow.h" #include "vtkTimerLog.h" #include "vtkVolume.h" vtkCxxRevisionMacro(vtkRenderer, "$Revision: 1.219 $"); //---------------------------------------------------------------------------- // Needed when we don't use the vtkStandardNewMacro. vtkInstantiatorNewMacro(vtkRenderer); //---------------------------------------------------------------------------- // Create a vtkRenderer with a black background, a white ambient light, // two-sided lighting turned on, a viewport of (0,0,1,1), and backface culling // turned off. vtkRenderer::vtkRenderer() { this->PickedProp = NULL; this->ActiveCamera = NULL; this->Ambient[0] = 1; this->Ambient[1] = 1; this->Ambient[2] = 1; this->AllocatedRenderTime = 100; this->TimeFactor = 1.0; this->CreatedLight = NULL; this->AutomaticLightCreation = 1; this->TwoSidedLighting = 1; this->BackingStore = 0; this->BackingImage = NULL; this->BackingStoreSize[0] = -1; this->BackingStoreSize[1] = -1; this->LastRenderTimeInSeconds = -1.0; this->RenderWindow = NULL; this->Lights = vtkLightCollection::New(); this->Actors = vtkActorCollection::New(); this->Volumes = vtkVolumeCollection::New(); this->LightFollowCamera = 1; this->NumberOfPropsRendered = 0; this->PropArray = NULL; this->PropArrayCount = 0; this->PathArray = NULL; this->PathArrayCount = 0; this->Layer = 0; this->ComputedVisiblePropBounds[0] = VTK_DOUBLE_MAX; this->ComputedVisiblePropBounds[1] = -VTK_DOUBLE_MAX; this->ComputedVisiblePropBounds[2] = VTK_DOUBLE_MAX; this->ComputedVisiblePropBounds[3] = -VTK_DOUBLE_MAX; this->ComputedVisiblePropBounds[4] = VTK_DOUBLE_MAX; this->ComputedVisiblePropBounds[5] = -VTK_DOUBLE_MAX; this->Interactive = 1; this->Cullers = vtkCullerCollection::New(); vtkFrustumCoverageCuller *cull = vtkFrustumCoverageCuller::New(); this->Cullers->AddItem(cull); cull->Delete(); // a value of 0 indicates it is uninitialized this->NearClippingPlaneTolerance = 0; this->Erase = 1; } vtkRenderer::~vtkRenderer() { this->SetRenderWindow( NULL ); if (this->ActiveCamera) { this->ActiveCamera->UnRegister(this); this->ActiveCamera = NULL; } if (this->CreatedLight) { this->CreatedLight->UnRegister(this); this->CreatedLight = NULL; } if (this->BackingImage) { delete [] this->BackingImage; } this->Actors->Delete(); this->Actors = NULL; this->Volumes->Delete(); this->Volumes = NULL; this->Lights->Delete(); this->Lights = NULL; this->Cullers->Delete(); this->Cullers = NULL; } // return the correct type of Renderer vtkRenderer *vtkRenderer::New() { // First try to create the object from the vtkObjectFactory vtkObject* ret = vtkGraphicsFactory::CreateInstance("vtkRenderer"); return (vtkRenderer *)ret; } // Concrete render method. void vtkRenderer::Render(void) { double t1, t2; int i; vtkProp *aProp; int *size; t1 = vtkTimerLog::GetUniversalTime(); this->InvokeEvent(vtkCommand::StartEvent,NULL); size = this->RenderWindow->GetSize(); // 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; // 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: if (!mods) { int rx1, ry1, rx2, ry2; // backing store should be OK, lets use it // calc the pixel range for the renderer rx1 = (int)(this->Viewport[0]*(this->RenderWindow->GetSize()[0] - 1)); ry1 = (int)(this->Viewport[1]*(this->RenderWindow->GetSize()[1] - 1)); rx2 = (int)(this->Viewport[2]*(this->RenderWindow->GetSize()[0] - 1)); ry2 = (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; } } // 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; } 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 { // Call all the culling methods to set allocated time // for each prop and re-order the prop list if desired this->AllocateTime(); } // 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(); } } // Clean up the space we allocated before. If the PropArray exists, // they all should exist if ( this->PropArray) { delete [] this->PropArray; this->PropArray = NULL; } if (this->BackingStore) { if (this->BackingImage) { delete [] this->BackingImage; } int rx1, ry1, rx2, ry2; // backing store should be OK, lets use it // calc the pixel range for the renderer rx1 = (int)(this->Viewport[0]*(size[0] - 1)); ry1 = (int)(this->Viewport[1]*(size[1] - 1)); rx2 = (int)(this->Viewport[2]*(size[0] - 1)); ry2 = (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 acuracy 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 = (double) (t2 - t1); if (this->LastRenderTimeInSeconds == 0.0) { this->LastRenderTimeInSeconds = 0.0001; } this->TimeFactor = this->AllocatedRenderTime/this->LastRenderTimeInSeconds; } } double vtkRenderer::GetAllocatedRenderTime() { return this->AllocatedRenderTime; } double vtkRenderer::GetTimeFactor() { return this->TimeFactor; } // Ask active camera to load its view matrix. int vtkRenderer::UpdateCamera () { if (!this->ActiveCamera) { vtkDebugMacro(<< "No cameras are on, creating one."); // the get method will automagically create a camera // and reset it since one hasn't been specified yet this->GetActiveCameraAndEventuallyReset(); } // update the viewing transformation this->ActiveCamera->Render((vtkRenderer *)this); return 1; } int vtkRenderer::UpdateLightsGeometryToFollowCamera() { vtkCamera *camera; vtkLight *light; vtkMatrix4x4 *lightMatrix; // only update the light's geometry if this Renderer is tracking // this lights. That allows one renderer to view the lights that // another renderer is setting up. camera = this->GetActiveCameraAndEventuallyReset(); lightMatrix = camera->GetCameraLightTransformMatrix(); vtkCollectionSimpleIterator sit; for(this->Lights->InitTraversal(sit); (light = this->Lights->GetNextLight(sit)); ) { if (light->LightTypeIsSceneLight()) { // Do nothing. Don't reset the transform matrix because applications // may have set a custom matrix. Only reset the transform matrix in // vtkLight::SetLightTypeToSceneLight() } else if (light->LightTypeIsHeadlight()) { // update position and orientation of light to match camera. light->SetPosition(camera->GetPosition()); light->SetFocalPoint(camera->GetFocalPoint()); } else if (light->LightTypeIsCameraLight()) { light->SetTransformMatrix(lightMatrix); } else { vtkErrorMacro(<< "light has unknown light type"); } } return 1; } int vtkRenderer::UpdateLightGeometry() { if (this->LightFollowCamera) { // only update the light's geometry if this Renderer is tracking // this lights. That allows one renderer to view the lights that // another renderer is setting up. return this->UpdateLightsGeometryToFollowCamera(); } return 1; } // Do all outer culling to set allocated time for each prop. // Possibly re-order the actor list. 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). // // 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(); // 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) if ( this->Cullers->GetNumberOfItems()) { this->GetActiveCameraAndEventuallyReset(); } vtkCollectionSimpleIterator sit; for (this->Cullers->InitTraversal(sit); (aCuller=this->Cullers->GetNextCuller(sit));) { totalTime = aCuller->Cull((vtkRenderer *)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 ); } } // Ask actors to render themselves. As a side effect will cause // visualization network to update. int vtkRenderer::UpdateGeometry() { int i; this->NumberOfPropsRendered = 0; if ( this->PropArrayCount == 0 ) { this->InvokeEvent(vtkCommand::EndEvent,NULL); return 0; } // We can render everything because if it was // not visible it would not have been put in the // list in the first place, and if it was allocated // no time (culled) it would have been removed from // the list // loop through props and give them a chance to // render themselves as opaque geometry for ( i = 0; i < this->PropArrayCount; i++ ) { this->NumberOfPropsRendered += this->PropArray[i]->RenderOpaqueGeometry(this); } // loop through props and give them a chance to // render themselves as translucent geometry for ( i = 0; i < this->PropArrayCount; i++ ) { this->NumberOfPropsRendered += this->PropArray[i]->RenderTranslucentGeometry(this); } // loop through props and give them a chance to // render themselves as an overlay (or underlay) for ( i = 0; i < this->PropArrayCount; i++ ) { this->NumberOfPropsRendered += this->PropArray[i]->RenderOverlay(this); } this->InvokeEvent(vtkCommand::EndEvent,NULL); this->RenderTime.Modified(); vtkDebugMacro( << "Rendered " << this->NumberOfPropsRendered << " actors" ); return this->NumberOfPropsRendered; } vtkWindow *vtkRenderer::GetVTKWindow() { return this->RenderWindow; } // Specify the camera to use for this renderer. void vtkRenderer::SetActiveCamera(vtkCamera *cam) { if (this->ActiveCamera == cam) { return; } if (this->ActiveCamera) { this->ActiveCamera->UnRegister(this); this->ActiveCamera = NULL; } if (cam) { cam->Register(this); } this->ActiveCamera = cam; this->Modified(); } //---------------------------------------------------------------------------- vtkCamera* vtkRenderer::MakeCamera() { return vtkCamera::New(); } //---------------------------------------------------------------------------- vtkCamera *vtkRenderer::GetActiveCamera() { if ( this->ActiveCamera == NULL ) { vtkCamera *cam = this->MakeCamera(); this->SetActiveCamera(cam); cam->Delete(); // The following line has been commented out as it has a lot of // side effects (like computing the bounds of all props, which will // eventually call UpdateInformation() on data objects, etc). // Instead, the rendering code has been updated to internally use // GetActiveCameraAndEventuallyReset which will reset the camera // if it gets created // this->ResetCamera(); } return this->ActiveCamera; } //---------------------------------------------------------------------------- vtkCamera *vtkRenderer::GetActiveCameraAndEventuallyReset() { if (this->ActiveCamera == NULL) { this->GetActiveCamera(); this->ResetCamera(); } return this->ActiveCamera; } //---------------------------------------------------------------------------- void vtkRenderer::AddActor(vtkProp* p) { this->AddViewProp(p); } //---------------------------------------------------------------------------- void vtkRenderer::AddVolume(vtkProp* p) { this->AddViewProp(p); } //---------------------------------------------------------------------------- void vtkRenderer::RemoveActor(vtkProp* p) { this->Actors->RemoveItem(p); this->RemoveViewProp(p); } //---------------------------------------------------------------------------- void vtkRenderer::RemoveVolume(vtkProp* p) { this->Volumes->RemoveItem(p); this->RemoveViewProp(p); } // Add a light to the list of lights. void vtkRenderer::AddLight(vtkLight *light) { this->Lights->AddItem(light); } // look through the props and get all the actors vtkActorCollection *vtkRenderer::GetActors() { vtkProp *aProp; // clear the collection first this->Actors->RemoveAllItems(); vtkCollectionSimpleIterator pit; for (this->Props->InitTraversal(pit); (aProp = this->Props->GetNextProp(pit)); ) { aProp->GetActors(this->Actors); } return this->Actors; } // look through the props and get all the volumes vtkVolumeCollection *vtkRenderer::GetVolumes() { vtkProp *aProp; // clear the collection first this->Volumes->RemoveAllItems(); vtkCollectionSimpleIterator pit; for (this->Props->InitTraversal(pit); (aProp = this->Props->GetNextProp(pit)); ) { aProp->GetVolumes(this->Volumes); } return this->Volumes; } // Remove a light from the list of lights. void vtkRenderer::RemoveLight(vtkLight *light) { this->Lights->RemoveItem(light); } // Add an culler to the list of cullers. void vtkRenderer::AddCuller(vtkCuller *culler) { this->Cullers->AddItem(culler); } // Remove an actor from the list of cullers. void vtkRenderer::RemoveCuller(vtkCuller *culler) { this->Cullers->RemoveItem(culler); } vtkLight *vtkRenderer::MakeLight() { return vtkLight::New(); } void vtkRenderer::CreateLight(void) { if ( !this->AutomaticLightCreation ) { return; } if (this->CreatedLight) { this->CreatedLight->UnRegister(this); this->CreatedLight = NULL; } // I do not see why UnRegister is used on CreatedLight, but lets be // consistent. vtkLight *l = this->MakeLight(); this->CreatedLight = l; this->CreatedLight->Register(this); this->AddLight(this->CreatedLight); l->Delete(); this->CreatedLight->SetLightTypeToHeadlight(); // set these values just to have a good default should LightFollowCamera // be turned off. this->CreatedLight->SetPosition(this->GetActiveCamera()->GetPosition()); this->CreatedLight->SetFocalPoint(this->GetActiveCamera()->GetFocalPoint()); } // Compute the bounds of the visible props void vtkRenderer::ComputeVisiblePropBounds( double allBounds[6] ) { vtkProp *prop; double *bounds; int nothingVisible=1; allBounds[0] = allBounds[2] = allBounds[4] = VTK_DOUBLE_MAX; allBounds[1] = allBounds[3] = allBounds[5] = -VTK_DOUBLE_MAX; // loop through all props vtkCollectionSimpleIterator pit; for (this->Props->InitTraversal(pit); (prop = this->Props->GetNextProp(pit)); ) { // if it's invisible, or has no geometry, we can skip the rest if ( prop->GetVisibility() ) { bounds = prop->GetBounds(); // make sure we haven't got bogus bounds if ( bounds != NULL && vtkMath::AreBoundsInitialized(bounds)) { nothingVisible = 0; if (bounds[0] < allBounds[0]) { allBounds[0] = bounds[0]; } if (bounds[1] > allBounds[1]) { allBounds[1] = bounds[1]; } if (bounds[2] < allBounds[2]) { allBounds[2] = bounds[2]; } if (bounds[3] > allBounds[3]) { allBounds[3] = bounds[3]; } if (bounds[4] < allBounds[4]) { allBounds[4] = bounds[4]; } if (bounds[5] > allBounds[5]) { allBounds[5] = bounds[5]; } }//not bogus } } if ( nothingVisible ) { vtkMath::UninitializeBounds(allBounds); vtkDebugMacro(<< "Can't compute bounds, no 3D props are visible"); return; } } double *vtkRenderer::ComputeVisiblePropBounds() { this->ComputeVisiblePropBounds(this->ComputedVisiblePropBounds); return this->ComputedVisiblePropBounds; } // Automatically set up the camera based on the visible actors. // The camera will reposition itself to view the center point of the actors, // and move along its initial view plane normal (i.e., vector defined from // camera position to focal point) so that all of the actors can be seen. void vtkRenderer::ResetCamera() { double allBounds[6]; this->ComputeVisiblePropBounds( allBounds ); if (!vtkMath::AreBoundsInitialized(allBounds)) { vtkDebugMacro( << "Cannot reset camera!" ); } else { this->ResetCamera(allBounds); } // Here to let parallel/distributed compositing intercept // and do the right thing. this->InvokeEvent(vtkCommand::ResetCameraEvent,this); } // Automatically set the clipping range of the camera based on the // visible actors void vtkRenderer::ResetCameraClippingRange() { double allBounds[6]; this->ComputeVisiblePropBounds( allBounds ); if (!vtkMath::AreBoundsInitialized(allBounds)) { vtkDebugMacro( << "Cannot reset camera clipping range!" ); } else { this->ResetCameraClippingRange(allBounds); } // Here to let parallel/distributed compositing intercept // and do the right thing. this->InvokeEvent(vtkCommand::ResetCameraClippingRangeEvent,this); } // Automatically set up the camera based on a specified bounding box // (xmin,xmax, ymin,ymax, zmin,zmax). Camera will reposition itself so // that its focal point is the center of the bounding box, and adjust its // distance and position to preserve its initial view plane normal // (i.e., vector defined from camera position to focal point). Note: is // the view plane is parallel to the view up axis, the view up axis will // be reset to one of the three coordinate axes. void vtkRenderer::ResetCamera(double bounds[6]) { double center[3]; double distance; double vn[3], *vup; this->GetActiveCamera(); if ( this->ActiveCamera != NULL ) { this->ActiveCamera->GetViewPlaneNormal(vn); } else { vtkErrorMacro(<< "Trying to reset non-existant camera"); return; } center[0] = (bounds[0] + bounds[1])/2.0; center[1] = (bounds[2] + bounds[3])/2.0; center[2] = (bounds[4] + bounds[5])/2.0; double w1 = bounds[1] - bounds[0]; double w2 = bounds[3] - bounds[2]; double w3 = bounds[5] - bounds[4]; w1 *= w1; w2 *= w2; w3 *= w3; double radius = w1 + w2 + w3; // If we have just a single point, pick a radius of 1.0 radius = (radius==0)?(1.0):(radius); // compute the radius of the enclosing sphere radius = sqrt(radius)*0.5; // default so that the bounding sphere fits within the view fustrum // compute the distance from the intersection of the view frustum with the // bounding sphere. Basically in 2D draw a circle representing the bounding // sphere in 2D then draw a horizontal line going out from the center of // the circle. That is the camera view. Then draw a line from the camera // position to the point where it intersects the circle. (it will be tangent // to the circle at this point, this is important, only go to the tangent // point, do not draw all the way to the view plane). Then draw the radius // from the tangent point to the center of the circle. You will note that // this forms a right triangle with one side being the radius, another being // the target distance for the camera, then just find the target dist using // a sin. distance = radius/sin(this->ActiveCamera->GetViewAngle()*vtkMath::Pi()/360.0); // check view-up vector against view plane normal vup = this->ActiveCamera->GetViewUp(); if ( fabs(vtkMath::Dot(vup,vn)) > 0.999 ) { vtkWarningMacro(<<"Resetting view-up since view plane normal is parallel"); this->ActiveCamera->SetViewUp(-vup[2], vup[0], vup[1]); } // update the camera this->ActiveCamera->SetFocalPoint(center[0],center[1],center[2]); this->ActiveCamera->SetPosition(center[0]+distance*vn[0], center[1]+distance*vn[1], center[2]+distance*vn[2]); this->ResetCameraClippingRange( bounds ); // setup default parallel scale this->ActiveCamera->SetParallelScale(radius); } // Alternative version of ResetCamera(bounds[6]); void vtkRenderer::ResetCamera(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) { double bounds[6]; bounds[0] = xmin; bounds[1] = xmax; bounds[2] = ymin; bounds[3] = ymax; bounds[4] = zmin; bounds[5] = zmax; this->ResetCamera(bounds); } // Reset the camera clipping range to include this entire bounding box void vtkRenderer::ResetCameraClippingRange( double bounds[6] ) { double vn[3], position[3], a, b, c, d; double range[2], dist; int i, j, k; // Don't reset the clipping range when we don't have any 3D visible props if (!vtkMath::AreBoundsInitialized(bounds)) { return; } this->GetActiveCameraAndEventuallyReset(); if ( this->ActiveCamera == NULL ) { vtkErrorMacro(<< "Trying to reset clipping range of non-existant camera"); return; } // Find the plane equation for the camera view plane this->ActiveCamera->GetViewPlaneNormal(vn); this->ActiveCamera->GetPosition(position); a = -vn[0]; b = -vn[1]; c = -vn[2]; d = -(a*position[0] + b*position[1] + c*position[2]); // Set the max near clipping plane and the min far clipping plane range[0] = a*bounds[0] + b*bounds[2] + c*bounds[4] + d; range[1] = 1e-18; // Find the closest / farthest bounding box vertex for ( k = 0; k < 2; k++ ) { for ( j = 0; j < 2; j++ ) { for ( i = 0; i < 2; i++ ) { dist = a*bounds[i] + b*bounds[2+j] + c*bounds[4+k] + d; range[0] = (distrange[1])?(dist):(range[1]); } } } // Do not let the range behind the camera throw off the calculation. if (range[0] < 0.0) { range[0] = 0.0; } // Give ourselves a little breathing room range[0] = 0.99*range[0] - (range[1] - range[0])*0.5; range[1] = 1.01*range[1] + (range[1] - range[0])*0.5; // Make sure near is not bigger than far range[0] = (range[0] >= range[1])?(0.01*range[1]):(range[0]); // Make sure near is at least some fraction of far - this prevents near // from being behind the camera or too close in front. How close is too // close depends on the resolution of the depth buffer if (!this->NearClippingPlaneTolerance) { this->NearClippingPlaneTolerance = 0.01; if (this->RenderWindow) { int ZBufferDepth = this->RenderWindow->GetDepthBufferSize(); if ( ZBufferDepth > 16 ) { this->NearClippingPlaneTolerance = 0.001; } } } // make sure the front clipping range is not too far from the far clippnig // range, this is to make sure that the zbuffer resolution is effectively // used if (range[0] < this->NearClippingPlaneTolerance*range[1]) { range[0] = this->NearClippingPlaneTolerance*range[1]; } this->ActiveCamera->SetClippingRange( range ); } // Alternative version of ResetCameraClippingRange(bounds[6]); void vtkRenderer::ResetCameraClippingRange(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) { double bounds[6]; bounds[0] = xmin; bounds[1] = xmax; bounds[2] = ymin; bounds[3] = ymax; bounds[4] = zmin; bounds[5] = zmax; this->ResetCameraClippingRange(bounds); } // Specify the rendering window in which to draw. This is automatically set // when the renderer is created by MakeRenderer. The user probably // shouldn't ever need to call this method. // no reference counting! void vtkRenderer::SetRenderWindow(vtkRenderWindow *renwin) { vtkProp *aProp; if (renwin != this->RenderWindow) { // This renderer is be dis-associated with its previous render window. // this information needs to be passed to the renderer's actors and // volumes so they can release and render window specific (or graphics // context specific) information (such as display lists and texture ids) vtkCollectionSimpleIterator pit; this->Props->InitTraversal(pit); for ( aProp = this->Props->GetNextProp(pit); aProp != NULL; aProp = this->Props->GetNextProp(pit) ) { aProp->ReleaseGraphicsResources(this->RenderWindow); } // what about lights? // what about cullers? } this->VTKWindow = renwin; this->RenderWindow = renwin; } // Given a pixel location, return the Z value double vtkRenderer::GetZ (int x, int y) { float *zPtr; double z; zPtr = this->RenderWindow->GetZbufferData (x, y, x, y); if (zPtr) { z = *zPtr; delete [] zPtr; } else { z = 1.0; } return z; } // Convert view point coordinates to world coordinates. void vtkRenderer::ViewToWorld() { double result[4]; result[0] = this->ViewPoint[0]; result[1] = this->ViewPoint[1]; result[2] = this->ViewPoint[2]; result[3] = 1.0; this->ViewToWorld(result[0],result[1],result[2]); this->SetWorldPoint(result); } void vtkRenderer::ViewToWorld(double &x, double &y, double &z) { vtkMatrix4x4 *mat = vtkMatrix4x4::New(); double result[4]; // get the perspective transformation from the active camera mat->DeepCopy(this->ActiveCamera-> GetCompositePerspectiveTransformMatrix( this->GetTiledAspectRatio(),0,1)); // use the inverse matrix mat->Invert(); // Transform point to world coordinates result[0] = x; result[1] = y; result[2] = z; result[3] = 1.0; mat->MultiplyPoint(result,result); // Get the transformed vector & set WorldPoint // while we are at it try to keep w at one if (result[3]) { x = result[0] / result[3]; y = result[1] / result[3]; z = result[2] / result[3]; } mat->Delete(); } // Convert world point coordinates to view coordinates. void vtkRenderer::WorldToView() { double result[3]; result[0] = this->WorldPoint[0]; result[1] = this->WorldPoint[1]; result[2] = this->WorldPoint[2]; this->WorldToView(result[0], result[1], result[2]); this->SetViewPoint(result[0], result[1], result[2]); } // Convert world point coordinates to view coordinates. void vtkRenderer::WorldToView(double &x, double &y, double &z) { vtkMatrix4x4 *matrix = vtkMatrix4x4::New(); double view[4]; // get the perspective transformation from the active camera matrix->DeepCopy(this->ActiveCamera-> GetCompositePerspectiveTransformMatrix( this->GetTiledAspectRatio(),0,1)); view[0] = x*matrix->Element[0][0] + y*matrix->Element[0][1] + z*matrix->Element[0][2] + matrix->Element[0][3]; view[1] = x*matrix->Element[1][0] + y*matrix->Element[1][1] + z*matrix->Element[1][2] + matrix->Element[1][3]; view[2] = x*matrix->Element[2][0] + y*matrix->Element[2][1] + z*matrix->Element[2][2] + matrix->Element[2][3]; view[3] = x*matrix->Element[3][0] + y*matrix->Element[3][1] + z*matrix->Element[3][2] + matrix->Element[3][3]; if (view[3] != 0.0) { x = view[0]/view[3]; y = view[1]/view[3]; z = view[2]/view[3]; } matrix->Delete(); } void vtkRenderer::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Near Clipping Plane Tolerance: " << this->NearClippingPlaneTolerance << "\n"; os << indent << "Ambient: (" << this->Ambient[0] << ", " << this->Ambient[1] << ", " << this->Ambient[2] << ")\n"; os << indent << "Backing Store: " << (this->BackingStore ? "On\n":"Off\n"); os << indent << "Display Point: (" << this->DisplayPoint[0] << ", " << this->DisplayPoint[1] << ", " << this->DisplayPoint[2] << ")\n"; os << indent << "Lights:\n"; this->Lights->PrintSelf(os,indent.GetNextIndent()); os << indent << "Light Follow Camera: " << (this->LightFollowCamera ? "On\n" : "Off\n"); os << indent << "View Point: (" << this->ViewPoint[0] << ", " << this->ViewPoint[1] << ", " << this->ViewPoint[2] << ")\n"; os << indent << "Two Sided Lighting: " << (this->TwoSidedLighting ? "On\n" : "Off\n"); os << indent << "Automatic Light Creation: " << (this->AutomaticLightCreation ? "On\n" : "Off\n"); os << indent << "Layer = " << this->Layer << "\n"; os << indent << "Interactive = " << (this->Interactive ? "On" : "Off") << "\n"; os << indent << "Allocated Render Time: " << this->AllocatedRenderTime << "\n"; os << indent << "Last Time To Render (Seconds): " << this->LastRenderTimeInSeconds << endl; os << indent << "TimeFactor: " << this->TimeFactor << endl; os << indent << "Erase: " << (this->Erase ? "On\n" : "Off\n"); // I don't want to print this since it is used just internally // os << indent << this->NumberOfPropsRendered; } int vtkRenderer::VisibleActorCount() { vtkProp *aProp; int count = 0; // loop through Props vtkCollectionSimpleIterator pit; for (this->Props->InitTraversal(pit); (aProp = this->Props->GetNextProp(pit)); ) { if (aProp->GetVisibility()) { count++; } } return count; } int vtkRenderer::VisibleVolumeCount() { int count = 0; vtkProp *aProp; // loop through volumes vtkCollectionSimpleIterator pit; for (this->Props->InitTraversal(pit); (aProp = this->Props->GetNextProp(pit)); ) { if (aProp->GetVisibility()) { count++; } } return count; } unsigned long int vtkRenderer::GetMTime() { unsigned long mTime=this-> vtkViewport::GetMTime(); unsigned long time; if ( this->ActiveCamera != NULL ) { time = this->ActiveCamera ->GetMTime(); mTime = ( time > mTime ? time : mTime ); } if ( this->CreatedLight != NULL ) { time = this->CreatedLight ->GetMTime(); mTime = ( time > mTime ? time : mTime ); } return mTime; } vtkAssemblyPath* vtkRenderer::PickProp(double selectionX, double selectionY) { // initialize picking information this->CurrentPickId = 1; // start at 1, so 0 can be a no pick this->PickX = selectionX; this->PickY = selectionY; int numberPickFrom; vtkPropCollection *props; // Initialize the pick (we're picking a path, the path // includes info about nodes) if (this->PickFromProps) { props = this->PickFromProps; } else { props = this->Props; } // number determined from number of rendering passes plus reserved "0" slot numberPickFrom = 2*props->GetNumberOfPaths()*3 + 1; this->IsPicking = 1; // turn on picking this->StartPick(numberPickFrom); this->PathArray = new vtkAssemblyPath *[numberPickFrom]; this->PathArrayCount = 0; // Actually perform the pick this->PickRender(props); // do the pick render this->IsPicking = 0; // turn off picking this->DonePick(); vtkDebugMacro(<< "z value for pick " << this->GetPickedZ() << "\n"); vtkDebugMacro(<< "pick time " << this->LastRenderTimeInSeconds << "\n"); // Get the pick id of the object that was picked if ( this->PickedProp != NULL ) { this->PickedProp->UnRegister(this); this->PickedProp = NULL; } unsigned int pickedId = this->GetPickedId(); if ( pickedId != 0 ) { pickedId--; // pick ids start at 1, so move back one // wrap around, as there are twice as many pickid's as PropArrayCount, // because each Prop has both RenderOpaqueGeometry and // RenderTranslucentGeometry called on it pickedId = pickedId % this->PathArrayCount; this->PickedProp = this->PathArray[pickedId]; this->PickedProp->Register(this); } // Clean up stuff from picking after we use it delete [] this->PathArray; this->PathArray = NULL; // Return the pick! return this->PickedProp; //returns an assembly path } // Do a render in pick mode. This is normally done with rendering turned off. // Before each Prop is rendered the pick id is incremented void vtkRenderer::PickRender(vtkPropCollection *props) { vtkProp *aProp; vtkAssemblyPath *path; this->InvokeEvent(vtkCommand::StartEvent,NULL); if( props->GetNumberOfItems() <= 0) { return; } // Create a place to store all props that remain after culling vtkPropCollection* pickFrom = vtkPropCollection::New(); // Extract all the prop3D's out of the props collection. // This collection will be further culled by using a bounding box // pick later (vtkPicker). Things that are not vtkProp3D will get // put into the Paths list directly. vtkCollectionSimpleIterator pit; for ( props->InitTraversal(pit); (aProp = props->GetNextProp(pit)); ) { if ( aProp->GetPickable() && aProp->GetVisibility() ) { if ( aProp->IsA("vtkProp3D") ) { pickFrom->AddItem(aProp); } else //must be some other type of prop (e.g., vtkActor2D) { for ( aProp->InitPathTraversal(); (path=aProp->GetNextPath()); ) { this->PathArray[this->PathArrayCount++] = path; } } }//pickable & visible }//for all props // For a first pass at the pick process, just use a vtkPicker to // intersect with bounding boxes of the objects. This should greatly // reduce the number of polygons that the hardware has to pick from, and // speeds things up substantially. // // Create a picker to do the culling process vtkPicker* cullPicker = vtkPicker::New(); // Add each of the Actors from the pickFrom list into the picker for ( pickFrom->InitTraversal(pit); (aProp = pickFrom->GetNextProp(pit)); ) { cullPicker->AddPickList(aProp); } // make sure this selects from the pickers list and not the renderers list cullPicker->PickFromListOn(); // do the pick cullPicker->Pick(this->PickX, this->PickY, 0, this); vtkProp3DCollection* cullPicked = cullPicker->GetProp3Ds(); // Put all the ones that were picked by the cull process // into the PathArray to be picked from vtkCollectionSimpleIterator p3dit; for (cullPicked->InitTraversal(p3dit); (aProp = cullPicked->GetNextProp3D(p3dit));) { if ( aProp != NULL ) { for ( aProp->InitPathTraversal(); (path=aProp->GetNextPath()); ) { this->PathArray[this->PathArrayCount++] = path; } } } // Clean picking support objects up pickFrom->Delete(); cullPicker->Delete(); if ( this->PathArrayCount == 0 ) { vtkDebugMacro( << "There are no visible props!" ); return; } // do the render library specific pick render this->DevicePickRender(); } void vtkRenderer::PickGeometry() { int i; this->NumberOfPropsRendered = 0; if ( this->PathArrayCount == 0 ) { return ; } // We can render everything because if it was // not visible it would not have been put in the // list in the first place, and if it was allocated // no time (culled) it would have been removed from // the list // loop through props and give them a change to // render themselves as opaque geometry vtkProp *prop; vtkMatrix4x4 *matrix; for ( i = 0; i < this->PathArrayCount; i++ ) { this->UpdatePickId(); prop = this->PathArray[i]->GetLastNode()->GetViewProp(); matrix = this->PathArray[i]->GetLastNode()->GetMatrix(); prop->PokeMatrix(matrix); this->NumberOfPropsRendered += prop->RenderOpaqueGeometry(this); prop->PokeMatrix(NULL); } // loop through props and give them a chance to // render themselves as translucent geometry for ( i = 0; i < this->PathArrayCount; i++ ) { this->UpdatePickId(); prop = this->PathArray[i]->GetLastNode()->GetViewProp(); matrix = this->PathArray[i]->GetLastNode()->GetMatrix(); prop->PokeMatrix(matrix); this->NumberOfPropsRendered += prop->RenderTranslucentGeometry(this); prop->PokeMatrix(NULL); } for ( i = 0; i < this->PathArrayCount; i++ ) { this->UpdatePickId(); prop = this->PathArray[i]->GetLastNode()->GetViewProp(); matrix = this->PathArray[i]->GetLastNode()->GetMatrix(); prop->PokeMatrix(matrix); this->NumberOfPropsRendered += prop->RenderOverlay(this); prop->PokeMatrix(NULL); } vtkDebugMacro( << "Pick Rendered " << this->NumberOfPropsRendered << " actors" ); } int vtkRenderer::Transparent() { // If our layer is the 0th layer, then we are not transparent, else we are. return (this->Layer == 0 ? 0 : 1); } double vtkRenderer::GetTiledAspectRatio() { int usize, vsize; this->GetTiledSize(&usize,&vsize); // some renderer subclasses may have more complicated computations for the // aspect ratio. SO take that into account by computing the difference // between our simple aspect ratio and what the actual renderer is // reporting. double aspect[2]; this->ComputeAspect(); this->GetAspect(aspect); double aspect2[2]; this->vtkViewport::ComputeAspect(); this->vtkViewport::GetAspect(aspect2); double aspectModification = aspect[0]*aspect2[1]/(aspect[1]*aspect2[0]); double finalAspect = 1.0; if(vsize && usize) { finalAspect = aspectModification*usize/vsize; } return finalAspect; }