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

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

ただいまの
回答率

87.60%

回転行列が上手く動作しない理由が知りたい。 中心を中心回転させたい。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 658
退会済みユーザー

退会済みユーザー

提示画像ですが移動して左キーを押すと座標はそのままで画像が上に移動してしまうのですがこれは何が原因なのでしょか?画像サイズはこの砲弾の画像の大きさが読み込んでいます。22,28
提示コードの/////コメント部の内部の回転行列の行列部が悪いと思うのですが何を間違えてのでしょうか?よく考えましたがどうしてもわかりません。
描画原点を中心に回転してしまうのですがどうすれば中心を中心に回転するのでしょうか?

イメージ説明
イメージ説明

#include "../Header/Sprite.hpp"
#include "../Header/Shader.hpp"
#include "../Header/Entry.hpp"
#include "../Header/LoadTexture.hpp"
#include "../Header/VertexData.hpp"

// 数学ライブラリ
#include "glm/ext.hpp"
#include "glm/glm.hpp"

#include <vector>

// OpenCV 
#include <opencv2/core.hpp>

/*################################################################################################################
* 画像 描画クラス
################################################################################################################*/

//コンストラクタ
/*
* Entry クラス
* テクスチャ パス
* 描画する画像の寸法
*/
Sprite::Sprite(class Entry* g, std::shared_ptr<TextureData> sp ) : Transform_2D(g)
{
    shader = std::make_shared<class Shader>(g,"Shader/2D/Sprite.vert", "Shader/2D/Sprite.frag");

    Owner = g;//Entryクラス

    Transform_2D::setTransfrom(glm::vec2(1,1),0,glm::vec2(0,0));    //トランスフォームを初期化

    //テクスチャを設定     
    glGenTextures(1, &TextureID);
    glBindTexture(GL_TEXTURE_2D, TextureID);

    //画像の大きさ
    mPicSize.x = (float)sp->mSize.x;
    mPicSize.y = (float)sp->mSize.y;


//    printf("%d\n",sp->mData->size());


    if (sp->mData->data() != NULL)
    {
        if (sp->channels == 3)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)sp->mSize.x, (GLsizei)sp->mSize.y, 0, GL_RGB, GL_UNSIGNED_BYTE, sp->mData->data());
        }
        else if (sp->channels == 4)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)sp->mSize.x, (GLsizei)sp->mSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, sp->mData->data());
        }
    }
    else {
        std::cerr << "Unable to load texture: " <<std::endl;
    }


    //ミニマップを設定
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glGenerateMipmap(GL_TEXTURE_2D);

    //異方性フィルタリングを設定
    GLfloat largest;
    glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest);




    //VAO
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    //VBO
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, (sizeof(vertex) / sizeof(vertex[0])) * sizeof(VertexAttribute_2D), vertex, GL_STATIC_DRAW);



}

//描画
void Sprite::DrawGraph(glm::ivec2 pos, glm::vec2 start, glm::vec2 end)
{

    glm::vec2 mSize;

    mSize = end - start;    //描画範囲を取得

    if (mSize.x > mPicSize.x)
    {
        mSize.x = mPicSize.x;
    }

    if (mSize.y > mPicSize.y)
    {
        mSize.y = mPicSize.y;
    }

    //左上が原点になるように修正
    //pos.x = (-SCREEN_WIDTH / 2) + (pos.x);
    //pos.y = (SCREEN_HEIGHT / 2) + (pos.y);


    shader->Enable();    //シェーダーを有効にする
    shader->SetFloatUniform_3m("uViewMatrix", getViewMatrix());
    shader->SetFloatUniform_3m("uWorldMatrix", getWorldMatrix());

    Transform_2D::setTransform_Move(pos);    //移動

    /* // 描画座標の中心に画像を描画
    vertex[0] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,        start.x / mPicSize.x   ,start.y / mPicSize.y };
    vertex[1] = VertexAttribute_2D{ -mSize.x / 2.0f,-mSize.y / 2.0f,    start.x / mPicSize.x   ,end.y / mPicSize.y };
    vertex[2] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,        end.x / mPicSize.x     ,end.y / mPicSize.y };
    vertex[3] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,        start.x / mPicSize.x  ,start.y / mPicSize.y };
    vertex[4] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,        end.x / mPicSize.x    ,end.y / mPicSize.y };
    vertex[5] = VertexAttribute_2D{ mSize.x / 2.0f,mSize.y / 2.0f,        end.x / mPicSize.x    ,start.y / mPicSize.y };
    */

    //左上が原点
    vertex[0] = VertexAttribute_2D{ 0,0,                                                start.x / mPicSize.x   ,start.y / mPicSize.y };
    vertex[1] = VertexAttribute_2D{ 0,-mSize.y,                                            start.x / mPicSize.x   ,end.y / mPicSize.y };
    vertex[2] = VertexAttribute_2D{ mSize.x,-mSize.y,                                    end.x / mPicSize.x     ,end.y / mPicSize.y };


    vertex[3] = VertexAttribute_2D{ 0 ,0,                                                start.x / mPicSize.x  ,start.y / mPicSize.y };
    vertex[4] = VertexAttribute_2D{ mSize.x,-mSize.y,                                    end.x / mPicSize.x    ,end.y / mPicSize.y };
    vertex[5] = VertexAttribute_2D{ mSize.x, 0,                                            end.x / mPicSize.x    ,start.y / mPicSize.y };




    //VAO
    glBindVertexArray(VAO);

    //VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, (sizeof(vertex) / sizeof(vertex[0])) * sizeof(VertexAttribute_2D), vertex, GL_STATIC_DRAW);

    //頂点座標
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttribute_2D), NULL);

    //UV座標
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttribute_2D), (void*)(sizeof(float) * 2));

    glBindVertexArray(VAO);
    glBindTexture(GL_TEXTURE_2D, TextureID);
    glDrawArrays(GL_TRIANGLES, 0, (GLsizei)std::size(vertex));    

}



