OpenGL(GLFW)で、視点移動を上手く行うことができない。
解決済
回答 1
投稿
- 評価
- クリップ 1
- VIEW 6,790
前提・実現したいこと
最終的に実現したいことは、モニタ上に描画する画像を切り替え続けつつ、頭部の動きに合わせて視点を移動させることで映像を見回すシステムです。(視界に収まらない程の巨大なスクリーンを見回すといった動作がしたい)OpenGLを用いてこれを実現しようとしています。
「raw画像を読み込み、それをテクスチャに張り付けてそれをモニタ上へ表示する」まで出来ており、"現在実現したいこと"は、「キーボードを用いて視点を移動させることで、テクスチャに張り付けた画像を見回す」ことです。
発生している問題
"gluLookAt"で視点移動を行った場合、視界からテクスチャが消える。(視点移動のコードは、Main関数の最後の方に記述する予定)
該当のソースコード
//=============================================================================
// Linker
//=============================================================================
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glfw3.lib")
#pragma comment(lib, "glew32.lib")
//=============================================================================
// define / include / using
//=============================================================================
#define GLFW_INCLUDE_GLU // GLFW3で"glu.h"を読み込むように指定
#include <iostream>
#include <fstream>
#include <vector>
#include <cassert>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
using std::cerr;
using std::endl;
using std::vector;
using std::ifstream;
using std::ios;
//=============================================================================
// variable
//=============================================================================
const int g_windowWidth = 1920;
const int g_windowHeight = 1080;
const int g_pictureWidth = 1920;
const int g_pictureHeight = 1080;
GLuint g_texID;
//=============================================================================
// Functions Prototype
//=============================================================================
extern void OnApplicationQuit();
extern void KeyCallBack(GLFWwindow *window, int key, int scancode, int action, int mods);
extern void Display();
extern void setupTexture(const char *fileName, const int textureWidth, const int textureHeight);
//=============================================================================
// Main Function
//=============================================================================
int main(){
// --- Initialize OpenGL ---
if (!glfwInit()){
cerr << "Can't initialize GLFW." << endl;
return -1;
}
// アプリケーション終了時に、GLFWで作成したウィンドウを閉じ、確保したリソースも開放する
atexit(OnApplicationQuit);
// OpenGL Version 3.2 Core Profileを選択
//glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// フルスクリーンのウィンドウを作成する
GLFWwindow *const wHandle(glfwCreateWindow(g_windowWidth, g_windowHeight, "Hello!", glfwGetPrimaryMonitor(), NULL));
if (wHandle == NULL) {
cerr << "Can't create GLFW window." << endl;
return -1;
}
// ウィンドウを作成した場合、そのウィンドウをアクティブにし、その後キーコールバック関数を登録する
glfwMakeContextCurrent(wHandle);
glfwSetKeyCallback(wHandle, KeyCallBack);
// モニタとの同期(0の場合は垂直同期オフと同義?)
glfwSwapInterval(1);
// 描画範囲の指定
glViewport(0, 0, g_windowWidth, g_windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, g_windowWidth, 0.0f, g_windowHeight, -1.0f, 1.0f);
// OpenGL上でテクスチャを生成し、その後そのテクスチャに読み込んだ画像を張り付ける
glGenTextures(1, &g_texID);
// --- Initialize OpenGL ---
// --- LoadPicture
setupTexture("sample2.raw", g_pictureWidth, g_pictureHeight);
// 背景は白色
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// ゲームループ
while (glfwWindowShouldClose(wHandle) == GL_FALSE) {
// 背景を塗りつぶす
glClear(GL_COLOR_BUFFER_BIT);
// カメラの調整
//glLoadIdentity();
//gluLookAt(0.0, 0.0, -5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// 描画
Display();
// 新しいバッファに入れ替え
glfwSwapBuffers(wHandle);
// イベントが起きるまで待機
glfwWaitEvents();
}
return 0;
}
//=============================================================================
// Static Functions
//=============================================================================
// プログラムが終了する直前に実行する。Add to atexit()
static void OnApplicationQuit(){
glfwTerminate();
}
// キーボードが入力された時の動作
static void KeyCallBack(GLFWwindow *window, int key, int scancode, int action, int mods){
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
// -- キーボードの入力に応じてgluLookAtの引数を変更する --
}
static void setupTexture(const char *fileName, const int textureWidth, const int textureHeight){
// 画像データをロードする
ifstream fstr(fileName, ios::binary);
assert(fstr);
// テクスチャデータを"textureBuffer配列"に格納する
const size_t fileSize = static_cast<size_t>(fstr.seekg(0, fstr.end).tellg());
fstr.seekg(0, fstr.beg);
vector<char> textureBuffer(fileSize);
fstr.read(&textureBuffer[0], fileSize);
// 画像データとテクスチャiDを結びつける
glBindTexture(GL_TEXTURE_2D, g_texID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureWidth, textureHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, &textureBuffer[0]);
// テクスチャの各種設定
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
// 描画
static void Display(){
// テクスチャの頂点配列を定義(画面"左下"から各頂点に対する距離)
static const GLfloat textureVertexArray[] = {
0, 0, // 左下
1920, 0, // 右下
1920, 1080, // 右上
0, 1080, // 左上
};
glVertexPointer(2, GL_FLOAT, 0, textureVertexArray);
// プロットする画像の頂点を定義(画像"左上"から各頂点に対する距離。[0 - 1.0])
static const GLfloat textureCoordArray[] = {
0.0f, 1.0f, // 左上
1.0f, 1.0f, // 右上
1.0f, 0.0f, // 右下
0.0f, 0.0f, // 左下
};
glTexCoordPointer(2, GL_FLOAT, 0, textureCoordArray);
// 指定テクスチャの設定開始
glBindTexture(GL_TEXTURE_2D, g_texID);
// 2Dテクスチャと頂点配列の使用を有効にする
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// 描画
glDrawArrays(GL_QUADS, 0, 4);
// 描画が終わったので有効にした機能を無効化
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
試したこと
"gluLookAt"で用いられているのは3次元座標となっているので、"Display関数"で定義する頂点配列を3次元のものに置き換えようと試みました。結果として画像が表示されなくなったのですが、"gluLookAt"の設定が悪いのかテクスチャのプロットが悪いのかがわかりませんでした。
補足情報(言語/FW/ツール等のバージョンなど)
〇開発環境
IDE
Visual Studio 2013 Express for Windows Desktop
OpenGLのツールキット
GLFW3
〇参考サイト
GLFW導入(NuGetは未使用)
http://marina.sys.wakayama-u.ac.jp/~tokoi/GLFW.pdf
テクスチャ(glfw3用に少し改変した)
http://nn-hokuson.hatenablog.com/entry/2014/02/05/001602
視点
http://www.natural-science.or.jp/article/20091110211125.php
頂点配列(3次元のテクスチャ貼り付け方法)
http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20080829
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
0
ざっと見て思いついたことです。
「カメラの調整」のところで、MatrixModeを設定していません。
設定していないという事は、最後に設定されたままになっています。glMatrixModeを呼んでいるのは一箇所のみのようですので、おそらくGL_PROJECTIONになっているでしょう。
ですので、glOrthoで設定したマトリクスがgluLookAt(の前のglLoadIdentity)で設定するマトリクスで上書きされていると思われます。
ビューマトリクスを設定する前に、MatrixModeをGL_MODELVIEWにしてください。
// カメラの調整
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, -5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
あともう一点。
glOrthoで指定しているFarクリップ値の値が「1.0」、カメラの位置が「0.0, 0.0, -5.0」、頂点が(Z値を指定していないので)「x, y, 0.0」の位置になっていて、カメラと頂点との距離が「5.0」になるので、デプスバッファの範囲外になり、デプステストが有効であれば表示されません。
もっとも、GL_DEPTH_TESTの設定がされていないので、デプステストのデフォルト値は無効のようなので、現状のままでも表示されると思いますが、一応適切な値を設定する事をお薦めします。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.13%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/01/09 21:32
仰る通りカメラの視点移動が正常に動作しなかったのは、モデルビューモードに設定していないことが原因でした。
カメラと頂点のパラメータを正確に理解しておらず、そのような設定となってしまいました。質問外の誤りまで指摘して頂き本当にありがとうございます。