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

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

ただいまの
回答率

87.50%

1 / width の計算を行って その値掛ける画像のピクセル数というUV座標のプログラムでは誤差が生じるのか?

解決済

回答 1

投稿 編集

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

退会済みユーザー

提示画像ですが白い矩形の砲弾の画像がおかしくなっています。右の白い縦線の部分が謎なのですがこれは「1 / width の計算を行って その値掛ける画像のピクセル数というUV座標」とう誤差なのでしょうか? 提示コードのDrawGraph()関数部の頂点情報の関数ですがこれが悪いのでしょうか?画像を再度確認しましたがそんな線は入っていません。また画像サイズは0から始まるので引く-1をしてみましたが変わりませんでした。

提示コードのDrawGraph();関数は座標と。その画像の描画する座標の始まりと終わりを指定して描画する関数です。

イメージ説明

#include "../Header/Sprite.hpp"
#include "../Header/Shader.hpp"
#include "../Header/Game.hpp"
#include "../Header/Texture.hpp"
#include "../Header/VertexData.hpp"

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

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

class Game;
/*################################################################################################################
* 画像 描画クラス
################################################################################################################*/

//コンストラクタ
/*
* Game クラス
* テクスチャ パス
* 描画する画像の寸法
*/
Sprite::Sprite(class Game* g, const char* FileName) : Transform_2D(g)
{
    shader = new Shader(g,"Shader/2D/Sprite.vert", "Shader/2D/Sprite.frag");
    Owner = g;//Gameクラス

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

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

    float width = 0, height = 0;    //画像の寸法
    int channels = 0;                //画像のチャンネル数

    byte* data = LoadTexture(FileName,width,height,channels);    //テクスチャを取得

    //printf("widht: %f\n", width);
    //printf("height: %f\n", height);

    if (data != NULL) 
    {
        if (channels == 3)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)width, (GLsizei)height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        }
        else if (channels == 4)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        }
    }
    else {
        std::cerr << "Unable to load texture: " << FileName << std::endl;
    }

    //1ドットのUV数値
    mUVpos.x = 1.0 / width;    //U
    mUVpos.y = 1.0 / height;//V    


//    mSize = end - start;    //画像のサイズを取得

//    printf("width: %.2f\n", mSize.x);
//    printf("height: %.2f\n",mSize.y);

    /*
    vertex[0] = VertexAttribute_2D{ -width / 2.0f,height / 2.0f,    0,0 };
    vertex[1] = VertexAttribute_2D{ -width / 2.0f,-height / 2.0f,    0,1 };
    vertex[2] = VertexAttribute_2D{ width / 2.0f,-height / 2.0f,    1,1 };

    vertex[3] = VertexAttribute_2D{ -width / 2.0f,height / 2.0f,    0,0 };
    vertex[4] = VertexAttribute_2D{ width / 2.0f,-height / 2.0f,    1,1 };
    vertex[5] = VertexAttribute_2D{ width / 2.0f,height / 2.0f,    1,0 };
    */


    /*
    * 
    // 頂点情報を設定
    vertex[0] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,    start.x * uvWidth,start.y * uvHeight };
    vertex[1] = VertexAttribute_2D{ -mSize.x / 2.0f,-mSize.y / 2.0f,    start.x * uvWidth,end.y * uvHeight };
    vertex[2] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,    end.x * uvWidth,end.y * uvHeight };

    vertex[3] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,    start.x * uvWidth,start.y * uvHeight };
    vertex[4] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,    end.x * uvWidth,end.y * uvHeight };
    vertex[5] = VertexAttribute_2D{ mSize.x / 2.0f,mSize.y / 2.0f,        end.x * uvWidth,start.y * uvHeight };

    */


    //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);

    //頂点座標
//    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));

    //ミニマップを設定
    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);


//    glDeleteBuffers(1, &VAO);
//    glDeleteVertexArrays(1, &VAO);

    delete data;
    data = nullptr;
}

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


    Transform_2D::UpdateTransform();        //トランスフォームを更新
    Transform_2D::setTransform_Move(pos);    //移動

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



    mSize = end - start;    //画像のサイズを取得

    // 頂点情報を設定
    vertex[0] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,    start.x * mUVpos.x,start.y * mUVpos.y };
    vertex[1] = VertexAttribute_2D{ -mSize.x / 2.0f,-mSize.y / 2.0f,    start.x * mUVpos.x,end.y * mUVpos.y };
    vertex[2] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,    end.x * mUVpos.x,end.y * mUVpos.y };

    vertex[3] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,    start.x * mUVpos.x,start.y * mUVpos.y };
    vertex[4] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,    end.x * mUVpos.x,end.y * mUVpos.y };
    vertex[5] = VertexAttribute_2D{ mSize.x / 2.0f,mSize.y / 2.0f,        end.x * mUVpos.x,start.y * mUVpos.y };



    //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);

    //頂点座標
    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));    

    // バッファを解放
    glDeleteBuffers(1,&VAO);
    glDeleteVertexArrays(1,&VAO);

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

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • fana

    2021/01/26 18:20

    何を確認したのですか?

    > 1引いたり足したり

    とか言っている時点で,その対象のデータの仕様がまともに定まっていないということに他ならないのでは?
    各データには「この場合にはこの値でなければならない」という確固たる決まり(仕様)があるハズ.
    確認すべきは,
    ・実際のデータ値がその仕様通りの値であること
    ・「その仕様の上で」行わんとしている演算内容が妥当であること
    ・上記演算内容が間違いなく実装されていること
    等ではないのでしょうか?
    これらが全て真っ当であると確認されていない段階で,演算精度がどうのという話を疑うのはおかしいし,
    既に諸々確認して疑うべき事柄が演算精度くらいしかないとかいう状態なのであれば,実際の演算結果値を見てみれば良いのでは?

    キャンセル

  • fana

    2021/01/26 18:28

    …ということなので,せめて
    「これこれこういう演算を行う処理であって,入力値がXであれば演算結果値はYとなるべき話であるのに,実際の演算結果値を見てみるとZになっている.なぜなのか? 浮動小数点演算の精度によるものなのだろうか?」
    みたいな形で問うべきでは?

    何の説明も無しに単にコードだけ示しても,他者にとっては何が正しくて何が違うのかすら不明なわけです.その状態で「これは演算精度のせいですかね?」とか問うても誰も判断できないのではないでしょうか.

    キャンセル

  • 退会済みユーザー

    2021/01/27 20:36

    複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

回答 1

checkベストアンサー

-4

浮動小数点での演算は、精度以下の小数点部分が切り落とされるため、誤差がつきまといます
できるだけ整数演算で済ますような配慮が必要となります

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2021/01/26 17:15

    ではこの場合はどうするのが妥当なのでしょうか?
    UV座標は1から0までなので小数点を使わずにはいられませんw

    キャンセル

  • 2021/01/26 17:27

    実際に、手計算でそのコードのとおりに出してみればわかると思います
    1 / widthを出して、ピクセル数を掛けるのではダメです

    全体のピクセル数/部分のピクセル というように、浮動小数点での演算部分は最小にする必要があります

    キャンセル

  • 2021/01/26 17:51

    続きの数式も教えてくれますでしょうか?

    キャンセル

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

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

関連した質問

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

  • トップ
  • C++に関する質問
  • 1 / width の計算を行って その値掛ける画像のピクセル数というUV座標のプログラムでは誤差が生じるのか?