CDR6275

Michio SHIRAISHI Official Site


OpenGL 4.1とOpenGL ES SL 1.0で学ぶ3次元コンピュータグラフィックス

東邦大学理学部情報科学科 白石路雄
最終更新: 2014年2月20日

3. ポリゴンモデル

 2章では、1つの三角形を描いてきました。3次元の形状モデルは三角形の集まりとして表されていますので、複数の三角形を描く方法について述べます。

3.2 内部が塗りつぶされた五角形を描く

 さて、前節で五角形の頂点を表示できるようになったところで、次に五角形の内部を塗りつぶす方法について考えてみましょう。五角形を3つの三角形に分割しますから、1つの三角形につき3頂点あることを考えると、頂点の数は全部で9つになります。1つの頂点は3つの3次元座標で表されますから、全部で27個からなる配列が必要になります。したがって、次のようなプログラムになります。

#include <iostream>

#define _USE_MATH_DEFINES
#include <math.h>

#include "PentagonFill.h"
#include "SimpleProgramObject.h"
#include "Matrix.h"

enum
{
  ATTRIBUTE_VERTEX_COORDINATE,
  NUM_ATTRIBUTES
};

enum
{
  UNIFORM_PROJECTION_MATRIX,
  UNIFORM_VIEW_MATRIX,
  NUM_UNIFORMS
};
GLint uniforms[NUM_UNIFORMS];

bool PentagonFill::initialize(){
#if !TARGET_OS_IPHONE
  BaseApplication::initializeWindow(640, 640, "PentagonFill");
#endif

  // 五角形の頂点座標
  float pentagonVertices[3*5];
  for(int i=0; i<5; i++){
    pentagonVertices[3*i+0] = 0.8f * (float)cos(i*M_PI*2.0/5.0);
    pentagonVertices[3*i+1] = 0.8f * (float)sin(i*M_PI*2.0/5.0);
    pentagonVertices[3*i+2] = 0.0f;
  }
  
  // 3つの三角形の頂点座標
  float faceVertexCoordinates[3*3*3];
  
  // 三角形P_0, P_1, P_2
  faceVertexCoordinates[0]  = pentagonVertices[3*0+0];
  faceVertexCoordinates[1]  = pentagonVertices[3*0+1];
  faceVertexCoordinates[2]  = pentagonVertices[3*0+2];
  faceVertexCoordinates[3]  = pentagonVertices[3*1+0];
  faceVertexCoordinates[4]  = pentagonVertices[3*1+1];
  faceVertexCoordinates[5]  = pentagonVertices[3*1+2];
  faceVertexCoordinates[6]  = pentagonVertices[3*2+0];
  faceVertexCoordinates[7]  = pentagonVertices[3*2+1];
  faceVertexCoordinates[8]  = pentagonVertices[3*2+2];
  // 三角形P_0, P_2, P_3
  faceVertexCoordinates[9]  = pentagonVertices[3*0+0];
  faceVertexCoordinates[10] = pentagonVertices[3*0+1];
  faceVertexCoordinates[11] = pentagonVertices[3*0+2];
  faceVertexCoordinates[12] = pentagonVertices[3*2+0];
  faceVertexCoordinates[13] = pentagonVertices[3*2+1];
  faceVertexCoordinates[14] = pentagonVertices[3*2+2];
  faceVertexCoordinates[15] = pentagonVertices[3*3+0];
  faceVertexCoordinates[16] = pentagonVertices[3*3+1];
  faceVertexCoordinates[17] = pentagonVertices[3*3+2];
  // 三角形P_0, P_3, P_4
  faceVertexCoordinates[18] = pentagonVertices[3*0+0];
  faceVertexCoordinates[19] = pentagonVertices[3*0+1];
  faceVertexCoordinates[20] = pentagonVertices[3*0+2];
  faceVertexCoordinates[21] = pentagonVertices[3*3+0];
  faceVertexCoordinates[22] = pentagonVertices[3*3+1];
  faceVertexCoordinates[23] = pentagonVertices[3*3+2];
  faceVertexCoordinates[24] = pentagonVertices[3*4+0];
  faceVertexCoordinates[25] = pentagonVertices[3*4+1];
  faceVertexCoordinates[26] = pentagonVertices[3*4+2];
  
  
  SimpleProgramObject programObject;
  const char* vertexShaderFileName = "first.vs";
  const char* fragmentShaderFileName = "first.fs";
  
  program = programObject.createProgram(vertexShaderFileName, fragmentShaderFileName, shaderSearchPath);

  // シェーダコード内の変数にインデックスを設定する
  glBindAttribLocation(program, ATTRIBUTE_VERTEX_COORDINATE, "vertexCoordinate");
  
  programObject.linkProgram();
  
  // 頂点配列オブジェクトを作成して設定する
#if TARGET_OS_IPHONE
  glGenVertexArraysOES(1, &vertexArrayObject);
  glBindVertexArrayOES(vertexArrayObject);
#else
  glGenVertexArrays(1, &vertexArrayObject);
  glBindVertexArray(vertexArrayObject);
#endif
  
  // 頂点バッファオブジェクトを作成する
  glGenBuffers(1, &vertexBufferObject);
  glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
  glBufferData(GL_ARRAY_BUFFER, sizeof(float)*27, faceVertexCoordinates, GL_STATIC_DRAW);
  
  // 頂点バッファオブジェクトにシェーダ内の変数vertexCoodrinateを結びつける
  glEnableVertexAttribArray(ATTRIBUTE_VERTEX_COORDINATE);
  glVertexAttribPointer(ATTRIBUTE_VERTEX_COORDINATE, 3, GL_FLOAT, GL_FALSE, sizeof(float)*3, 0);
  
  // 背景色の設定
  glClearColor(0.75f, 0.75f, 0.75f, 1.0f);
  
  return true;
}

void PentagonFill::update(){
  
}

void PentagonFill::draw(){
#if TARGET_OS_IPHONE
  int viewport[4];
  glGetIntegerv(GL_VIEWPORT, viewport);
  glViewport(0, (viewport[3]-viewport[2])/2, viewport[2], viewport[2]);
#endif
  // 背景のクリア
  glClear(GL_COLOR_BUFFER_BIT);
  // 使用するプログラムオブジェクトをする
  glUseProgram(program);
  // 三角形を描く
  glDrawArrays(GL_TRIANGLES, 0, 3*3);
  // 使用するプログラムオブジェクトを解除する
  glUseProgram(0);
#if _WIN32 || (TARGET_OS_MAC && !TARGET_OS_IPHONE)
  // バッファの入れ替え
  glfwSwapBuffers(window);
  // イベントの取得
  glfwPollEvents();
#endif
}

 実行結果は次のようになります。

pentagon-fill

 できた、とは言え、9個の頂点の座標を与えるのは、無駄が多いです。0番目の頂点と1番目の頂点と2番目の頂点を結ぶ三角形というように指定したいところです。この方法については次に述べます。