スポンサーリンク

VTKで現在設定中のカスタムシェーダを表示する

カスタムシェーダを使おうとして動かないときに、生成されたシェーダを確認したいことがある。

MapperのObserverを追加してコンパイルされるシェーダのソースコードを表示できる。

なおエラーがある場合はどのみちエラー出力で表示されるのでここまでしなくていい。

#include <iostream>

//VTK_MODULE_INITに必要
#include <vtkAutoInit.h>


#include <vtkSmartPointer.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>

//円筒とその表示に必要
#include <vtkCylinderSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkPointData.h>


// シェーダ関係のinclude
#include <vtkShaderProgram.h> 
#include <vtkShaderProperty.h>
#include <vtkOpenGLPolyDataMapper.h>

////////////////////////////////

#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"psapi.lib")
#pragma comment(lib,"dbghelp.lib")
#pragma comment(lib,"ws2_32.lib")


//必須
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);



// データに色情報を追加
void SetColor(vtkSmartPointer<vtkPolyData> data, const char* scalarname, std::array<unsigned char, 3> rgb) {

  size_t PointNum = data->GetNumberOfPoints();

  vtkSmartPointer<vtkUnsignedCharArray> colorsNew = vtkSmartPointer<vtkUnsignedCharArray>::New();
  colorsNew->SetNumberOfComponents(3);
  colorsNew->SetName(scalarname);
  for (int i = 0; i < PointNum; i++) {

    // ランダムな色を作成
    double r = vtkMath::Random(0.0, 255.0);
    double g = vtkMath::Random(0.0, 255.0);
    double b = vtkMath::Random(0.0, 255.0);

    colorsNew->InsertNextTuple3(r,g,b);
  }
  data->GetPointData()->AddArray(colorsNew);

}

void setShader(vtkSmartPointer<vtkActor> actor) {
  auto shaderProperty = actor->GetShaderProperty();

  shaderProperty->AddVertexShaderReplacement(
    "//VTK::Color::Impl",
    true,
    R"(
//VTK::Color::Impl

// 頂点カラーから赤を除去
vertexColorVSOutput = vec4(
  0.0,
  vertexColorVSOutput.g,
  vertexColorVSOutput.b,
  1.0
);
  )",
    false);

}

class MyShaderCallback : public vtkCommand
{
public:
  static MyShaderCallback* New()
  {
    return new MyShaderCallback;
  }

  void Execute(vtkObject* caller, unsigned long eventId, void* callData) override
  {
    if (eventId == vtkCommand::UpdateShaderEvent && callData)
    {
      auto* program = static_cast<vtkShaderProgram*>(callData);
      if (!program)
      {
        return;
      }

      // 頂点シェーダとフラグメントシェーダのソースコードを取得
      const std::string& vertSrc = program->GetVertexShader()->GetSource();
      const std::string& fragSrc = program->GetFragmentShader()->GetSource();

      std::cout << "=== Vertex Shader (頂点シェーダ)===" << std::endl;
      std::cout << "=== " << std::endl;
      std::cout << "=== " << std::endl << std::endl;
      std::cout << vertSrc << std::endl;
      std::cout << "///////////////////////////////////////////////" << std::endl;
      std::cout << "///////////////////////////////////////////////" << std::endl;
      std::cout << "///////////////////////////////////////////////" << std::endl;
      std::cout << "///////////////////////////////////////////////" << std::endl;
      std::cout << "=== Fragment Shader (フラグメントシェーダ)===" << std::endl;
      std::cout << "=== " << std::endl;
      std::cout << "=== " << std::endl << std::endl;
      std::cout << fragSrc << std::endl;
    }
  }
};
int main(int /*argc*/, char** /*argv*/)
{
  // シリンダー作成
  vtkSmartPointer<vtkCylinderSource> cylinder = vtkSmartPointer<vtkCylinderSource>::New();
  cylinder->SetResolution(50);
  cylinder->SetHeight(3.0);
  cylinder->SetRadius(1.0);
  cylinder->Update();
  // actorを作成
  vtkSmartPointer<vtkPolyData> points = cylinder->GetOutput();

  SetColor(points, "ColorsRed", { 255,0,0 });
  SetColor(points, "ColorsBlue", { 0,0,255 });

  // actorを作成
  vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputData(points);
  vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
  actor->SetMapper(mapper);

  //////////////////////////////////////
  // 使用する色をAddArrayで指定したスカラー値を使用するように設定
  mapper->SetScalarVisibility(1);                     // スカラー値を使用して色をつける設定
  mapper->SetScalarModeToUsePointFieldData();         // スカラー値はポイントデータに設定されているものを使用
  mapper->SetColorModeToDefault();                    // カラーモードをデフォルトに設定

  // 色の切り替えも有効
  mapper->SelectColorArray("ColorsBlue");
  mapper->Modified();// マッパーを更新
  //////////////////////////////////////


  // カスタムシェーダを設定
  setShader(actor);

  mapper->Modified();// マッパーを更新

  vtkOpenGLPolyDataMapper* glMapper = vtkOpenGLPolyDataMapper::SafeDownCast(mapper);
  if (!glMapper)
  {
    std::cout << "Shader is not OpenGL based." << std::endl;
  }
  else {
    // シェーダの更新イベントを監視
    vtkNew<MyShaderCallback> callback;
    glMapper->AddObserver(vtkCommand::UpdateShaderEvent, callback);
  }


  //////////////////////////////////////
  auto renderer = vtkSmartPointer<vtkRenderer>::New();
  renderer->AddActor(actor);
  renderer->ResetCamera();

  //////////////////////////////////////
  auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();

  //////////////////////////////////////
  auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->AddRenderer(renderer);
  renderWindow->SetInteractor(interactor);
  renderWindow->Render();


  interactor->Start(); //イベントループへ入る

  return 0;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: