スポンサーリンク

| キーワード:

glReadPixelsでOpenGLの表示内容を保存

saveGLtoPPM.hpp

#pragma once

#include <Windows.h>
#include <gl/GL.h>
#include <vector>
#include <cstdio>

#pragma warning(disable:4996)


//画像の上下を反転する
void reverse_Y(const int width, const int height, unsigned char* p) {

  int WidthByte = width * 3;

  size_t HalfHEIGHT = height / 2;
  for (int ha = 0; ha < HalfHEIGHT; ha++) {

    int hb = (height - ha) - 1;

    unsigned char* pha = p + ha * WidthByte;
    unsigned char* phb = p + hb * WidthByte;

    if (ha != hb) {
      for (size_t i = 0; i < WidthByte; i++) {
        std::swap(pha[i], phb[i]);
      }
    }

  }

}
//! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む
//! @param [in] fname ファイル名
//! @param [in] vmax 全てのRGBの中の最大値
//! @param [in] width 画像の幅
//! @param [in] height 画像の高さ
//! @param [in] p 画像のメモリへのアドレス
//! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
void pnmP3_Write(const char* const fname, const int vmax, const int width, const int height, const unsigned char* const p) { // PPM ASCII


  FILE* fp = fopen(fname, "w");

  fprintf(fp, "P3\n%d %d\n%d\n", width, height, vmax);

  size_t k = 0;
  for (size_t i = 0; i < (size_t)height; i++) {
    for (size_t j = 0; j < (size_t)width; j++) {
      fprintf(fp, "%d %d %d ", p[k * 3 + 0], p[k * 3 + 1], p[k * 3 + 2]);
      k++;
    }
    fprintf(fp, "\n");
  }

  fclose(fp);


}

//! @brief OpenGLの画面を画像に保存 
//! @param [in] width 画像幅ピクセル数
//! @param [in] height 画像高さピクセル数
//! @param [in] pathname ファイル名
void saveGLtoPPM(const int width, const int height, const char* pathname) {

  //メモリ確保
  std::vector<GLubyte> buffer;
  buffer.resize(width*height * 3);

  //画像取得
  glReadBuffer(GL_FRONT);
  glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer.data());

  //上下反転
  reverse_Y(width, height, buffer.data());

  pnmP3_Write(
    pathname,
    255,
    width,
    height,
    buffer.data()); // PPM ASCII

}

使用方法

#include <iostream>

#include <Windows.h>
#include "prepare_shader.hpp"
#include <gl/GL.h>
#include <gl/GLU.h>
#include <gl/freeglut.h>

#include <fstream>

#include "saveGLtoPPM.hpp"


#pragma comment(lib,"glew32.lib")


//ウィンドウの幅と高さ
int Width, Height;

GLuint buf_points;
GLuint buf_colors;

GLfloat mproj[16];
GLfloat mmodel[16];
GLuint programID;


// シェーダとデータの設定
void init() {

  std::vector<GLfloat> colors;
  std::vector<GLfloat> points;

  GLfloat v = 0.8;

  push_3(colors, 0, 0, 1);//色 RGB
  push_3(points, 0, 0, 0);//座標 XYZ

  push_3(colors, 0, 1, 0);
  push_3(points, 0, v, 0);

  push_3(colors, 1, 0, 0);
  push_3(points, v, 0, 0);

  prepare_buffer(&buf_points, points.data(), points.size() * sizeof(GLfloat), GL_STATIC_DRAW);
  prepare_buffer(&buf_colors, colors.data(), colors.size() * sizeof(GLfloat), GL_STATIC_DRAW);

  GLuint vtxShader;
  GLuint flagShader;

  const char* vtxfile = "default.vert";
  const char* fragfile = "default.frag";

  std::string verr;
  std::string ferr;
  prepare_shader_byfile(&vtxShader, GL_VERTEX_SHADER, vtxfile, &verr);
  prepare_shader_byfile(&flagShader, GL_FRAGMENT_SHADER, fragfile, &ferr);

  std::cout << verr << std::endl;
  std::cout << ferr << std::endl;

  std::string linkerr;
  link_program(&programID, { vtxShader ,flagShader }, nullptr, &linkerr);

  loadidentity44(mproj);
  loadidentity44(mmodel);
}

//描画関数
void disp(void) {

  glViewport(0, 0, Width, Height);

  glClearColor(0.2, 0.2, 0.2, 1);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glUseProgram(programID);
  GLuint loc_ModelViewMatrix = glGetUniformLocation(programID, "ModelViewMatrix");
  GLuint loc_ProjectionMatrix = glGetUniformLocation(programID, "ProjectionMatrix");


  glUniformMatrix4fv(loc_ModelViewMatrix, 1, GL_FALSE, mmodel);
  glUniformMatrix4fv(loc_ProjectionMatrix, 1, GL_FALSE, mproj);

  {

    auto bindbufP = EnableAndBindFArrayBuffer(0, buf_points, 3, GL_FLOAT);
    auto bindbufC = EnableAndBindFArrayBuffer(1, buf_colors, 3, GL_FLOAT);

    glDrawArrays(GL_TRIANGLES, 0, 3);

  }
  glFlush();

}


//ウィンドウサイズの変化時に呼び出される
void reshape(int w, int h) {
  Width = w;
  Height = h;

  disp();
}

// クリックでファイルに保存
void mouse(int button, int state, int x, int y) {
  saveGLtoPPM(
    Width, 
    Height, 
    R"(C:\test\a.ppm)");
}

//エントリポイント
int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitWindowPosition(100, 50);
  glutInitWindowSize(500, 500);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);


  glutCreateWindow("sample");
  glutDisplayFunc(disp);
  glutReshapeFunc(reshape);
  glutMouseFunc(mouse);

  glewInit();

  init();


  glutMainLoop();

  return 0;
}

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: