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

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

ただいまの
回答率

89.99%

GLFWで矩形が描画されない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,139

honjoriki

score 56

わからないこと

現在、床井研究室(http://marina.sys.wakayama-u.ac.jp/~tokoi/)の資料を見ながらOpenGLを勉強しております。

そこで見ていたGLFWでのOpenGL入門(http://marina.sys.wakayama-u.ac.jp/~tokoi/GLFWdraft.pdf)第5章、矩形の表示ができません。コンパイルまでは通るのですが、図形表示までの処理がされていない様子です。

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include <memory>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "Shape.h"


// シェーダオブジェクトのコンパイル結果を表示する
// shader: シェーダオブジェクト名
// str: コンパイルエラーが発生した場所を示す文字列
GLboolean printShaderInfoLog(GLuint shader, const char *str)
{
  // コンパイル結果を取得する
  GLint status;
  glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
  if (status == GL_FALSE) std::cerr << "Compile Error in " << str << std::endl;
  // シェーダのコンパイル時のログの長さを取得する
  GLsizei bufSize;
  glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &bufSize);
  if (bufSize > 1)
  {
    // シェーダのコンパイル時のログの内容を取得する
    std::vector<GLchar> infoLog(bufSize);
    GLsizei length;
    glGetShaderInfoLog(shader, bufSize, &length, &infoLog[0]);
    std::cerr << &infoLog[0] << std::endl;
  }
  return static_cast<GLboolean>(status);
}

// プログラムオブジェクトのリンク結果を表示
// program: プログラムオブジェクト名
GLboolean printProgramInfoLog(GLuint program)
{
  // リンク結果取得
  GLint status;
  glGetProgramiv(program, GL_LINK_STATUS, &status);
  if(status == GL_FALSE) std::cerr << "Link Error." << std::endl;

  // シェーダのリンク時のログの長さを取得
  GLsizei bufSize;
  glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufSize);

  if(bufSize > 1) {
    //シェーダのリンク時のログの内容を取得する
    std::vector<GLchar> infoLog(bufSize);
    GLsizei length;
    glGetProgramInfoLog(program, bufSize, &length, &infoLog[0]);
    std::cerr << &infoLog[0] << std::endl;
  }

  return static_cast<GLboolean>(status);
}


// プログラムオブジェクトを作成する
// vsrc: バーテックスシェーダのソースプログラムの文字列
// fsrc: フラグメントシェーダのソースプログラムの文字列

GLuint createProgram(const char *vsrc, const char *fsrc)
{
  // 空のプログラムオブジェクトを作成する
  const GLuint program(glCreateProgram());

  if(vsrc != NULL) {
    // バーテックスシェーダのシェーダオブジェクトを作成
    const GLuint vobj(glCreateShader(GL_VERTEX_SHADER));
    glShaderSource(vobj, 1, &vsrc, NULL);
    glCompileShader(vobj);

    // バーテックスシェーダのシェーダオブジェクトをプログラムオブジェクトに組み込む
    if(printShaderInfoLog(vobj, "vertex shader"))
      glAttachShader(program, vobj);
    glDeleteShader(vobj);
  }

  if(fsrc != NULL) {
    // フラグメントシェーダのシェーダオブジェクトを作成
    const GLuint fobj(glCreateShader(GL_FRAGMENT_SHADER));
    glShaderSource(fobj, 1, &fsrc, NULL);
    glCompileShader(fobj);

    // フラグメントシェーダのシェーダオブジェクトをプログラムオブジェクトに組み込む
    if(printShaderInfoLog(fobj, "fragment shader"))
      glAttachShader(program, fobj);
    glDeleteShader(program);
  }

  // プログラムオブジェクトをリンクする
  glBindAttribLocation(program, 0, "position");
  glBindFragDataLocation(program, 0, "fragment");
  glLinkProgram(program);

  // 作成したプログラムオブジェクトを返す
  if(printProgramInfoLog(program))
    return program;

  // プログラムオブジェクトが作成できなければ0を返す
  glDeleteProgram(program);
  return 0;
}




