スポンサーリンク

OpenGLで常に正面を向いた簡単な円を描く

球を模倣したい。wireframeなsphereだと表示が鬱陶しくなったりするので円で代用したいような場合に用いる。

今回のプログラムは前回のものに付け足すのでdrawcircle.hppをincludeする。なおbbはbillboardの意。

ソースコード

円を描く関数(drawcircle_bb.hpp)

//! @file drawcircle_bb.hpp
#pragma once
#include "drawcircle.hpp"

//! @brief カメラ行列から視線方向に対して垂直で画面右向きのベクトルを取得する
//! @param [out] v3 結果を格納する三次元ベクトル 要素数3
//! @param [in] cameraModelView カメラ行列
//! @return なし
inline void getRayRightFromCamera(double* v3, double* cameraModelView) {
  v3[0] = cameraModelView[0];
  v3[1] = cameraModelView[4];
  v3[2] = cameraModelView[8];
}

//! @brief カメラ行列から視線方向に対して垂直で画面上向きのベクトルを取得する
//! @param [out] v3 結果を格納する三次元ベクトル 要素数3
//! @param [in] cameraModelView カメラ行列
//! @return なし
inline void getRayUpFromCamera(double* v3, double* cameraModelView) {
  v3[0] = cameraModelView[1];
  v3[1] = cameraModelView[5];
  v3[2] = cameraModelView[9];
};

//! @brief 常に正面を向いた円を描く
//! @param [in] x 中心座標
//! @param [in] y 中心座標
//! @param [in] z 中心座標
//! @param [in] r 半径
//! @param [in] count 分割数 4 ぐらいがとりあえず適当
//! @param [in] カメラ行列。nullptrを指定した場合はglGetDoublevでOpenGLから取り出す
//! @return なし
inline void circle_xy_bb(double x, double y, double z, double r, const int count,double* cameramatrix=nullptr) {

  coord_t center(x, y, z);

  double vr[3];
  double vu[3];


  //モデルビュー行列から四角形の頂点を取り出す
  if (cameramatrix == nullptr) {
    double model[16];
    glGetDoublev(GL_MODELVIEW_MATRIX, model);
    getRayRightFromCamera(vr, model);
    getRayUpFromCamera(vu, model);
  }
  else {
    getRayRightFromCamera(vr, cameramatrix);
    getRayUpFromCamera(vu, cameramatrix);
  }

  double a[3] = { vr[0], vr[1], vr[2] };
  double b[3] = { vu[0],vu[1], vu[2] };
  double c[3] = {-vr[0],-vr[1], -vr[2] };
  double d[3] = {-vu[0],-vu[1], -vu[2] };


  coord_t p[4];
  p[0] = coord_t(a);
  p[1] = coord_t(b);
  p[2] = coord_t(c);
  p[3] = coord_t(d);

  glBegin(GL_LINE_LOOP);
  for (int i = 0; i < 4; i++) {

    int ia = i % 4;
    int ic = (i + 1) % 4;

    coord_t a(p[ia].x, p[ia].y, p[ia].z);
    coord_t c(p[ic].x, p[ic].y, p[ic].z);
    plot_ab(center, count, r, a, c);
  }
  glEnd();
}

呼び出しサンプル

#include <iostream>
#include <Windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <gl/freeglut.h>

#include <cassert>

// freeglut:
// http://freeglut.sourceforge.net/

//矢印描画関数
#include "drawarrow.hpp"
//円描画関数
#include "drawcircle.hpp"
#include "drawcircle_bb.hpp"


//ウィンドウの幅と高さ
int width, height;

double rotate_angle = 0;


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

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

  glEnable(GL_DEPTH_TEST);

  glViewport(0, 0, width, height);

  //カメラの設定
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60, width / (double)height, 0.1, 3);
  glMatrixMode(GL_MODELVIEW);

  glLoadIdentity();

  glTranslated(0, 0, -2);

  //表示用の回転
  glRotated(rotate_angle, 0, 1, 0);
  glRotated(rotate_angle, 1, 0, 0);

  //表示用に全体を少しずらす
  glTranslated(0, 0.2, 0.2);

  //矢印を三つ描画
  
  glLineWidth(2);
  double center[3] = { 0.3,0,0 };
  double tox[3] = { 1 + center[0],0 + center[1],0 + center[2] };
  double toy[3] = { 0 + center[0],1 + center[1],0 + center[2] };
  double toz[3] = { 0 + center[0],0 + center[1],1 + center[2] };
  glColor3d(1, 0, 0);
  drawArrow(center, tox);
  glColor3d(0, 1, 0);
  drawArrow(center, toy);
  glColor3d(0, 0, 1);
  drawArrow(center, toz);
  glLineWidth(1);

  //////////////////////////////////////
  //円を描画
  glLineWidth(3);
  glColor3d(1, 1, 0);
  circle_xy(center[0], center[1], center[2], 0.5, 3);
  glColor3d(0, 1, 1);
  circle_xy_bb(center[0], center[1], center[2], 0.5, 3,nullptr);

  glFlush();
}

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

  disp();
}

void timer(int value)
{
  rotate_angle += 5;

  disp();
  glutTimerFunc(100, timer, 0);
}

//エントリポイント
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);
  glutTimerFunc(1000, timer, 0);//タイマー
  glutMainLoop();

  return 0;
}

コメントを残す

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

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


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