いてはここでは述べない11。
1
なお、よく見ると、図3.41の7号館は、図3.40の元画像の7号館よりもスリムに描画
2
されている。その理由は、元画像は600×459のやや横長の画像なのだが、それを縦横1:1
3
のテクスチャに張っているためである。
4
✓ ✏
#include <iostream>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#if defined(WIN32)
# pragma comment(lib, "glew32.lib")
# include "glew.h"
# include "glut.h"
# include "glext.h"
#elif defined(__APPLE__) || defined(MACOSX)
# include <GLUT/glut.h>
#else
# define GL_GLEXT_PROTOTYPES
# include <GL/glut.h>
#endif
struct Position2D { // 2次元座標 float x;
float y;
};
struct RGB { // RGB値 float r;
float g;
float b;
};
struct RGBA { // RGBA値 float r;
float g;
float b;
float a;
};
✒ ✑
図 3.42: 小まとめ:全体のヘッダー・ファイル(All.h、次ページへ続く)
✓ ✏ struct ArrayBuffer { //attribute変数配列
GLuint bufID;
int size;
ArrayBuffer(float* data, int s, int n);
};
struct Texture1D { // 1次元テクスチャ GLuint texID;
GLint num;
Texture1D(int tnum, void* data, int w);
};
struct Texture2D { // 2次元テクスチャ GLuint texID;
GLint num;
Texture2D(int tnum, void* data, int w, int h);
};
struct Shader { // シェーダー・オブジェクト GLuint program;
Shader(const char* vsn, const char* fsn);
void use();
void bindArrayBuffer(const char* vname, ArrayBuffer* ap);
void bindTexture(const char* vname, Texture1D* tp);
void bindTexture(const char* vname, Texture2D* tp);
void run(GLenum mode, int n);
GLuint compileProgram(GLenum type, const GLchar *file);
void buildProgram(const GLchar *vsfile, const GLchar *fsfile);
};
✒ ✑
図3.43: 小まとめ:全体のヘッダー・ファイル(All.h、前ページから続く)
✓ ✏ void initSystem(int argc, char *argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowSize(512,512);
glutCreateWindow("Test Window");
glClearColor(0.5,0.5,0.5,1);
//以下の2行はポイントスプライト用であり、削除してもよいが、残しておいても //大きな問題はない
glEnable(GL_POINT_SPRITE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
sp = new Shader("shader.vert","shader.frag");
sp->use();
✒} ✑
図3.44: 小まとめ:三角形ポリゴンを描画するinitSystem()
✓ ✏
void initData() {
Position2D pos[NUM_POINTS];
pos[0].x = -0.5; pos[0].y = -0.5;
pos[1].x = +0.5; pos[1].y = +0.5;
pos[2].x = +0.5; pos[2].y = -0.5;
ArrayBuffer ab((float*)pos,2,NUM_POINTS);
sp->bindArrayBuffer("position",&ab);
RGB rgb[NUM_POINTS];
rgb[0].r = 1.0; rgb[0].g = 1.0; rgb[0].b = 1.0;
rgb[1].r = 1.0; rgb[1].g = 0.0; rgb[1].b = 0.0;
rgb[2].r = 0.0; rgb[2].g = 1.0; rgb[2].b = 0.0;
ArrayBuffer ab2((float*)rgb,3,NUM_POINTS);
sp->bindArrayBuffer("in_color",&ab2);
//以下の行は線分用であり、削除してもよいが、残しておいても大きな問題はない glLineWidth(10.0);
✒} ✑
✓ ✏ void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
sp->run(GL_TRIANGLES,NUM_POINTS);
✒} ✑
図3.46: 小まとめ:三角形ポリゴンを描画するdisplay()
✓ ✏
int main(int argc, char *argv[]) {
initSystem(argc,argv);
initData();
glutDisplayFunc(display);
glutMainLoop();
return 0;
✒} ✑
図 3.47: 小まとめ:三角形ポリゴンを描画するmain()(この関数には一貫して全く変更 を加えていないが、プログラム全体の理解のために載せる)
✓ ✏
#version 120
attribute vec2 position;
attribute vec3 in_color;
varying vec3 out_color;
void main(void) {
gl_Position = vec4(position,0.0,1.0);
out_color = in_color;
✒} ✑
図3.48: 小まとめ:三角形ポリゴンを描画するバーテックスシェーダープログラム
✓ ✏
#version 120
varying vec3 out_color;
void main(void) {
gl_FragColor = vec4(out_color, 0.0);
✒} ✑
図3.49: 小まとめ:三角形ポリゴンを描画するフラグメントシェーダープログラム
GPUによる描画処理では多数のバーテックスシェーダーおよび多数のフラグメントシェー
2
ダーが並列実行する。しかもシェーダープログラムはプログラミング可能であるから、そ
3
れをうまく活用すれば描画に限らず様々な並列計算ができるのではないかと期待できる。
4
ここで述べるテクスチャとフラグメントシェーダーを用いる並列計算はその自由度が高
5
く、CUDAやOpenCLにおける計算方法の先駆けになった。
6
テクスチャは全てのシェーダープログラムから共通に参照可能な配列のように見える。特
7
にテクスチャからRGBA値を取得する(サンプリングする)方法を線形補間(GL LINEAR)
8
ではなく、最近傍(GL NEAREST)に設定する場合には、テクスチャ内の個々の生のRGBA
9
値をそのまま読み出すことができるため、配列要素を読み出すイメージに非常に近い。
10
前章のテクスチャデータをは読み出し専用であるが、もしテクスチャへデータを書き込
11
むことができるならば、配列要素データを読み込み、配列要素へデータを書き込む一連の
12
操作ができる訳であるから、2次元配列のデータ並列演算ができるだろうことは想像に難
13
くない。実際、可能である。テクスチャへの書き込みは、元々はより高度な3D CGを実
14
装するため1に導入されたのだが、これを用いれば任意のデータ並列演算ができることに
15
気づいた研究者に利用されるようになっていく。その演算性能が圧倒的であったため、そ
16
の後、CUDAやOpenCLなどのGPGPU専用のプログラミング環境が開発された。
17
この章ではGPGPU草創期のOpenGLによるデータ並列計算の方法を振り返る。
18