ビルボード

ビルボードです。
ビルボードというのは常に視点(カメラ)を向く板の事です。
古くは樹木や球のポリゴン数を減らすために用いられました。
現在では火花や雪などのパーティクルとして主に使用されます。
ビルボードにはビュー行列を逆行列にする方法もありますが、
今回はもっと簡単に実装できるやり方がありましたので紹介して
おきます。
3D空間のビルボードオブジェクトの中心位置を保存しておき、
glLoadIdentity(); して初期化します。
中心位置から画像サイズ分だけ+-してポリゴンを描画すると
行列計算なしでビルボードができます。

 

ファイル
main.cpp
lodepng.cpp
lodepng.h

tree.png

map.png

main.cpp

#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
#include <gl/glew.h>
#include <GL/freeglut/freeglut.h>
#include "lodepng.h"

#define WIDTH 320
#define HEIGHT 240

//赤
GLfloat red[] = { 1.0, 0.0, 0.0, 1.0 };
//回転用
float angleY=0.0f;
float angleX=0.0f;
bool flag=false;

class PNG{
public:
 LodePNG_Decoder decoder;
 unsigned char* buffer;
 unsigned char* image;
 size_t buffersize, imagesize;
 int Width,Height;
 GLuint texture;
 PNG(char* FileName);
 void DrawBillBoard(float x,float y,float z,float sizeX,float sizeY);
 void DrawPolygon(float x,float y,float z,float sizeX,float sizeY);
};
PNG::PNG(char* FileName)
{
 LodePNG_Decoder_init(&decoder);
 LodePNG_loadFile(&buffer, &buffersize, FileName);
 LodePNG_decode(&decoder, &image, &imagesize, buffer, buffersize);
 Width = decoder.infoPng.width;
 Height = decoder.infoPng.height;
 glGenTextures(1, &texture);
 glBindTexture(GL_TEXTURE_2D, texture);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}

void PNG::DrawBillBoard(float x,float y,float z,float sizeX,float sizeY)
{
 GLdouble v[16];
 glPushMatrix();
  glPushMatrix();
   glTranslated(x, y, z);
   glGetDoublev(GL_MODELVIEW_MATRIX, v);
  glPopMatrix();

  glLoadIdentity();

  glEnable(GL_TEXTURE_2D);
  glEnable( GL_TEXTURE_RECTANGLE_EXT );//拡張機能を使う
  glBindTexture( GL_TEXTURE_RECTANGLE_EXT, texture );
 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA,Width, Height, 0,GL_RGBA, GL_UNSIGNED_BYTE, image);
    glBegin(GL_POLYGON);
 
  glTexCoord2i(0, Height);   glVertex3d( v[12]-sizeX, v[13]-sizeY, v[14]);//左下
  glTexCoord2i(0, 0);      glVertex3d( v[12]-sizeX, v[13]+sizeY, v[14]);//左上
  glTexCoord2i(Width, 0);    glVertex3d( v[12]+sizeX, v[13]+sizeY, v[14]);//右上
  glTexCoord2i(Width, Height);glVertex3d( v[12]+sizeX, v[13]-sizeY, v[14]);//右下

  glEnd();

  glDisable( GL_TEXTURE_RECTANGLE_EXT );
  glDisable(GL_TEXTURE_2D);
glPopMatrix();
}

void PNG::DrawPolygon(float x,float y,float z,float sizeX,float sizeY)
{

  glEnable(GL_TEXTURE_2D);
  glEnable( GL_TEXTURE_RECTANGLE_EXT );//拡張機能を使う
  glBindTexture( GL_TEXTURE_RECTANGLE_EXT, texture );
 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA,Width, Height, 0,GL_RGBA, GL_UNSIGNED_BYTE, image);
    glBegin(GL_POLYGON);
 
  glTexCoord2i(0, Height);   glVertex3d( x+sizeX, y-3, z+sizeY);//左下
  glTexCoord2i(0, 0);      glVertex3d( x+sizeX, y-3, z-sizeY);//左上
  glTexCoord2i(Width, 0);    glVertex3d( x-sizeX, y-3, z-sizeY);//右上
  glTexCoord2i(Width, Height);glVertex3d( x-sizeX, y-3, z+sizeY);//右下

  glEnd();

  glDisable( GL_TEXTURE_RECTANGLE_EXT );
  glDisable(GL_TEXTURE_2D);
}

PNG *Map;
PNG *Tree;

// 初期化
void init(void)
{
  glClearColor(1.0, 1.0, 1.0, 1.0);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_BLEND);

  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  Map = new PNG("map.png");
  Tree = new PNG("tree.png");
}

void idle(void)
{
  if(flag){angleX-=0.1f;}else{angleX+=0.1f;}
  if(angleX>10.0f)flag=true;
  if(angleX<-10.0f)flag=false;
  angleY+=0.5f;
  Sleep(1);
  glutPostRedisplay();
}

 

// 画面表示
void display(void)
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glViewport(0, 0, WIDTH, HEIGHT);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 //視野角,アスペクト比(ウィンドウの幅/高さ),描画する範囲(最も近い距離,最も遠い距離)
 gluPerspective(30.0, (double)WIDTH / (double)HEIGHT, 1.0, 5000.0);
 glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
 //視点の設定
 gluLookAt(0.0,5.0,-50.0, //カメラの座標
      0.0,0.0,0.0, // 注視点の座標
     0.0,1.0,0.0); // 画面の上方向を指すベクトル

  glRotatef(angleY, 0.0, 1.0, 0.0);
  glRotatef(angleX, 1.0, 0.0, 1.0);

  glDisable(GL_LIGHTING);
  glDepthMask(GL_FALSE);

  Map->DrawPolygon(0.0,0.0,0.0,20.0,20.0);
  Tree->DrawBillBoard(0.0,0.0,10.0,3.0,3.0);
  Tree->DrawBillBoard(0.0,0.0,-10.0,3.0,3.0);
  Tree->DrawBillBoard(-10.0,0.0,0.0,3.0,3.0);
  Tree->DrawBillBoard(10.0,0.0,0.0,3.0,3.0);

  glDepthMask(GL_TRUE);
  glEnable(GL_LIGHTING);
  glutSwapBuffers();
}

int main(int argc, char *argv[])
{
 glutInitWindowPosition(100, 100);
 glutInitWindowSize(WIDTH, HEIGHT);
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
 glutCreateWindow("ビルボード");
 glutDisplayFunc(display);
 glutIdleFunc(idle);
 init();
 glutMainLoop();
 return 0;
}

 

 

 

 

 

 

 

最終更新:2015年02月22日 00:33