Here is a simple example about make vtkImageActor always face current active camera and keep it under a vtkFollower object.

It’s impossible to send image data to vtkFollower directly, so we have to add the feature that adjust orientation of image actor automatically when rendering. To keep the lower status, we need to move it further from camera.

#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 <vtkTextSource.h>
#include <vtkAxesActor.h>
#include <vtkImageActor.h>
#include <vtkPNGReader.h>
#include <vtkTransform.h>
#include <vtkFollower.h>
#include <vtkImageMapper.h>
#include <vtkBillboardTextActor3D.h>
#include "point.hpp"
#include <vtkJPEGReader.h>
#include <vtkImageSlice.h>
#include <vtkImageMapper3D.h>
#include <vtkCamera.h>

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

using namespace std;

class ImgFollower: public vtkImageActor
{
public:
    vtkTypeMacro(ImgFollower,vtkImageActor);
    static ImgFollower *New();
    vtkSetMacro( Camera, vtkSmartPointer<vtkCamera> );
    virtual void Render(vtkRenderer *ren)
    {
        vtkImageActor::Render( ren );

        this->ComputeMatrix();
    }

    virtual void ComputeMatrix()
    {
      // check whether or not need to rebuild the matrix
      if ( this->GetMTime() > this->MatrixMTime ||
           (this->Camera && this->Camera->GetMTime() > this->MatrixMTime) )
      {
        this->GetOrientation();
        this->Transform->Push();
        this->Transform->Identity();
        this->Transform->PostMultiply();

        this->Transform->Translate(-this->Origin[0],
                                   -this->Origin[1],
                                   -this->Origin[2]);
        // scale
        this->Transform->Scale(this->Scale[0],
                               this->Scale[1],
                               this->Scale[2]);

        // rotate
        this->Transform->RotateY(this->Orientation[1]);
        this->Transform->RotateX(this->Orientation[0]);
        this->Transform->RotateZ(this->Orientation[2]);

        if (this->Camera)
        {
          double *pos, *vup, distance;
          double Rx[3], Ry[3], Rz[3];

          vtkSmartPointer<vtkMatrix4x4> matrix = vtkSmartPointer<vtkMatrix4x4>::New();

          // do the rotation
          // first rotate y
          pos = this->Camera->GetPosition();
          vup = this->Camera->GetViewUp();
          Point focalPt( this->Camera->GetFocalPoint() );
          Point viewDir;
          vtkMath::Subtract( focalPt.point, pos, viewDir.point );
          viewDir.Unit();

          if (this->Camera->GetParallelProjection())
          {
            this->Camera->GetDirectionOfProjection(Rz);
            Rz[0] = -Rz[0];
            Rz[1] = -Rz[1];
            Rz[2] = -Rz[2];
          }
          else
          {
            distance = sqrt(
              (pos[0] - this->Position[0])*(pos[0] - this->Position[0]) +
              (pos[1] - this->Position[1])*(pos[1] - this->Position[1]) +
              (pos[2] - this->Position[2])*(pos[2] - this->Position[2]));
            for (int i = 0; i < 3; i++)
            {
              Rz[i] = (pos[i] - this->Position[i])/distance;
            }
          }

          // We cannot directly use the vup angle since it can be aligned with Rz:
          //vtkMath::Cross(vup,Rz,Rx);
          //vtkMath::Normalize(Rx);
          //vtkMath::Cross(Rz,Rx,Ry);

          //instead use the view right angle:
          double dop[3], vur[3];
          this->Camera->GetDirectionOfProjection(dop);

          vtkMath::Cross(dop,vup,vur);
          vtkMath::Normalize(vur);

          vtkMath::Cross(Rz, vur, Ry);
          vtkMath::Normalize(Ry);
          vtkMath::Cross(Ry,Rz,Rx);

          matrix->Element[0][0] = Rx[0];
          matrix->Element[1][0] = Rx[1];
          matrix->Element[2][0] = Rx[2];
          matrix->Element[0][1] = Ry[0];
          matrix->Element[1][1] = Ry[1];
          matrix->Element[2][1] = Ry[2];
          matrix->Element[0][2] = Rz[0];
          matrix->Element[1][2] = Rz[1];
          matrix->Element[2][2] = Rz[2];

          this->Transform->Concatenate(matrix);

          // move the image follower to lower postion for other actor can be above it.
          this->Transform->Translate( viewDir.point );
        }

        // translate to projection reference point PRP
        // this is the camera's position blasted through
        // the current matrix
        this->Transform->Translate(this->Origin[0] + this->Position[0],
                                   this->Origin[1] + this->Position[1],
                                   this->Origin[2] + this->Position[2]);

        // apply user defined transform last if there is one
        if (this->UserTransform)
        {
          this->Transform->Concatenate(this->UserTransform->GetMatrix());
        }

        this->Transform->PreMultiply();
        this->Transform->GetMatrix(this->Matrix);
        this->MatrixMTime.Modified();
        this->Transform->Pop();
      }
    }
protected:
    vtkSmartPointer<vtkCamera> Camera;
};

vtkStandardNewMacro(ImgFollower);

int main()
{
    vtkSPtrNew( reader, vtkPNGReader );
    reader->SetFileName( "screenshot.png" );
    reader->Update();

    vtkSPtrNew( imgActor, ImgFollower );
    imgActor->SetInputData( reader->GetOutput() );
    //imgActor->SetPosition( 0, 0, 0 ); // if we want to keep their relative status unchanged, position need to be same

    vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
    axes->AxisLabelsOff();
    axes->SetTotalLength( 3, 3, 3 );

    vtkSmartPointer<vtkTextSource> text = vtkSmartPointer<vtkTextSource>::New();
    text->SetText( "12.4" );
    text->SetBacking(false);
    text->Update();

    vtkSPtrNew( mapper, vtkPolyDataMapper );
    mapper->SetInputConnection( text->GetOutputPort() );

    vtkSPtrNew( follower, vtkFollower );
    follower->SetMapper( mapper );

    vtkSPtrNew( renderer, vtkRenderer );
    renderer->AddActor( axes );
    imgActor->SetCamera( renderer->GetActiveCamera() );
    follower->SetCamera( renderer->GetActiveCamera() );
    renderer->AddActor( imgActor );
    renderer->AddActor( follower );
    renderer->SetBackground( 0, 0, 0 );

    vtkSPtrNew( renderWindow, vtkRenderWindow );
    renderWindow->AddRenderer( renderer );

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

    renderer->ResetCamera();

    renderer->ResetCamera();
    renderWindow->Render();
    renderWindowInteractor->Start();
    return 0;
}

Result:

The file point.hpp can be found at https://www.weiy.city/2020/09/project-point-on-line-and-plane-by-special-direction/.

Categories: VTK

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments

Tex To PDF
: convert the Latex file which suffix is tex to a PDF file

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