I create two renderers that show the same 3D model. Make the camera in the right renderer linkage with the left one’s, that means we can get the same view in the right renderer when we modify the status of the camera of the left renderer.
Here is all information of implementations.

main.cpp

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkOBJReader.h>
#include <vtkCamera.h>

#include "CustomIteractorStyle.h"

using namespace std;

int main()
{
    const string filePath = "/Users/weiyang/Desktop/8.obj";

    vtkSPtrNew( reader, vtkOBJReader );
    reader->SetFileName( filePath.c_str() );
    reader->Update();

    vtkSPtrNew( mapper1, vtkPolyDataMapper );
    mapper1->SetInputConnection( reader->GetOutputPort() );

    vtkSPtrNew( actor1, vtkActor );
    actor1->SetMapper( mapper1 );

    vtkSPtrNew( mapper2, vtkPolyDataMapper );
    mapper2->SetInputConnection( reader->GetOutputPort() );

    vtkSPtrNew( actor2, vtkActor );
    actor2->SetMapper( mapper2 );

    // Define viewport ranges
    // (xmin, ymin, xmax, ymax) left-top and right-bottom point
    double leftViewport[4] = {0.0, 0.0, 0.5, 1.0};
    double rightViewport[4] = {0.5, 0.0, 1.0, 1.0};
    // Setup renderers
    vtkSmartPointer<vtkRenderer> leftRenderer =
        vtkSmartPointer<vtkRenderer>::New();
    leftRenderer->SetViewport( leftViewport );
    leftRenderer->SetBackground( .6, .5, .4 );
    leftRenderer->AddActor( actor1 );
    leftRenderer->ResetCamera();
    leftRenderer->GetActiveCamera()->ParallelProjectionOn();

    vtkSmartPointer<vtkRenderer> rightRenderer =
        vtkSmartPointer<vtkRenderer>::New();
    rightRenderer->SetViewport( rightViewport );
    rightRenderer->SetBackground( .4, .5, .6);
    rightRenderer->AddActor( actor2 );
    rightRenderer->ResetCamera();
    rightRenderer->GetActiveCamera()->ParallelProjectionOn();

    vtkSPtrNew( renderWindow, vtkRenderWindow );
    renderWindow->AddRenderer( leftRenderer );
    renderWindow->AddRenderer( rightRenderer );

    vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
    renderWindowInteractor->SetRenderWindow( renderWindow );

    vtkSPtrNew( iStyle, CustomIteractorStyle );
    iStyle->Setm_LeftRender( leftRenderer );
    iStyle->Setm_RightRender( rightRenderer );
    iStyle->Init();

    renderWindowInteractor->SetInteractorStyle( iStyle );
    renderWindow->Render();
    renderWindowInteractor->Start();
    return 0;
}

CustomIteractorStyle.h:

#pragma once

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkTransform.h>

#include "point.hpp"

#define CPP_SET_MACRO(name,type) \
  void Set##name(type _arg) \
  { \
    if (this->name != _arg) \
    { \
    this->name = _arg; \
    } \
  }

#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();

class CustomIteractorStyle: public vtkInteractorStyleTrackballCamera
{
public:
    static CustomIteractorStyle *New(){ return new CustomIteractorStyle(); }
    void OnMouseWheelForward() override;
    void OnMouseWheelBackward() override;
    void Rotate() override;
    void Pan() override;

    void Init();

    CPP_SET_MACRO( m_LeftRender, vtkSmartPointer<vtkRenderer> );
    CPP_SET_MACRO( m_RightRender, vtkSmartPointer<vtkRenderer> );
protected:
    CustomIteractorStyle();
    ~CustomIteractorStyle() override;
    void KeepSameCameraStatus();

    vtkSmartPointer<vtkRenderer> m_LeftRender;
    vtkSmartPointer<vtkRenderer> m_RightRender;
    Point m_LastVTKCameraFocal;
};

CustomIteractorStyle.cpp:

#include "CustomIteractorStyle.h"
#include "point.hpp"

#include <vtkCamera.h>

void CustomIteractorStyle::OnMouseWheelForward()
{
    vtkInteractorStyleTrackballCamera::OnMouseWheelForward();
    KeepSameCameraStatus();
}

void CustomIteractorStyle::OnMouseWheelBackward()
{
    vtkInteractorStyleTrackballCamera::OnMouseWheelBackward();
    KeepSameCameraStatus();
}

void CustomIteractorStyle::Rotate()
{
    vtkInteractorStyleTrackballCamera::Rotate();
    KeepSameCameraStatus();
}

void CustomIteractorStyle::Pan()
{
    vtkInteractorStyleTrackballCamera::Pan();
    KeepSameCameraStatus();
}

void CustomIteractorStyle::Init()
{
    m_LastVTKCameraFocal = Point( m_LeftRender->GetActiveCamera()->GetFocalPoint() );
}

CustomIteractorStyle::CustomIteractorStyle()
{
}

CustomIteractorStyle::~CustomIteractorStyle()
{
}

void CustomIteractorStyle::KeepSameCameraStatus()
{
    vtkCamera *targetCamera = m_RightRender->GetActiveCamera();
    vtkCamera *sampleCamera = m_LeftRender->GetActiveCamera();

    Point sampleFocal, sampleCameraPos, sampleViewUp;
    sampleCamera->GetFocalPoint( sampleFocal.point );
    sampleCamera->GetPosition( sampleCameraPos.point );
    sampleCamera->GetViewUp( sampleViewUp.point );
    double parallelValue = sampleCamera->GetParallelScale();
    Point focalToPos = sampleCameraPos - sampleFocal;
    focalToPos.Unit();
    Point moveVec = sampleFocal - m_LastVTKCameraFocal;

    Point targetFocal, targetCameraPos;
    targetCamera->GetFocalPoint( targetFocal.point );
    targetCamera->GetPosition( targetCameraPos.point );
    double dis = (targetFocal - targetCameraPos).Length();
    Point newFocal = moveVec + targetFocal;
    targetCamera->SetFocalPoint( newFocal.point );
    Point newPos = newFocal + focalToPos * dis;
    targetCamera->SetPosition( newPos.point );
    targetCamera->SetViewUp( sampleViewUp.point );
    targetCamera->SetParallelScale( parallelValue );

    m_LastVTKCameraFocal = sampleFocal;
 );
}

But I can’t see the whole body of the right one after rotating the left 3D model.

rotate1

Let’s set the same clipping range with the left camera.

void CustomIteractorStyle::KeepSameCameraStatus()
{
//...
    double *sClippingRange = sampleCamera->GetClippingRange();
    targetCamera->SetClippingRange( sClippingRange[0], sClippingRange[1]

It seems correct after configure the clipping range.

rotate2

The OBJ file I used in my project can be created on the page: create 3d text

The relevant interfaces in VTK:

// 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);
}

// 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->GetActiveCameraAndResetIfCreated();
  if (this->ActiveCamera == nullptr)
  {
    vtkErrorMacro(<< "Trying to reset clipping range of non-existent camera");
    return;
  }

  if (!this->ActiveCamera->GetUseOffAxisProjection())
  {
    this->ActiveCamera->GetViewPlaneNormal(vn);
    this->ActiveCamera->GetPosition(position);
    this->ExpandBounds(bounds, this->ActiveCamera->GetModelTransformMatrix());
  }
  else
  {
    this->ActiveCamera->GetEyePosition(position);
    this->ActiveCamera->GetEyePlaneNormal(vn);
    this->ExpandBounds(bounds, this->ActiveCamera->GetModelViewTransformMatrix());
  }

  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] = (dist < range[0]) ? (dist) : (range[0]);
        range[1] = (dist > range[1]) ? (dist) : (range[1]);
      }
    }
  }

  // do not let far - near be less than 0.1 of the window height
  // this is for cases such as 2D images which may have zero range
  double minGap = 0.0;
  if (this->ActiveCamera->GetParallelProjection())
  {
    minGap = 0.1 * this->ActiveCamera->GetParallelScale();
  }
  else
  {
    double angle = vtkMath::RadiansFromDegrees(this->ActiveCamera->GetViewAngle());
    minGap = 0.2 * tan(angle / 2.0) * range[1];
  }
  if (range[1] - range[0] < minGap)
  {
    minGap = minGap - range[1] + range[0];
    range[1] += minGap / 2.0;
    range[0] -= minGap / 2.0;
  }

  // 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]) * this->ClippingRangeExpansion;
  range[1] = 1.01 * range[1] + (range[1] - range[0]) * this->ClippingRangeExpansion;

  // 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);
}
Categories: VTK

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

3D Model Viewer: add grid plane and convex hull.
Add google translate tool at right-bottom position.

X
A prohibited operation
0
Would love your thoughts, please comment.x
()
x