// 画像サイズを取得
glm::vec2 Sprite::getSize()
{
    return mPicSize;
}


//コンストラクタ
Sprite::Sprite(const Sprite & sp) : Transform_2D(sp.Owner)
{
    shader = std::make_shared<Shader>(sp.Owner, "Shader/2D/Sprite.vert", "Shader/2D/Sprite.frag");
    Owner = sp.Owner;    //Entryクラス
    mPicSize.x = sp.mPicSize.x;
    mPicSize.y = sp.mPicSize.y;

}


// デストラクタ
Sprite::~Sprite()
{
    // バッファを解放
    glDeleteBuffers(1, &VAO);
    glDeleteVertexArrays(1, &VAO);

    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D, 0);

    glDeleteTextures(1,&TextureID);

}
#include "../Header/Transform_2D.hpp"
#include "../Header/Entry.hpp"

//コンストラクタ
Transform_2D::Transform_2D(class Entry* g)
{
    Owner = g; //Entryクラス

    //回転行列を初期化
    mRotate_matrix = glm::mat3(0);
    mRadian = 0;

    //拡大縮小行列を初期化
    mScale_matrix = glm::mat3(0);

    //平行移動行列を初期化
    mMove_matrix = glm::mat3(0);


    mScale = glm::vec2(1,1);    //スケール
    mRadian = 0;                //回転
    mMove = glm::vec2(0, 0);    //平行移動

    //初期化
    setTransform_Scale(mScale);
    setTransform_Rotate(mRadian);
    setTransform_Move(mMove);
}

void Transform_2D::UpdateTransform()
{
    setTransform_Scale(mScale);
    setTransform_Rotate(mRadian);
    setTransform_Move(mMove);
}

