スポンサーリンク

VTKでポリゴンにテクスチャを貼ってみる

MyTexture.hpp

#pragma once

#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkTexture.h>
#include <vtkImageData.h>

//! @brief 指定サイズの矩形を作成
//! @note テクスチャ座標設定済み
//! @param width 幅(ピクセル)
//! @param height 高さ(ピクセル)
//! @return 矩形ポリゴンのvtkPolyData
vtkSmartPointer<vtkPolyData>
MakeScreenAlignedQuad(float width, float height);
      
//! @brief 矩形ポリゴンのサイズを変更
//! @param quad 矩形ポリゴンのvtkPolyData
//! @param newWidth 新しい幅(ピクセル)
//! @param newHeight 新しい高さ(ピクセル)
//! @return なし
void ResizeQuad(vtkPolyData* quad, float newWidth, float newHeight);

//! @brief vtkTextureにvtkImageDataをセット
//! @param texture テクスチャオブジェクト
//! @param image 画像データオブジェクト
//! @return なし
void SetTextureImage(vtkTexture* texture, vtkImageData* image);

//! @brief 画像配列から vtkImageData を生成
//! @param pixels 画像ピクセル配列(RGBAまたはRGB)
//! @param width 画像幅(ピクセル)
//! @param height 画像高さ(ピクセル)
//! @param numComponents ピクセルあたりの成分数(3または4)
vtkSmartPointer<vtkImageData>
MakeImageDataFromBuffer(
  const unsigned char* pixels,
  int width, int height, 
  int numComponents
);

MyTexture.cpp

#include "MyTexture.hpp"

#include <vtkFloatArray.h>
#include <vtkPointData.h>


vtkSmartPointer<vtkPolyData>
MakeScreenAlignedQuad(float width, float height)
{
    vtkNew<vtkPoints> pts;
    pts->SetNumberOfPoints(4);

    pts->SetPoint(0, 0.0, 0.0, 0.0);
    pts->SetPoint(1, width, 0.0, 0.0);
    pts->SetPoint(2, width, height, 0.0);
    pts->SetPoint(3, 0.0, height, 0.0);

    vtkNew<vtkCellArray> polys;
    vtkIdType ids[4] = { 0,1,2,3 };
    polys->InsertNextCell(4, ids);

    vtkNew<vtkFloatArray> tcoords;
    tcoords->SetName("TCoords");
    tcoords->SetNumberOfComponents(2);
    tcoords->InsertNextTuple2(0.f, 0.f); // 左下
    tcoords->InsertNextTuple2(1.f, 0.f); // 右下
    tcoords->InsertNextTuple2(1.f, 1.f); // 右上
    tcoords->InsertNextTuple2(0.f, 1.f); // 左上

    vtkNew<vtkPolyData> pd;
    pd->SetPoints(pts);
    pd->SetPolys(polys);
    pd->GetPointData()->SetTCoords(tcoords);

    return pd;
}

vtkSmartPointer<vtkImageData>
MakeImageDataFromBuffer(
    const unsigned char* pixels,
    int width,
    int height,
    int numComponents
)
{
    vtkNew<vtkImageData> img;
    img->SetDimensions(width, height, 1);
    img->AllocateScalars(VTK_UNSIGNED_CHAR, numComponents);

    const int stride = numComponents;
    auto* dst = static_cast<unsigned char*>(img->GetScalarPointer());
    std::memcpy(dst, pixels, static_cast<size_t>(width) * height * stride);

    return img;
}

void ResizeQuad(vtkPolyData* quad, float newWidth, float newHeight)
{
    auto* pts = quad->GetPoints();
    pts->SetPoint(0, 0.0, 0.0, 0.0);
    pts->SetPoint(1, newWidth, 0.0, 0.0);
    pts->SetPoint(2, newWidth, newHeight, 0.0);
    pts->SetPoint(3, 0.0, newHeight, 0.0);
    pts->Modified();
    quad->Modified();
}

void SetTextureImage(vtkTexture* texture, vtkImageData* image)
{
    texture->SetInputData(image);
    texture->InterpolateOn();   // バイリニア補間
    texture->RepeatOff();       // 画像外は伸ばさない
    texture->EdgeClampOn();
    texture->Modified();
}

使用例

// 画像生成
std::vector<unsigned char> MakeCheckerRGBA(int w, int h, int block = 16)
{
    std::vector<unsigned char> buf(static_cast<size_t>(w) * h * 4);
    for (int y = 0; y < h; ++y)
    {
        for (int x = 0; x < w; ++x)
        {
            bool on = ((x / block) + (y / block)) % 2 == 0;
            unsigned char c = on ? 230 : 60;
            size_t idx = (static_cast<size_t>(y) * w + x) * 4;
            buf[idx + 0] = c;
            buf[idx + 1] = c;
            buf[idx + 2] = c;
            buf[idx + 3] = 255;
        }
    }
    return buf;
}
    // テクスチャオブジェクト作成 ///////////////
    vtkNew<vtkTexture> texture;
    
    // 画像データ作成 ///////////////////////////
    std::vector<unsigned char> pixels = MakeCheckerRGBA(256, 256, 32);

    // 画像データをvtkImageDataに変換 ///////////
    vtkSmartPointer<vtkImageData> imgdata = MakeImageDataFromBuffer(pixels.data(), 256, 256, 4);

    // テクスチャに画像データをセット ///////////
    SetTextureImage(texture, imgdata);

    // ポリゴン作成 /////////////////////////////
    auto poly_quad = MakeScreenAlignedQuad(100, 200);

    vtkNew<vtkPolyDataMapper> mapper;
    mapper->SetInputData(poly_quad);
    vtkNew<vtkActor> actor;
    actor->SetMapper(mapper);
    actor->SetTexture(texture);

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

コメントを残す

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

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


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