質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • C++

    3768questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • OpenGL

    174questions

    OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

OpenGLの"glTexImage2D"で動的確保した多次元配列を受け渡したい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 919

Unity-chan

score 12

現在OpenGLで,動的確保を行い画素情報を格納した多次元配列をOpenGL側の"glTexImage2D"という関数に引き渡そうとしています.

静的に多次元配列を確保していた時は問題なく引き渡すことが出来ていました.

static char    pictureData[HEIGHT][WIDTH][4];
   --------
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pictureWidth, pictureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pictureData);
   -------

しかし,毎回画像のサイズが一定ではないことから配列を動的確保したほうがよいと思いプログラムを書き換えました.その結果画面にデータが正常に表示されなくなりました.

static GLubyte***pictureData;
pictureData= new GLubyte**[HEIGHT];
for (int i = 0; i < HEIGHT; i++){
    pictureData[i] = new GLubyte*[WIDTH];
    for (int j = 0; j < WIDTH; j++){
        pictureData[i][j] = new GLubyte[4];
    }
}
   --------
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pictureWidth, pictureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pictureData);
   -------

glTexImage2Dの引数が下のようになっているので,1重(?)ポインタに3重ポインタを渡しているのでそれが原因かなと思っています.
GLAPI void GLAPIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);

しかし,どのように解決すればいいかよくわかりませんでした.
今まで多次元配列を静的確保した場合も,動的確保した場合も違いがないと思っていたので・・・・.

//静的確保
static char    staticArray[HEIGHT][WIDTH][4];
//動的確保
static char    dynamicArray;
dynamicArray= new char    **[HEIGHT];
for (int i = 0; i < HEIGHT; i++){
    dynamicArray[i] = new char*[WIDTH];
    for (int j = 0; j < WIDTH; j++){
        dynamicArray[i][j] = new char[4];
    }
}

解決策やアドバイスを頂けると幸いです.

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

自己解決できました.
glTexImage2Dが想定しているデータの並び方に対して正しく動的確保を行えていないことが原因でした.

次の図はglTexImage2Dにおけるデータの読み込み方を示したものです.
ここで番地「1000」は引数として渡されたポインタのことです(基本的には配列の先頭アドレスになると思います).また今回の配列のデータ型はchar,色情報はRGBとしています.
イメージ説明
glTexImage2Dは,渡された先頭アドレスから1バイト単位でデータを読んでいきます.そのデータを3つ毎にピクセル値のRGB情報として扱い,「WIDTH」ピクセル分繰り返したら次の行に移るということを,「HEIGHT」行まで行います.

次の図では静的に多次元配列を確保した場合における,「配列のインデックス番号」「メモリ上の番地」「データ」の関係を示したものです.ここで,確保した配列は"staticArray[HEIGH][WIDTH][3]"であり,先頭アドレス"&staticArray[HEIGHT][WIDTH][3]"のアドレスは"1000"とします.また,「HEIGHTはピクセルの行番号」「WIDTHはピクセルの列番号」「3はRGB」を示しています.
イメージ説明
表を見てわかるとおり,静的確保をした場合すべてのデータがメモリ上へ順番に確保されます.
したがって,staticArrayの先頭アドレスをglTexImage2Dに引き渡した場合,先頭アドレスからのデータを順番に読み込んでくれるのでOpenGL上で想定通りにデータが読み込まれます.

一方次の図に,質問のように動的確保をした多次元配列の関係を示してみます.インデックス番号等の条件は静的確保した場合と同様です.
イメージ説明
表を見ると,"dynamicArray[0][0][0]"から"dynaicArray[0][0][2]"までは連続してメモリ上に格納されているにも関わらず,"dynamicArray[0][1][0]"では全く違うところに格納されていることがわかります.
もし,同じようにdynamicArrayの先頭アドレスをglTexImage2Dに渡した場合,最初の1ピクセル目までのデータは正常に読みこみますが,その次は番地"1003"を参照してしまうため2ピクセル目以降は想定した画素情報が読み込まれません(もちろんすべてのデータが順番にメモリ上へ格納されていれば問題ないですが…).

上記のことを踏まえると,動的確保する際にすべてのデータが順番にメモリ上へ格納されるように定義すればよいということがわかります.そうすれば,その先頭アドレスをglTexImage2Dに渡すだけであとはOpenGLが処理を行ってくれます.

// 必要なメモリ確保及び,各先頭アドレスの定義
dynamicArray= new GLubyte**[HEIGHT];
dynamicArray[0] = new GLubyte*[HEIGHT * WIDTH];
dynamicArray[0][0] = new GLubyte[HEIGHT * WIDTH * 3];

// 先頭アドレスからの相対位置にすることで順番にメモリ上へ並ぶようにする
for (int i = 0; i < HEIGHT; i++){
    dynamicArray[i] = dynamicArray[0] + (i * WIDTH);
    for (int j = 0; j < WIDTH; j++){
        dynamicArray[i][j] = dynamicArray[0][0] + (i * CAMERA_WIDTH * 3) + (j * 3);
    }
}

// 値の書き込みの例(緑一色)
for (int i = 0; i < CAMERA_HEIGHT; i++){
    for (int j = 0; j < CAMERA_WIDTH; j++){
        dynamicArray[i][j][0] = 0;
        dynamicArray[i][j][1] = 255;
        dynamicArray[i][j][2] = 0;
    }
}

// glTexImage2Dへの引き渡し("**dynamicArray"よりは"&dynamicArray[0][0][0]"のほうがぱっと見で分かりやすいかもしれない)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, **dynamicArray);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

こんにちは。

渡しているメモリの構造が異なりますよ。

static char    pictureData[HEIGHT][WIDTH][4];

これは、連続した領域にHEIGHT*WIDTH*4バイトのメモリを確保します。
pictureDataはそのHEIGHT*WIDTH*4バイトのメモリの先頭アドレスを指します。

static GLubyte*pictureData;
pictureData= new GLubyte
[HEIGHT];

この場合、pictureDataは(GLubyte*)型を指すポインタHEIGHT個の配列を指しています。
32ビット・ビルドならポインタは4バイトなので、4*HEIGHTバイトの連続したメモリです。
メモリのサイズが異なりますね。

下記のようなイメージで獲得し、アクセスすれば良いですよ。

char* pictureData=new char[HEIGHT*WIDTH*4];
h, wピクセルのcチャネルは、pictureData[((h*WIDTH)+w)*4+c]

折角のC++なので、classを作ってメモリ獲得/解放やピクセル・アクセスを任せてしまうと良いですよ。
手抜きしまくりですが、下記のようなイメージです。

struct PictureData
{
    size_t  mHeight;
    size_t  mWidth;
    char*   mData;
public:
    PictureData(size_t iHeight, size_t iWidth) :
        mHeight(iHeight), mWidth(iWidth), mData(new char[iHeight*iWidth*4]())
    { }
    ~PictureData()
    {
        delete[] mData;
    }
    char& at(size_t h, size_t w, size_t c)
    {
        return mData[((h*mWidth)+w)*4+c];
    }
};

at()は参照を返しているので、下記のような操作もできます。

PictureData aPictureData(200, 100);
aPictureData.at(0, 0, 2)=100;

glTexImage2Dへ渡す時は、&aPictureData.at(0, 0, 0)でmDataの先頭アドレスが渡ります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • C++

    3768questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • OpenGL

    174questions

    OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。