// 同時に初期化
void Transform_2D::setTransfrom(glm::vec2 s, float r, glm::vec2 m)
{
    setTransform_Scale(s);
    setTransform_Rotate(r);
    setTransform_Move(m);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//回転行列
void Transform_2D::setTransform_Rotate(float r)
{
    float sc[9];
    sc[0] = cos(r);
    sc[1] = -sin(r);
    sc[2] = 0;

    sc[3] = sin(r);
    sc[4] = cos(r);
    sc[5] = 0;

    sc[6] = 0;
    sc[7] = 0;
    sc[8] = 1;

    glm::mat3 t = glm::make_mat3(sc);
    mRotate_matrix = t;

    mRadian = r;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//拡大縮小
void Transform_2D::setTransform_Scale(glm::vec2 p)
{
    float sc[9];
    sc[0] = p.x;
    sc[1] = 0;
    sc[2] = 0;

    sc[3] = 0;
    sc[4] = p.y;
    sc[5] = 0;

    sc[6] = 0;
    sc[7] = 0;
    sc[8] = 1;

    glm::mat3 t = glm::make_mat3(sc);
    mScale_matrix = t;
}

//平行移動
void Transform_2D::setTransform_Move(glm::vec2 p)
{
    float m[9];

    m[0] = 1;
    m[1] = 0;
    m[2] = p.x;

    m[3] = 0;
    m[4] = 1;
    m[5] = p.y;

    m[6] = 0;
    m[7] = 0;
    m[8] = 1;


    glm::mat3 tt = glm::make_mat3(m);
    mMove_matrix = tt;

    mMove = p;

}

//回転
glm::mat3 Transform_2D::getRotate()
{
    return mRotate_matrix;
}

//平行移動
glm::mat3 Transform_2D::getMove()
{
    return mMove_matrix;
}
//拡大縮小
glm::mat3 Transform_2D::getScale()
{
    return mScale_matrix;
}


float Transform_2D::getTransform_getRotate()
{
    return mRadian;
}

glm::vec2 Transform_2D::getTransform_Scale()
{
    return mScale;
}

glm::vec2 Transform_2D::getTransform_Move()
{
    return mMove;
}



//ワールド行列
glm::mat3 Transform_2D::getWorldMatrix()
{
    glm::mat3 r = mScale_matrix * mRotate_matrix * mMove_matrix;

    return r;
}

//ビュー行列
glm::mat3 Transform_2D::getViewMatrix()
{
    //ビュー行列
    float sv[9];
    sv[0] = (2.0f / SCREEN_WIDTH);
    sv[1] = 0.0f;
    sv[2] = 0.0f;

    sv[3] = 0.0f;
    sv[4] = (2.0f / SCREEN_HEIGHT);
    sv[5] = 0.0f;

    sv[6] = 0.0f;
    sv[7] = 0.0f;
    sv[8] = 1.0f;

    ViewMatrix = glm::make_mat3(sv);

    return ViewMatrix;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2021/02/15 21:17

    文章を修正しました。

    キャンセル

  • int32_t

    2021/02/16 10:05

    コードは精読していませんが、座標の原点は画面中央で、キャラクターに180度の回転行列を適用すると、原点を中心に回転してしまうが、キャラクターの中心を中心に回転させたい、という理解で合ってますか?

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2021/02/16 10:07

    そうですね。この画像と状態を見るにおそらくそいうことが起きてほしいのでだと思います。

    キャンセル

回答 3

checkベストアンサー

+1

(※強引な「エスパー回答」的なものになるかと思うので,間違いだと判断できた方はその旨をコメントとして示しつつ低評価していただきたく)

glm::mat3 Transform_2D::getWorldMatrix()の返す行列の内容が
glm::mat3 r = mScale_matrix * mRotate_matrix * mMove_matrix;であること
と,
その行列の用いられ方との間に齟齬があることが(左を押すと上に行くみたいな)問題現象の原因ではないかと想像します.

この行列が
shader->SetFloatUniform_3m("uWorldMatrix", getWorldMatrix());
としてシェーダに渡された後で実際にどのように使用されているのかは示されていませんが,頂点座標ベクトルに左からかける:

(mScale_matrix * mRotate_matrix * mMove_matrix) * 頂点座標

という形で用いるのだとすれば,この演算は

mScale_matrix * ( mRotate_matrix * ( mMove_matrix * 頂点座標 ) )

ということであり,
真っ先に mMove_matrix が適用される形となります.
その結果座標に対して mRotate_matrix を適用した結果の座標というのはどこに行くのか? ということを再確認されると良いのではないでしょうか.

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2021/02/17 18:42

    自分の能力では不可能と判断しました。

    キャンセル

+1

おそらくmSpriteの内部実装と思われます。なんとなくですが setTransform_Rotate の回転の機能が移動と描画に対して整理されておらず、うまく作用していないような気がします。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2021/02/15 19:23

    確認しましたが入ってますwwwどうしたらいいのでしょうか?

    //ワールド行列を生成
    glm::mat4 Transform::getWorldMatrix()
    {
    glm::mat4 m = getMove() * getScale() * getRotate();

    return m;
    }

    キャンセル

  • 2021/02/15 19:36

    言い方が間違っていました回転成分自体は必ず入っています。ただ今回のこの状況では回転角度0の成分になっているのではないでしょうか?という意味です。回転角度0ではない回転行列になってしまっている場合はそうなった箇所を自身で特定・修正するしかありません。

    キャンセル

  • 2021/02/15 19:39

    わからないので4方向分のスプライトを用意することにしました。

    キャンセル

+1

(微塵もコードを読まずに回答します。OpenGLの知識はないのでコードでの回答はできません。)

キャラクターの中心点を中心として回転をさせたい場合は、

  1. キャラクターの座標から、キャラクターの中心点を引いて、原点に移動させる
  2. 結果の座標に回転行列を適用する
  3. 結果の座標に、手順1で引いたキャラクター中心点を足す

という計算をすればよいはずです。
(これを一つの行列計算でやることが可能だった気がしますが、それは無くても動くし、必要ならご自分で調べてください)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

  • ただいまの回答率 87.60%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

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