#include <iostream> //VTK_MODULE_INITに必要 #include <vtkAutoInit.h> #include <vtkSmartPointer.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> //円筒とその表示に必要 #include <vtkPointData.h> #include <vtkCellData.h> #include <vtkPolyData.h> #include <vtkActor.h> #include <vtkPolyDataMapper.h> #include <vtkLookupTable.h> #include <vtkFloatArray.h> #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"psapi.lib") #pragma comment(lib,"dbghelp.lib") #pragma comment(lib,"ws2_32.lib") #include <vtkCellArray.h> #include <vtkTriangle.h> //必須 VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle);
//! @brief サーモグラフィー風のカラールックアップテーブルを生成する //! @param [in] scalar_min スカラー値の最小値 //! @param [in] scalar_max スカラー値の最大値 //! @param [in] division スカラー値の範囲を何分割するか //! @return カラールックアップテーブル vtkSmartPointer<vtkLookupTable> ThermographyColorTable(const double scalar_min, const double scalar_max, const int division) { vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New(); lut->SetNumberOfTableValues(division); // テーブルの要素数を設定 lut->SetTableRange(scalar_min, scalar_max); // スカラー値の範囲を設定 lut->Build(); // テーブルの i 番目の要素に対応する色を設定 for (int i = 0; i < division; i++) { double t = static_cast<double>(i) / float(division - 1); double r, g, b; if (t < 0.33) { // 青から緑への補間 double factor = t / 0.33; r = 0.0; g = factor; b = 1.0 - factor; } else if (t < 0.66) { // 緑から黄への補間 double factor = (t - 0.33) / 0.33; r = factor; g = 1.0; b = 0.0; } else { // 黄から赤への補間 double factor = (t - 0.66) / 0.34; r = 1.0; g = 1.0 - factor; b = 0.0; } // テーブルの i 番目の要素に色を設定 lut->SetTableValue( i // テーブルの要素番号 ,r,g,b,1.0 ); } return lut; }
int main(int, char* []) { ///////////////////////////// // 三頂点を定義 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); points->InsertNextPoint(0.0, 0.0, 0.0); points->InsertNextPoint(1.0, 0.0, 0.0); points->InsertNextPoint(0.0, 1.0, 0.0); // 三角形を定義 vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New(); vtkIdType pts[3] = { 0, 1, 2 }; triangles->InsertNextCell(3, pts); // ポリゴンデータを作成 vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New(); polyData->SetPoints(points); polyData->SetPolys(triangles); ///////////////////////////// // 各頂点にスカラー値を設定 vtkSmartPointer<vtkFloatArray> scalars = vtkSmartPointer<vtkFloatArray>::New(); scalars->SetName("MyScalarValues"); scalars->InsertNextValue(0.0); // 頂点0 に 0.0 を設定 scalars->InsertNextValue(50.0); // 頂点1 に 50.0 を設定 scalars->InsertNextValue(100.0); // 頂点2 に 100.0 を設定 polyData->GetPointData()->SetScalars(scalars); vtkSmartPointer<vtkFloatArray> scalars2 = vtkSmartPointer<vtkFloatArray>::New(); scalars2->SetName("MyScalarValues2"); scalars2->InsertNextValue(0.0); // 頂点0 に 0.0 を設定 scalars2->InsertNextValue(90.0); // 頂点1 に 50.0 を設定 scalars2->InsertNextValue(0.0); // 頂点2 に 100.0 を設定 polyData->GetPointData()->AddArray(scalars2); polyData->GetPointData()->SetActiveScalars("MyScalarValues"); ///////////////////////////// // ルックアップテーブルの設定 // scalar_min から scalar_max までのスカラー値を 100 段階に分け、それぞれの範囲に対応する色を設定 float scalar_min = 0.0; float scalar_max = 100.0; // スカラー値の最小値と最大値 int division = 200; // スカラー値の範囲を何分割するか vtkSmartPointer<vtkLookupTable> thermocolor = ThermographyColorTable(scalar_min, scalar_max,division); ///////////////////////////// // マッパーとアクターの設定 vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputData(polyData); mapper->SetLookupTable(thermocolor); mapper->SetScalarRange(scalar_min, scalar_max); // スカラー値の補間を先に行い、その後ルックアップテーブルで色を決定 mapper->SetInterpolateScalarsBeforeMapping(true); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); ///////////////////////////// // レンダラー等の設定 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddActor(actor); renderer->SetBackground(0.1, 0.1, 0.1); vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); renderWindow->SetSize(800, 600); vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); interactor->SetRenderWindow(renderWindow); renderWindow->Render(); interactor->Start(); return EXIT_SUCCESS; }
どうやらカスタムシェーダでピクセル色だけを書き換えるのは無理らしい。
試しに以下のようにVTK::Color::Implを置き換えてみる。
void setShader(vtkSmartPointer<vtkActor> actor) { auto shaderProperty = actor->GetShaderProperty(); shaderProperty->AddFragmentShaderReplacement( "//VTK::Color::Impl", // 挿入ポイント true, // 置き換えモード (true で完全に置き換え R"(
//VTK::Color::Impl // ここが VTK::Color::Impl
)" "", false ); }
この結果は以下のように、vertexColorVSOutputの下に挿入される。vertexColorVSOutputは書き換えられないし、ADSを算出するコードを置き換えることもできない
vertexColorVSOutput.rgbを使用するambientColorとdiffuseColorを再計算して上書きする。
void setShader(vtkSmartPointer<vtkActor> actor) { auto shaderProperty = actor->GetShaderProperty(); shaderProperty->AddFragmentShaderReplacement( "//VTK::Color::Impl", // 挿入ポイント true, // 置き換えモード (true で完全に置き換える) R"(
//VTK::Color::Impl // フラグメントシェーダに入ってきた色を編集して表示色を上書き vec3 MyRGB=vertexColorVSOutput.rgb; MyRGB = (MyRGB.b < 0.3)?vec3(1,1,1):MyRGB; ambientColor = ambientIntensity * MyRGB; diffuseColor = diffuseIntensity * MyRGB;
)" "", // カスタムシェーダコード false // 再帰的ではない置き換え ); }
カスタム頂点シェーダでSelectColorArrayで指定した色を編集する。フラグメントシェーダ側での編集はやや難しいので次回。
SelectColorArrayで選択した色情報は、頂点シェーダ側ではvertexColorVSOutput に格納されている。コードはこの色から赤を0に設定している。頂点シェーダの実装以外はデフォルトのものを使う。
#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> // shader #include <vtkShaderProperty.h> #include <vtkOpenGLPolyDataMapper.h> #include <vtkUniforms.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); }
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();// マッパーを更新 ////////////////////////////////////// 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; }
カスタムシェーダを使おうとして動かないときに、生成されたシェーダを確認したいことがある。
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; }
#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> // shader #include <vtkShaderProperty.h> #include <vtkOpenGLPolyDataMapper.h> #include <vtkUniforms.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 setShader(vtkSmartPointer<vtkActor> actor) { // カスタムシェーダを設定 vtkShaderProperty* shaderProperty = actor->GetShaderProperty(); // フラグメントシェーダの宣言部分 shaderProperty->AddFragmentShaderReplacement( "//VTK::Light::Dec", // 挿入位置 true, "//VTK::Light::Dec\n" "uniform vec3 customColor;\n", // ユニフォーム変数を定義 false ); // フラグメントシェーダの実装部分 shaderProperty->AddFragmentShaderReplacement( "//VTK::Light::Impl", // 挿入位置 true, "//VTK::Light::Impl\n" " fragOutput0 = vec4(customColor, 1.0);\n", // 出力変数(オブジェクト色) false ); // ユニフォーム変数を設定 double customColor[3] = { 1.0, 0.5, 0.0 }; shaderProperty->GetVertexCustomUniforms()->SetUniform3f("customColor", customColor); }
int main(int /*argc*/, char** /*argv*/) { ////////////////////////////////////// // Create a vtkCylinderSource vtkSmartPointer<vtkCylinderSource> cylinderSource = vtkSmartPointer<vtkCylinderSource>::New(); cylinderSource->SetCenter(0.0, 0.0, 0.0); cylinderSource->SetRadius(5.0); cylinderSource->SetHeight(7.0); cylinderSource->SetResolution(100); ////////////////////////////////////// // Create a mapper and actor vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputConnection(cylinderSource->GetOutputPort()); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); // カスタムシェーダを設定 setShader(actor); ////////////////////////////////////// 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; }'
VTKでデータを管理しているときに、色用のスカラー値を複数作成している場合、SetArrayNameでスカラー値名を指定して、その色で保存できる。
VTKで一つのオブジェクトに頂点色情報を二つ以上与えて切り替えて表示
// #include <vtkPLYWriter.h> が必要 // filename : 出力ファイル名 // colorname : 使用する色情報のスカラー値名 void SavePolyData(vtkSmartPointer<vtkPolyData> data,const char* filename,const char* colorname) {
vtkSmartPointer<vtkPLYWriter> writer = vtkSmartPointer<vtkPLYWriter>::New(); writer->SetFileName(filename); writer->SetColorModeToDefault(); writer->SetArrayName(colorname); // 使用する色情報をスカラー値名で指定 writer->SetInputData(data); writer->SetFileTypeToBinary(); writer->Write(); }
頂点に何らかの重みを割り当て、サーモグラフィー的に表示したい。三角形一枚の色はデフォルトでは各頂点の線形補間になってしまうので、フラグメントシェーダで重みを色に変換する関数を通して着色する。なおこのコードは以前作ったRust+OpenGLで三角形を表示するコードのdraw.rsを書き換えている。
use std::ptr::null; use std::ffi::CString; use std::ffi::CStr;
pub fn draw_prepare() ->(gl::types::GLuint, gl::types::GLuint){ // 頂点の定義 let vertices: [f32;9]=[ 0.0, 0.5, 0.0, // 上頂点 -0.5, -0.5, 0.0, // 左下 0.5, -0.5, 0.0, // 右下 ]; // スカラー値 let scalar:[f32;3]=[ 1.0, 0.3, 0.0, ]; let mut vertexbuffer=0; unsafe{ gl::GenBuffers(1,&mut vertexbuffer); gl::BindBuffer(gl::ARRAY_BUFFER,vertexbuffer); gl::BufferData( gl::ARRAY_BUFFER, 3*3*std::mem::size_of::<gl::types::GLfloat>() as gl::types::GLsizeiptr, vertices.as_ptr() as *const _, gl::STATIC_DRAW ); } let mut scalarbuffer=0; unsafe{ gl::GenBuffers(1,&mut scalarbuffer); gl::BindBuffer(gl::ARRAY_BUFFER,scalarbuffer); gl::BufferData( gl::ARRAY_BUFFER, 3*std::mem::size_of::<gl::types::GLfloat>() as gl::types::GLsizeiptr, scalar.as_ptr() as *const _, gl::STATIC_DRAW ); } (vertexbuffer,scalarbuffer) }
pub fn prepare_vertex_shader()->gl::types::GLuint{ let mut VertexShaderID = 0; // 頂点シェーダプログラム let vertex_shader_source = "\ #version 460 core layout (location = 0) in vec3 aPos;
// layout (location = 1) in vec3 incolor; layout (location = 1) in float scalar; // out vec4 vertexColor; out float fragscalar; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(aPos, 1.0);
// vertexColor = vec4(incolor, 1.0); fragscalar = scalar; } "; let c_src = CString::new(vertex_shader_source).unwrap(); let mut Result:gl::types::GLint = 0; let mut InfoLogLength:i32 = 0; let mut info_log; unsafe{ VertexShaderID = gl::CreateShader(gl::VERTEX_SHADER); gl::ShaderSource( VertexShaderID, 1, &c_src.as_ptr(), std::ptr::null() ); gl::CompileShader(VertexShaderID); // シェーダのチェック gl::GetShaderiv(VertexShaderID,gl::COMPILE_STATUS,&mut Result); gl::GetShaderiv(VertexShaderID,gl::INFO_LOG_LENGTH,&mut InfoLogLength); if InfoLogLength > 0 { info_log = vec![0u8; InfoLogLength as usize]; if Result == gl::FALSE as i32 { gl::GetShaderInfoLog( VertexShaderID, InfoLogLength, std::ptr::null_mut(), info_log.as_mut_ptr() as *mut gl::types::GLchar ); if let Ok(msg) = CStr::from_ptr(info_log.as_ptr() as *const i8).to_str() { println!("Vertex Shader Error :\n {}\n", msg); } } } } VertexShaderID }
pub fn prepare_fragment_shader()->gl::types::GLuint{ let mut FragmentShaderID=0; let fragment_shader_source = "\ #version 460 core out vec4 FragColor; // in vec4 vertexColor; in float fragscalar; // スカラーをサーモグラフィーのRGBに変換 vec3 scalarToThermalColor(float scalar) { // 0.0〜1.0の範囲に制限 scalar = clamp(scalar, 0.0, 1.0); // サーモグラフィーカラーの計算 vec3 color; if (scalar < 0.25) { color = vec3(0.0, 4.0 * scalar, 1.0); // 青 → シアン } else if (scalar < 0.5) { color = vec3(0.0, 1.0, 1.0 - 4.0 * (scalar - 0.25)); // シアン → 緑 } else if (scalar < 0.75) { color = vec3(4.0 * (scalar - 0.5), 1.0, 0.0); // 緑 → 黄 } else { color = vec3(1.0, 1.0 - 4.0 * (scalar - 0.75), 0.0); // 黄 → 赤 } return color; } void main() { // FragColor = vertexColor; FragColor = vec4(scalarToThermalColor(fragscalar), 1.0); // 出力 } "; let c_str = CString::new(fragment_shader_source).unwrap(); let mut Result:gl::types::GLint=0; let mut InfoLogLength:i32=0; let mut info_log; unsafe { FragmentShaderID = gl::CreateShader(gl::FRAGMENT_SHADER); gl::ShaderSource( FragmentShaderID, 1, &c_str.as_ptr(), null() ); gl::CompileShader(FragmentShaderID); // フラグメントシェーダ gl::GetShaderiv(FragmentShaderID, gl::COMPILE_STATUS, &mut Result); gl::GetShaderiv(FragmentShaderID, gl::INFO_LOG_LENGTH, &mut InfoLogLength); if InfoLogLength > 0 { if Result == gl::FALSE as i32 { info_log = vec![0u8; InfoLogLength as usize]; gl::GetShaderInfoLog( FragmentShaderID, InfoLogLength, std::ptr::null_mut(), info_log.as_mut_ptr() as *mut gl::types::GLchar ); if let Ok(msg) = CStr::from_ptr(info_log.as_ptr() as *const i8).to_str() { println!("Fragment Shader Error :\n{}\n", msg); } } } } FragmentShaderID }
pub fn link_program(VertexShaderID:gl::types::GLuint,FragmentShaderID:gl::types::GLuint)->gl::types::GLuint{ let mut Result:gl::types::GLint = gl::FALSE as i32; let mut InfoLogLength:i32=0; let mut ProgramID:gl::types::GLuint=0; println!("Linking program"); unsafe{ ProgramID = gl::CreateProgram(); gl::AttachShader(ProgramID,VertexShaderID); gl::AttachShader(ProgramID,FragmentShaderID); gl::LinkProgram(ProgramID); gl::GetProgramiv(ProgramID,gl::LINK_STATUS,&mut Result); gl::GetProgramiv(ProgramID,gl::INFO_LOG_LENGTH,&mut InfoLogLength); if InfoLogLength > 0 { let mut ProgramErrorMessage = vec![0u8; InfoLogLength as usize]; gl::GetProgramInfoLog( ProgramID, InfoLogLength, std::ptr::null_mut(), ProgramErrorMessage.as_mut_ptr() as *mut gl::types::GLchar ); if let Ok(msg) = CStr::from_ptr(ProgramErrorMessage.as_ptr() as *const i8).to_str() { println!("Program Link Error:\n{}\n",msg); } } } ProgramID }
pub fn draw_triangle(programid:gl::types::GLuint,vertexbuffer: gl::types::GLuint,scalarbuffer:gl::types::GLuint){ unsafe { gl::UseProgram(programid); } let proj_mat:[f32;16]=[ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, ]; let model_mat:[f32;16]=[ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, ]; let proj; let model; unsafe { let proj_location_name = CString::new("projectionMatrix").unwrap(); let model_location_name = CString::new("modelViewMatrix").unwrap(); proj = gl::GetUniformLocation(programid,proj_location_name.as_ptr()); model = gl::GetUniformLocation(programid,model_location_name.as_ptr()); gl::UniformMatrix4fv(proj,1,gl::FALSE,proj_mat.as_ptr()); gl::UniformMatrix4fv(model,1,gl::FALSE,model_mat.as_ptr()); } /* // デバッグ println!("proj location: {}",proj); println!("model location: {}",model); */ unsafe{ gl::EnableVertexAttribArray(0); gl::BindBuffer(gl::ARRAY_BUFFER,vertexbuffer); gl::VertexAttribPointer( 0, 3, gl::FLOAT, gl::FALSE, 0, null() ); } unsafe{ gl::EnableVertexAttribArray(1); gl::BindBuffer(gl::ARRAY_BUFFER,scalarbuffer); gl::VertexAttribPointer( 1, 1, // 一次元配列 gl::FLOAT, gl::FALSE, 0, null() ); } unsafe { gl::DrawArrays(gl::TRIANGLES, 0,3); let err_check = gl::GetError(); if err_check != gl::NO_ERROR { println!("ERROR::: {}\n", err_check); } gl::DisableVertexAttribArray(0); gl::DisableVertexAttribArray(1); } unsafe { gl::UseProgram(0); } }
vtkPolyDataにAddArrayし、表示時にSetNameで指定したスカラー名でSelectColorArrayを呼び出す。かならずModifiedも呼び出す。
#include <iostream> //VTK_MODULE_INITに必要 #include <vtkAutoInit.h> #include <vtkSmartPointer.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkPolyDataMapper.h> #include <vtkActor.h> #include <vtkPointData.h> #include <vtkRenderWindowInteractor.h> #include <vtkCommand.h> #include <vtkInteractorStyleTrackballCamera.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);
// キーボード入力を処理 class MyCommand : public vtkCommand { bool IsRed = true; public: static MyCommand* New() { return new MyCommand; } void SetMapper(vtkSmartPointer<vtkPolyDataMapper> mapper) { this->Mapper = mapper; } void Execute(vtkObject* caller, unsigned long eventId, void*) override { if (eventId == vtkCommand::KeyPressEvent) { vtkRenderWindowInteractor* interactor = dynamic_cast<vtkRenderWindowInteractor*>(caller); std::string key = interactor->GetKeySym(); // 注意 デフォルト機能で E キーで終了してしまう
if(IsRed) { Mapper->SelectColorArray("ColorsRed");// 頂点色切替 Mapper->Modified(); } else { Mapper->SelectColorArray("ColorsBlue"); Mapper->Modified(); }
IsRed = !IsRed; interactor->GetRenderWindow()->Render(); } } private: vtkSmartPointer<vtkPolyDataMapper> Mapper; };
////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
// ランダムな点群を生成 vtkSmartPointer<vtkPolyData> CreateRandomCloud() { vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New(); polyData->SetPoints(points); polyData->SetVerts(vertices); vtkSmartPointer<vtkCellArray> verts = vtkSmartPointer<vtkCellArray>::New(); vtkIdType pid[1]; for (int i = 0; i < 10000; i++) { double p[3]; p[0] = vtkMath::Random(-1.0, 1.0); p[1] = vtkMath::Random(-1.0, 1.0); p[2] = vtkMath::Random(-1.0, 1.0); pid[0] = points->InsertNextPoint(p); verts->InsertNextCell(1, pid); } polyData->SetVerts(verts); return polyData; }
// データに色情報を追加 // 呼び出すたびにdataに色情報が追加される 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++) { colorsNew->InsertNextTuple3(rgb[0], rgb[1], rgb[2]); } data->GetPointData()->AddArray(colorsNew); }
int main(int /*argc*/, char** /*argv*/) { vtkSmartPointer<vtkPolyData> cloud = CreateRandomCloud(); SetColor(cloud, "ColorsRed",{255,0,0}); SetColor(cloud, "ColorsBlue", { 0,0,255 }); // cloudのactorを作成 vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputData(cloud); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); ////////////////////////////////////// ////////////////////////////////////// ////////////////////////////////////// // 使用する色をAddArrayで指定したスカラー値を使用するように設定 mapper->SetScalarVisibility(1); // スカラー値を使用して色をつける設定 mapper->SetScalarModeToUsePointFieldData(); // スカラー値はポイントデータに設定されているものを使用 mapper->SetColorModeToDefault(); // カラーモードをデフォルトに設定 // 実際にどのスカラー値を使用するかを設定 // 切り替え時にはかならずModified()を呼ぶ mapper->SelectColorArray("ColorsRed"); mapper->Modified();// マッパーを更新 ////////////////////////////////////// ////////////////////////////////////// ////////////////////////////////////// ////////////////////////////////////// auto renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddActor(actor); renderer->ResetCamera(); ////////////////////////////////////// auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); ////////////////////////////////////// // キー入力で色を切り替えるコマンドを設定 vtkSmartPointer<MyCommand> colorToggleCommand = vtkSmartPointer<MyCommand>::New(); colorToggleCommand->SetMapper(mapper); interactor->AddObserver(vtkCommand::KeyPressEvent, colorToggleCommand); ////////////////////////////////////// auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); renderWindow->SetInteractor(interactor); renderWindow->Render(); interactor->Start(); //イベントループへ入る return 0; }
SVGはXMLで書かれる画像フォーマットなので、pugixmlで出力できる。
以前pugixmlを導入したので、それを使う。
#include "pugixml.hpp" int main() { pugi::xml_document doc; pugi::xml_node mysvg = doc.append_child("svg"); mysvg.append_attribute("xmlns") = "http://www.w3.org/2000/svg"; mysvg.append_attribute("width") = "200"; mysvg.append_attribute("height") = "200"; // 背景を塗りつぶすための矩形 pugi::xml_node bgrect = mysvg.append_child("rect"); bgrect.append_attribute("x") = "0"; bgrect.append_attribute("y") = "0"; bgrect.append_attribute("width") = "200"; bgrect.append_attribute("height") = "200"; bgrect.append_attribute("fill") = "rgb(200,200,200)"; // 円 pugi::xml_node circle = mysvg.append_child("circle"); circle.append_attribute("cx") = "50"; circle.append_attribute("cy") = "50"; circle.append_attribute("r") = "40"; circle.append_attribute("fill") = "red"; // 線 pugi::xml_node line = mysvg.append_child("line"); line.append_attribute("x1") = "10"; line.append_attribute("y1") = "10"; line.append_attribute("x2") = "150"; line.append_attribute("y2") = "80"; line.append_attribute("stroke") = "black"; line.append_attribute("stroke-width") = "4"; // 矩形 pugi::xml_node rect = mysvg.append_child("rect"); rect.append_attribute("x") = "50"; rect.append_attribute("y") = "50"; rect.append_attribute("width") = "80"; rect.append_attribute("height") = "80"; rect.append_attribute("fill") = "blue"; rect.append_attribute("stroke") = "green"; rect.append_attribute("stroke-width") = "6"; // ファイルに保存 doc.save_file("test.svg"); }
imagemagickで画像に変換できる