// シェーダのソースファイルを読み込んだメモリを返す
// name: シェーダのソースファイル名
// buffer: 読み込んだソースファイルのテキスト
bool readShaderSource(const char *name, std::vector<GLchar> &buffer)
{
  //ファイル名がNULLなら
  if(name == NULL) {
    return false;
  }
  // ソースファイルを開く
  std::ifstream file(name, std::ios::binary);
  if(file.fail()) {
    // 開けなかった
    std::cerr << "Error: Can't open source file: " << name << std::endl;
    return false;
  }

  // ファイルの末尾に移動して現在位置を得る
  file.seekg(0L, std::ios::end);
  GLsizei length = static_cast<GLsizei>(file.tellg());

  // ファイルサイズのメモリ確保
  buffer.resize(length + 1);

  // ファイルを先頭から読み込む
  file.seekg(0L, std::ios::beg);
  file.read(buffer.data(), length);
  buffer[length] = '\0';

  if(file.fail()) {
    // うまく読み込めなかった
    std::cerr << "Error: Could not read source file: " << name << std::endl;
    file.close();
    return false;
  }

  // 読み込み成功
  file.close();
  return true;
}


// シェーダのソースファイルを読み込んでプログラムオブジェクトを作成する
// vert:バーテックスシェーダのソースファイル名
// frag:フラグメントシェーダのソースファイル名
GLuint loadProgram(const char *vert, const char *frag)
{
  // シェーダのソースファイルを読み込む
  std::vector<GLchar> vsrc;
  const bool vstat(readShaderSource(vert, vsrc));
  std::vector<GLchar> fsrc;
  const bool fstat(readShaderSource(frag, fsrc));

  // プログラムオブジェクトを作成
  return vstat && fstat ? createProgram(vsrc.data(), fsrc.data()) : 0;
}

// 矩形の頂点の位置
constexpr Object::Vertex rectangleVertex[] =
{
  { -0.5f, -0.5f },
  {  0.5f, -0.5f },
  {  0.5f,  0.5f },
  { -0.5f,  0.5f }
};


int main()
{
  // GLFW初期化
  if(glfwInit() == GL_FALSE) {
    std::cerr << "Can't initialize GLFW" << std::endl;

    return 1;
  }

  // プログラム終了時の処理を登録
  atexit(glfwTerminate);

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

  // window生成
  GLFWwindow *const window(glfwCreateWindow(640, 480, "Hello", NULL, NULL));
  if(window == NULL) {
    std::cerr << "Can't create GLFW window" << std::endl;
    return 1;
  }
  //windowをOpenGLの処理対象にする
  glfwMakeContextCurrent(window);

  // GLEW初期化
  glewExperimental = GL_TRUE;
  if(glewInit() != GLEW_OK) {
    std::cerr << "Can't initialize GLEW" << std::endl;
    return 1;
  }

  // 垂直同期のタイミングを待つ
  glfwSwapInterval(1);

  // 背景色指定
  glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

  // プログラムオブジェクトの作成
  const GLuint program(loadProgram("point.vert", "point.frag"));

  // 図形データを作成する
  std::unique_ptr<const Shape> shape(new Shape(2, 4, rectangleVertex));

  // windowが開いている間繰り返す
  while(glfwWindowShouldClose(window) == GL_FALSE) {
    // windowの消去
    glClear(GL_COLOR_BUFFER_BIT);

    // シェーダプログラムの使用開始
    glUseProgram(program);

    //ここで描画処理を行う
    shape->draw();


    // カラーバッファの入れ替え
    glfwSwapBuffers(window);

    // イベントを取り出す
    glfwWaitEvents();
  }
}
#pragma once
#include <GL/glew.h>

// 図形データ
class Object {
  // 頂点配列オブジェクト名
  GLuint vao;
  // 頂点バッファオブジェクト名
  GLuint vbo;

public:

  // 頂点属性
  struct Vertex {
    // 位置
    GLfloat position[2];
  };

  //コンストラクタ
  // size: 頂点の位置の次元
  // vertexcount: 頂点の数
  // vertex: 頂点属性を格納した配列
  Object(GLint size, GLsizei vertexcount, const Vertex *vertex)
  {
    // 頂点配列オブジェクト
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // 頂点バッファオブジェクト
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER,
      vertexcount * sizeof(Vertex), vertex, GL_STATIC_DRAW);

    // 結合されている頂点バッファオブジェクトを in 変数から参照できるようにする
    glVertexAttribPointer(0, size, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
  }

  // デストラクタ
  virtual ~Object()
  {
    // 頂点配列オブジェクトを削除
    glDeleteBuffers(1, &vao);

    // 頂点バッファオブジェクトを削除
    glDeleteBuffers(1, &vbo);
  }

private:

  // コピーコンストラクタによるコピー禁止
  Object(const Object &o);

  // 代入によるコピー禁止
  Object &operator=(const Object &o);


public:

  // 頂点配列オブジェクトの結合
  void bind() const
  {
    // 描画する頂点配列オブジェクトを指定する
    glBindVertexArray(vao);
  }
};
#pragma once
#include <memory>

// 図形データ
#include "Object.h"

// 図形の描画
class Shape
{
  // 図形データ
  std::shared_ptr<const Object> object;

protected:

  // 図形に扱う頂点の数
  const GLsizei vertexcount;

public:

  // コンストラクタ
  // size: 頂点の位置の次元
  // vertexcount: 頂点の数
  // vertex: 頂点属性を格納した配列
  Shape(GLint size, GLsizei vertexcount, const Object::Vertex *vertex)
   : object(new Object(size, vertexcount, vertex))
   , vertexcount(vertexcount)
   {
     // 本体はない
   }

   // 描画
   void draw() const
   {
     // 頂点配列オブジェクトを結合
     object->bind();

     // 描画の実行
     execute();
   }

   // 描画の実行
   virtual void execute() const
   {
     // 折れ線で描画する
     glDrawArrays(GL_LINE_LOOP, 0, vertexcount);
   }
};
#version 150 core
in vec4 position;
void main()
{
  gl_Position = position;
}
#version 150 core
out vec4 fragment;
void main()
{
  fragment = vec4(1.0, 0.0, 0.0, 1.0);
}

これまでも何度か、記述の順番が違うなどの理由でエラーを出してきたのですが、今回ばかりはどうにもわかりません。よろしくお願いします。

$ c++ main.cpp -g -std=c++11 -I/usr/local/include -L/usr/local/lib -lglfw -lglew -framework OpenGL -framework CoreVideo -framework IOKit -framework Cocoa
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

macOS 10.14にHomebrewでGLEW 2.1.0、GLFW 3.2.1をインストールして、ご提示の「○○くんのために一所懸命書いたものの結局○○くんの卒業に間に合わなかったGLFW による OpenGL 入門」に従ってプロジェクトを作り、ソースコードはご質問者さんのものをそのまま使ったところ、確かに描画されませんでした...

このとき、Xcodeの出力欄に「Link Error.」と表示されたのですが、ご質問者さんの場合は何かメッセージは表示されましたでしょうか?
私の場合ですと、フラグメントシェーダーを生成・アタッチする部分に下記のような修正を加えたところ、とりあえず赤い四角が現れるようになりました(ただし、最初にウインドウをちょっとドラッグして動かしてやらないと描画されないという謎の現象がありましたが...)。

    if(fsrc != NULL) {
        // フラグメントシェーダのシェーダオブジェクトを作成
        const GLuint fobj(glCreateShader(GL_FRAGMENT_SHADER));
        glShaderSource(fobj, 1, &fsrc, NULL);
        glCompileShader(fobj);

        // フラグメントシェーダのシェーダオブジェクトをプログラムオブジェクトに組み込む
        if(printShaderInfoLog(fobj, "fragment shader"))
            glAttachShader(program, fobj);
        // glDeleteShader(program); // ここで関数に渡すべきなのは、プログラムオブジェクトではなく...
        glDeleteShader(fobj); // シェーダーオブジェクトの方ではないでしょうか?
    }

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/10/01 09:25

    ありがとうございます。単純に私のタイプミスだと思います。私の環境はコマンドラインでコンパイル・実行しているのですが、特にエラー情報は出力されませんでした。ウインドウをドラッグしないと描画されない現象も今の所は確認できておりません。環境によって実行処理が変わってしまうのでしょうか...

    キャンセル

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

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

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