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

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

新規登録して質問してみよう
ただいま回答率
85.48%
GLFW

GLFWは、OpenGLを使用してアプリ開発を行うためのフレームワークです。Macにも対応しているマルチプラットフォームであることが特徴。ウィンドウ管理、解像度切り替え、入力管理などの機能を持ちます。

OpenGL

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

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

GLSL

GLSL (OpenGL Shading Language) はC言語をベースとしたシェーディング言語です。

Q&A

解決済

1回答

3359閲覧

ウィンドウを移動するまで正常に図形が描画されない(OpenGL、GLFW)

code413

総合スコア14

GLFW

GLFWは、OpenGLを使用してアプリ開発を行うためのフレームワークです。Macにも対応しているマルチプラットフォームであることが特徴。ウィンドウ管理、解像度切り替え、入力管理などの機能を持ちます。

OpenGL

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

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

GLSL

GLSL (OpenGL Shading Language) はC言語をベースとしたシェーディング言語です。

0グッド

1クリップ

投稿2019/07/26 11:28

編集2019/07/26 15:28

環境:
MacOS 10.14.5
Xcode 10.3

床井研究室様の『GLFWによるOpenGL入門』(http://marina.sys.wakayama-u.ac.jp/~tokoi/GLFWdraft.pdf)を見て勉強しています。

第6章100Pまで行い、下記のソース(字数の都合上コメントを一部省略)ができたのですが、起動後は真ん中に(図1)、ウィンドウのサイズを変えると図形の位置が変わり、そこからウィンドウを移動すると再び図形の位置が戻ります。(図2,図3)
イメージ説明
---図1 起動直後---
イメージ説明
---図2 サイズ変更後---
イメージ説明
---図3 サイズ変更後、移動---

main

1#include<cstdlib> 2#include<iostream> 3#include<fstream> 4#include<vector> 5#include<memory> 6#include<GL/glew.h> 7#include<GLFW/glfw3.h> 8#include "Window.h" 9#include "Shape.h" 10 11// シェーダオブジェクトのコンパイル結果 12GLboolean printShaderInfoLog(GLuint shader,const char *str){ 13 GLint status; 14 glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 15 if(status == GL_FALSE) std :: cerr << "Compile Error in " << str << std::endl; 16 17 GLsizei bufSize; 18 glGetShaderiv(shader,GL_INFO_LOG_LENGTH,&bufSize); 19 20 if(bufSize > 1){ 21 std::vector<GLchar> infoLog(bufSize); 22 GLsizei length; 23 glGetShaderInfoLog(shader,bufSize,&length,&infoLog[0]); 24 std::cerr << &infoLog[0] << std::endl; 25 } 26 return static_cast<GLboolean>(status); 27} 28 29//プログラムオブジェクトのリンク結果 30GLboolean printProgramInfoLog(GLuint program){ 31 GLint status; 32 glGetProgramiv(program,GL_LINK_STATUS,&status); 33 if(status == GL_FALSE) std::cerr << "Link Error" << std::endl; 34 35 GLsizei bufsize; 36 glGetProgramiv(program,GL_INFO_LOG_LENGTH,&bufsize); 37 38 if(bufsize > 1){ 39 std::vector<GLchar> infoLog(bufsize); 40 GLsizei length; 41 glGetProgramInfoLog(program,bufsize,&length,&infoLog[0]); 42 std::cerr << &infoLog[0] << std::endl; 43 } 44 45 return static_cast<GLboolean>(status); 46} 47 48 49//プログラムオブジェクト作成 50 GLuint createProgram(const char *vsrc, const char *fsrc){ 51 const GLuint program(glCreateProgram()); 52 53 if(vsrc != NULL){ 54 //バーテックスシェーダのシェーダオブジェクトを作成、組込 55 const GLuint vobj(glCreateShader(GL_VERTEX_SHADER)); 56 glShaderSource(vobj,1,&vsrc,NULL); 57 glCompileShader(vobj); 58 59 if(printShaderInfoLog(vobj,"vertex shader")) 60 glAttachShader(program,vobj); 61 glDeleteShader(vobj); 62 } 63 64 65 if(fsrc != NULL){ 66 //フラグメントシェーダのシェーダオブジェクトを作成、組込 67 const GLuint fobj(glCreateShader(GL_FRAGMENT_SHADER)); 68 glShaderSource(fobj,1,&fsrc,NULL); 69 glCompileShader(fobj); 70 71 if(printShaderInfoLog(fobj,"fragment shader")) 72 glAttachShader(program,fobj); 73 glDeleteShader(fobj); 74 } 75 76 glBindAttribLocation(program,0,"position"); 77 glBindFragDataLocation(program,0,"fragment"); 78 glLinkProgram(program); 79 80 if(printProgramInfoLog(program)) 81 return program; 82 glDeleteProgram(program); 83 return 0; 84} 85 86 87 88//シェーダのソースを読み込んだメモリを返す 89bool readShaderSource(const char *name,std::vector<GLchar> &buffer){ 90 if(name == NULL) return false; 91 92 std::ifstream file(name,std::ios::binary); 93 if(file.fail()){ 94 std::cerr << "Error: Can't open source: " << name << std::endl; 95 return false; 96 } 97 98 file.seekg(0L,std::ios::end); 99 GLsizei length = static_cast<GLsizei>(file.tellg()); 100 101 //ファイルサイズのメモリ確保(+1では動かなかったので4に) 102 buffer.resize(length + 4); 103 104 file.seekg(0L,std::ios::beg); 105 file.read(buffer.data(),length); 106 buffer[length] = '\n'; 107 108 if(file.fail()){ 109 std::cerr << "Error: Couldn't read source:" << name << std::endl; 110 file.close(); 111 return false; 112 } 113 file.close(); 114 return true; 115} 116 117 118//シェーダのソースを読み込んでプログラムオブジェクトを作成 119GLuint loadProgram(const char *vert,const char *frag){ 120 std::vector<GLchar> vsrc; 121 const bool vstat(readShaderSource(vert, vsrc)); 122 std::vector<GLchar> fsrc; 123 const bool fstat(readShaderSource(frag, fsrc)); 124 125 return vstat && fstat ? createProgram(vsrc.data(), fsrc.data()) : 0; 126} 127 128 129constexpr Object::Vertex rectangleVertex[] = 130{ 131 {-0.5f ,-0.5f }, 132 { 0.5f ,-0.5f }, 133 { 0.5f , 0.5f }, 134 {-0.5f , 0.5f } 135}; 136 137int main() { 138 139 if(glfwInit() == GL_FALSE){ 140 std::cerr << "Can't initialize GLFW" << std::endl; 141 return 1; 142 } 143 144 atexit(glfwTerminate); 145 146 // Version 3.2 Core Profile を選択 147 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 148 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 149 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 150 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 151 152 Window window; 153 glClearColor(1.0f, 1.0f, 1.0f, 0.0f); 154 155 //プログラムオブジェクト作成 156 const GLuint program(loadProgram("point.vert","point.frag")); 157 158 // uniform変数の場所を取得 159 const GLint sizeLoc(glGetUniformLocation(program, "size")); 160 const GLint scaleLoc(glGetUniformLocation(program,"scale")); 161 162 // 図形データ作成 163 std::unique_ptr<const Shape> shape(new Shape(2, 4, rectangleVertex)); 164 165 while(window.shouldClose() == GL_FALSE) 166 { 167 glClear(GL_COLOR_BUFFER_BIT); 168 169 //シェーダプログラムの使用開始 170 glUseProgram(program); 171 172 // uniform変数に値を設定 173 glUniform2fv(sizeLoc, 1, window.getSize()); 174 glUniform1f(scaleLoc, window.getScale()); 175 176 //図形を描画 177 shape -> draw(); 178 179 window.swapBuffers(); 180 } 181} 182

Window

1#pragma once 2#include <iostream> 3#include <GL/glew.h> 4#include <GLFW/glfw3.h> 5 6// ウィンドウ関連の処理 7class Window{ 8 GLFWwindow *const window; 9 10 //ウィンドウのサイズ 11 GLfloat size[2]; 12 13 //ワールド座標系に対するデバイス座標系の拡大率 14 GLfloat scale; 15 16public: 17 //コンストラクタ 18 Window(int width = 640, int height = 480, const char *title = "Hello!") 19 : window(glfwCreateWindow(width, height, title, NULL, NULL)) 20 , scale(100.0f) 21 { 22 if(window == NULL) 23 { 24 //ウィンドウが作成できなかった 25 std::cerr << "Can't create GLFW window." << std::endl; 26 exit(1); 27 } 28 29 //現在のウィンドウを処理対象にする 30 glfwMakeContextCurrent(window); 31 32 //GLEWを初期化する 33 glewExperimental = GL_TRUE; 34 if(glewInit() != GLEW_OK) 35 { 36 //GLEWの初期化に失敗した 37 std::cerr << "Can't initialize GLEW" << std::endl; 38 exit(1); 39 } 40 41 //垂直同期のタイミングを待つ 42 glfwSwapInterval(1); 43 44 //このインスタンスの this ポインタを記録しておく 45 glfwSetWindowUserPointer(window, this); 46 47 //ウィンドウのサイズ変更時に呼び出す処理の登録 48 glfwSetWindowSizeCallback(window,resize); 49 50 //開いたウィンドウの初期設定 51 resize(window,width,height); 52 } 53 54 55 virtual ~Window(){ 56 glfwDestroyWindow(window); 57 } 58 59 //ウィンドウを閉じるべきかを判定する 60 int shouldClose() const{ 61 return glfwWindowShouldClose(window); 62 } 63 64 //カラーバッファを入れ替えてイベントを取り出す 65 void swapBuffers(){ 66 glfwSwapBuffers(window); 67 glfwWaitEvents(); 68 } 69 70 71 //ウィンドウのサイズを取り出す 72 const GLfloat *getSize() const { return size; } 73 74 //ワールド座標系に対するデバイス座標系の拡大率を取り出す 75 GLfloat getScale() const{ return scale; } 76 77 // ウィンドウのサイズ変更時の処理 78 static void resize(GLFWwindow *const window,int width,int height) 79 { 80 //ウィンドウ全体をビューポートに設定する 81 glViewport(0, 0, width, height); 82 83 //このインスタンスのthisポインタを得る 84 Window *const instance(static_cast<Window *>(glfwGetWindowUserPointer(window))); 85 86 if(instance != NULL){ 87 //開いたウィンドウのサイズを保存する 88 instance->size[0] = static_cast<GLfloat>(width); 89 instance->size[1] = static_cast<GLfloat>(height); 90 } 91 } 92}; 93

Object

1#pragma once 2#include<GL/glew.h> 3 4//図形データ 5class Object{ 6 //頂点配列、バッファ 7 GLuint vao; 8 GLuint vbo; 9 10public: 11 struct Vertex{ 12 GLfloat position[2]; 13 }; 14 15 //コンストラクタ 16 Object(GLint size,GLsizei vertexcount,const Vertex *vertex){ 17 //頂点配列,バッファオブジェクト 18 glGenVertexArrays(1,&vao); 19 glBindVertexArray(vao); 20 21 glGenBuffers(1,&vbo); 22 glBindBuffer(GL_ARRAY_BUFFER,vbo); 23 glBufferData(GL_ARRAY_BUFFER,vertexcount * sizeof(Vertex),vertex,GL_STATIC_DRAW); 24 25 //結合されている頂点バッファオブジェクトをin変数から参照できる様にする 26 glVertexAttribPointer(0,size,GL_FLOAT,GL_FALSE,0,0); 27 glEnableVertexAttribArray(0); 28 } 29 30 virtual ~Object(){ 31 glDeleteBuffers(1,&vao); 32 glDeleteBuffers(1,&vbo); 33 } 34 35private: 36 Object(const Object &o); 37 Object &operator = (const Object &o); 38 39public: 40 //頂点オブジェクトの統合 41 void bind() const{ 42 //描画する頂点配列オブジェクトを指定 43 glBindVertexArray(vao); 44 } 45}; 46

Shape

1#pragma once 2#include<memory> 3 4//図形データ 5#include "Object.h" 6 7//図形の描画 8class Shape{ 9 std::shared_ptr<const Object> object; 10 11protected: 12 const GLsizei vertexcount; 13 14public: 15 Shape(GLint size,GLsizei vertexcount,const Object::Vertex *vertex) 16 :object(new Object(size,vertexcount,vertex)) 17 ,vertexcount(vertexcount) 18 { 19 } 20 21 //描画 22 void draw() const{ 23 object -> bind(); 24 execute(); 25 } 26 27 virtual void execute() const{ 28 glDrawArrays(GL_LINE_LOOP,0,vertexcount); 29 } 30}; 31

VertexShader

1#version 150 core 2uniform vec2 size; 3uniform float scale; 4in vec4 position; 5 6void main(){ 7 gl_Position = vec4(2.0 * scale/size, 1.0 , 1.0) * position; 8 //二つ目の1.0のの前に空白を入れると動いた

FragmentShader

1#version 150 core 2out vec4 fragment; 3 4void main(){ 5 fragment = vec4(1.0, 0.0, 0.0, 1.0); 6} 7

ウィンドウのサイズが切り替わっても真ん中に表示したいのですが、移動するまでは左下の位置のままです、どうかよろしくお願いします。

追伸
バーテックスシェーダに1つスペースを加えたら、図形が横長になる問題とサイズがウィンドウに比例する問題は自己解決したので質問の画像、文章などを差し替えさせていただきました。
現在は画面サイズ変更に伴う図形の移動について悩んでいます。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

このページをSNS上で発信したところ、なんと床井先生本人からのリプライをいただいたのでWindow.hを以下のように修正して解決しました。
原因としては私の使用していたディスプレイがRetinaであることに依るものだそうです。
これに伴い、PDFの修正も行われたそうです(https://twitter.com/tokoik/status/1156837991005880321)……本当にありがとうございます。

また、この後の部分に関しても幾つか修正点があるそうなのですが、とりあえず質問の疑問となっていた部分は解決したので、いただいた修正案を解決方法として掲載させていただきます。
ちなみに画面の仕様の違いなので、PDFの抜けと呼べるものではないと思います……。(このPDFにはとてもお世話になったという私の個人的感情もありますが、修正部分があろうともOpenGL初心者の方にはおすすめします、とても良い教材です)

また、その際に質問のVertexShaderの部分は尻切れになっていたことを指摘されました、こちらに関しては私の不備です、申し訳ありません。

そして修正の詳細に関してですが、端的に言えば

glfwSetWindowSizeCallback()を
glfwSetFramebufferSizeCallback()に、

コンストラクタにあるresize()の前に
glfwGetFramebufferSize()をつけることです

なぜこの修正になるのかに関しては、修正されたpdfのP87辺り、及び以下の床井先生のツイートが一番参考になると思われます
https://twitter.com/tokoik/status/1156821288985362432

シャープが付いているのが変更点になります

Window.hの修正部分

1 2 3 4<中略> 5 6 7 8 //GLEWを初期化する 9 glewExperimental = GL_TRUE; 10 if(glewInit() != GLEW_OK) 11 { 12 //GLEWの初期化に失敗した 13 std::cerr << "Can't initialize GLEW" << std::endl; 14 exit(1); 15 } 16 17 //垂直同期のタイミングを待つ 18 glfwSwapInterval(1); 19 20 //このインスタンスの this ポインタを記録しておく 21 glfwSetWindowUserPointer(window, this); 22 23 //ウィンドウのサイズ変更時に呼び出す処理の登録 24 ### glfwSetFramebufferSizeCallback(window,resize); 25 26 //開いたウィンドウの初期設定 27 ### glfwGetFramebufferSize(window, &width, &height); 28 resize(window,width,height); 29 30 }

また、尻切れトンボになっていたvertexShaderに関しても床井先生からいただいたソースコードを掲載しておきます。なお、上のVertexShaderの最後に"}"を付けるだけでも同様の挙動を示すことを確認済みです。

vertexShader

1#version 150 core 2uniform vec2 size; 3uniform float scale; 4uniform vec2 location; 5in vec4 position; 6void main() 7{ 8 gl_Position = vec4(2.0 * scale / size, 1.0, 1.0) * position 9 + vec4(location, 0.0, 0.0); 10}

投稿2019/08/01 09:52

編集2019/08/01 09:53
code413

総合スコア14

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問