必要なときにコピペするためのもの. ---- #contents ---- *描画関数 [#r8efd250] ***グリッド描画 [#xb859bb1] #code(C){{ /*! * グリッド描画(x-y軸平面) * @param[in] d 分割数 * @param[in] x,y グリッド全体のside length * @param[in] h グリッドの高さ */ static int DrawGroundGrid(int d, double x, double y, double h) { glPushMatrix(); glDisable(GL_LIGHTING); glColor3f(1,0,0); glLineWidth(6.0); glBegin(GL_LINE_LOOP); glVertex3d(-x, y, h); glVertex3d( x, y, h); glVertex3d( x, -y, h); glVertex3d(-x, -y, h); glEnd(); glLineWidth(3.0); // x方向 float x0, x1, y0, y1; float deltaX, deltaY; x0 = -x; x1 = -x; y0 = -y; y1 = y; deltaX = (2*x)/d; for(int i = 0; i < d; ++i){ x0 = x0 + deltaX; glBegin(GL_LINES); glVertex3f(x0, y0, h); glVertex3f(x0, y1, h); glEnd(); } // y方向 x0 = -x; x1 = x; deltaY = (2*y)/d; for(int i = 0; i < d; ++i){ y0 = y0 + deltaY; glBegin(GL_LINES); glVertex3f(x0, y0, h); glVertex3f(x1, y0, h); glEnd(); } glLineWidth(1.0); glPopMatrix(); return 0; } }} ***ポリゴン描画 [#x93b90cd] rxMaterialは下の材質クラスを参照. #code(C){{ /*! * 単一ポリゴンの描画 * @param[in] verts 頂点座標格納コンテナ * @param[in] index 頂点位相 * @param[in] norm ポリゴン法線 * @param[in] color 描画色 */ inline void DrawPolygon(const vector<Vec3> &verts, const vector<int> &index, const Vec3 &color) { glBegin(GL_POLYGON); glColor3f(color[0], color[1], color[2]); for(int i = 0; i < (int)index.size(); ++i){ glVertex3dv(verts[index[i]-1].data); } glEnd(); } /*! * OpenGLによるグローシェーディングで単一ポリゴン描画 * @param[in] poly ポリゴン * @param[in] color 描画色 */ inline void DrawPolygonGouraud(const vector<Vec3> &verts, const vector<int> &index, const vector<Vec3> &norms, const Vec3 &color) { Vec3 norm; Vec3 vert; glColor3f(color[0], color[1], color[2]); glBegin(GL_POLYGON); for(int i = 0; i < (int)index.size(); ++i){ glNormal3dv(norms[index[i]-1].data); glVertex3dv(verts[index[i]-1].data); } glEnd(); } /*! * OpenGLによるグローシェーディングで複数ポリゴン描画(ポリゴン法線) * @param[in] polys ポリゴンを格納したコンテナ * @param[in] gmat 全体の材質 */ static void DrawPolygons(const vector<Vec3> &vrts, const vector< vector<int> > &idxs, rxMaterial *gmat, bool select) { int i; rxMaterial *mat; for(i = 0; i < (int)idxs.size(); ++i){ if(gmat == NULL){ mat = &g_matDefault; } else{ mat = gmat; } if(select) glLoadName(i); mat->SetGL(); glEnable(GL_LIGHTING); DrawPolygon(vrts, idxs[i], mat->GetDiff3()); } } /*! * OpenGLによるグローシェーディングで複数ポリゴン描画(頂点法線) * @param[in] polys ポリゴンを格納したコンテナ * @param[in] gmat 全体の材質 */ static void DrawPolygonsGouraud(const vector<Vec3> &vrts, const vector< vector<int> > &idxs, const vector<Vec3> &nrms, rxMaterial *gmat, bool select) { int i; rxMaterial *mat; for(i = 0; i < (int)idxs.size(); ++i){ if(gmat == NULL){ mat = &g_matDefault; } else{ mat = gmat; } if(select) glLoadName(i); mat->SetGL(); glEnable(GL_LIGHTING); DrawPolygonGouraud(vrts, idxs[i], nrms, mat->GetDiff3()); } } }} ***傾いた直方体描画 [#e72399ce] glRotate使用版 #code(C){{ /*! * cenを中心で辺の長さがlen,dirの方向を向いた直方体の描画 * @param[in] cen 直方体の中心 * @param[in] len 直方体の辺の長さ(x,y,z) * @param[in] dir 直方体のx軸の向き */ inline void DrawSolidCuboid(Vec3 cen, Vec3 len, Vec3 dir) { Vec3 org_axis(1.0, 0.0, 0.0); Vec3 tgt_axis = Unit(dir); Vec3 rot_axis = Unit(cross(org_axis, tgt_axis)); double rot_angle = acos((double)(dot(org_axis, tgt_axis))); glPushMatrix(); glTranslatef(cen[0], cen[1], cen[2]); glRotatef(RX_TO_DEGREES(rot_angle), rot_axis[0], rot_axis[1], rot_axis[2]); DrawSolidCuboid(Vec3(0.0), len); glPopMatrix(); } }} コーナー座標値算出版 #code(C){{ /*! * cenを中心で辺の長さがlen,dirの方向を向いた直方体の描画 * @param[in] cen 直方体の中心 * @param[in] len 直方体の辺の長さ(x,y,z) * @param[in] dir 直方体のx軸の向き */ inline void DrawSolidCuboid(Vec3 cen, Vec3 len, Vec3 dir) { len *= 0.5; dir = Unit(dir); Vec3 up(0.0, 1.0, 0.0); Vec3 right = cross(dir, up); Vec3 nc = cen-dir*len[0]; Vec3 fc = cen+dir*len[0]; right = Unit(right); up = Unit(cross(right, dir)); Vec3 corner[8]; corner[0] = nc-up*len[1]-right*len[2]; corner[1] = nc+up*len[1]-right*len[2]; corner[2] = nc+up*len[1]+right*len[2]; corner[3] = nc-up*len[1]+right*len[2]; corner[4] = fc-up*len[1]-right*len[2]; corner[5] = fc+up*len[1]-right*len[2]; corner[6] = fc+up*len[1]+right*len[2]; corner[7] = fc-up*len[1]+right*len[2]; int index[6][4] = { { 3, 2, 1, 0 }, { 4, 5, 6, 7 }, { 3, 0, 4, 7 }, { 1, 2, 6, 5 }, { 0, 1, 5, 4 }, { 2, 3, 7, 6 } }; glPushMatrix(); glBegin(GL_QUADS); // 前後面 glNormal3dv((-dir).data); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[0][i]].data); glNormal3dv(dir.data); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[1][i]].data); // 上下側面 glNormal3dv((-up).data); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[2][i]].data); glNormal3dv(up.data); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[3][i]].data); // 左右側面 glNormal3dv((-right).data); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[4][i]].data); glNormal3dv(right.data); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[5][i]].data); glEnd(); glPopMatrix(); } }} ***直方体描画 [#c7cf7534] #code(C){{ /*! * cenを中心で辺の長さがlenの直方体の描画 * @param[in] cen 直方体の中心 * @param[in] len 直方体の辺の長さ(x,y,z) */ inline void DrawSolidCuboid(Vec3 &cen, Vec3 len) { len *= 0.5; Vec3 corner[8]; corner[0] = cen+Vec3(-len[0], -len[1], -len[2]); corner[1] = cen+Vec3(-len[0], len[1], -len[2]); corner[2] = cen+Vec3(-len[0], len[1], len[2]); corner[3] = cen+Vec3(-len[0], -len[1], len[2]); corner[4] = cen+Vec3( len[0], -len[1], -len[2]); corner[5] = cen+Vec3( len[0], len[1], -len[2]); corner[6] = cen+Vec3( len[0], len[1], len[2]); corner[7] = cen+Vec3( len[0], -len[1], len[2]); int index[6][4] = { { 3, 2, 1, 0 }, { 4, 5, 6, 7 }, { 3, 0, 4, 7 }, { 1, 2, 6, 5 }, { 0, 1, 5, 4 }, { 2, 3, 7, 6 } }; glPushMatrix(); glBegin(GL_QUADS); // x軸に垂直な面 glNormal3d(-1.0, 0.0, 0.0); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[0][i]].data); glNormal3d( 1.0, 0.0, 0.0); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[1][i]].data); // y軸に垂直な面 glNormal3d(0.0, -1.0, 0.0); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[2][i]].data); glNormal3d(0.0, 1.0, 0.0); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[3][i]].data); // z軸に垂直な面 glNormal3d(0.0, 0.0, -1.0); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[4][i]].data); glNormal3d(0.0, 0.0, 1.0); for(int i = 0; i < 4; ++i) glVertex3dv(corner[index[5][i]].data); glEnd(); glPopMatrix(); } }} ***立方体描画(ディスプレイリスト使用) [#e72399ce] vector<Vec3>は配列にした方が効率がよいかも.scaleやwireは最初の描画時に指定した値が反映される. #code(C){{ static void DrawCube(double scale = 0.5, bool wire = false) { using namespace boost::assign; static GLuint polyList = 0; vector<Vec3> vrts, cols; vrts += Vec3( 1.0, 1.0, 1.0), \ Vec3( 1.0, -1.0, 1.0), \ Vec3(-1.0, -1.0, 1.0), \ Vec3(-1.0, 1.0, 1.0), \ Vec3( 1.0, 1.0, -1.0), \ Vec3( 1.0, -1.0, -1.0), \ Vec3(-1.0, -1.0, -1.0), \ Vec3(-1.0, 1.0, -1.0); cols += Vec3(1.0, 1.0, 1.0), \ Vec3(1.0, 1.0, 0.0), \ Vec3(0.0, 1.0, 0.0), \ Vec3(0.0, 1.0, 1.0), \ Vec3(1.0, 0.0, 1.0), \ Vec3(1.0, 0.0, 0.0), \ Vec3(0.0, 0.0, 0.0), \ Vec3(0.0, 0.0, 1.0); const short faces[6][4] = { {3, 2, 1, 0}, {2, 3, 7, 6}, {0, 1, 5, 4}, {3, 0, 4, 7}, {1, 2, 6, 5}, {4, 5, 6, 7} }; GLint num_faces = 6; if(!polyList){ polyList = glGenLists(1); glNewList(polyList, GL_COMPILE); if(!wire){ glBegin(GL_QUADS); for(int f = 0; f < num_faces; ++f){ for(int i = 0; i < 4; ++i){ glColor3dv(cols[faces[f][i]].data); glVertex3dv((vrts[faces[f][i]]*scale).data); } } glEnd(); } glColor3f(0.0, 0.0, 0.0); for(int f = 0; f < num_faces; ++f){ glBegin(GL_LINE_LOOP); for(int i = 0; i < 4; ++i){ glVertex3dv((vrts[faces[f][i]]*scale).data); } glEnd(); } glEndList(); } glPushMatrix(); glCallList(polyList); glPopMatrix(); } }} ***円筒描画 [#e43fca86] DrawCylinderは円筒,DrawCapsuleは両端が半球状の円筒. #code(C){{ /*! * 円筒描画 * @param[in] rad,len 半径と中心軸方向長さ * @param[in] axis 軸方向 * @param[in] slices ポリゴン近似する際の分割数 */ static void DrawCylinder(double rad, double len, int axis, int slices) { GLUquadricObj *qobj; qobj = gluNewQuadric(); glPushMatrix(); switch(axis){ case 0: glRotatef(-90.0, 0.0, 1.0, 0.0); glTranslatef(0.0, 0.0, -0.5*len); break; case 1: glRotatef(-90.0, 1.0, 0.0, 0.0); glTranslatef(0.0, 0.0, -0.5*len); break; case 2: glTranslatef(0.0, 0.0, -0.5*len); break; default: glTranslatef(0.0, 0.0, -0.5*len); } gluQuadricDrawStyle(qobj, GLU_FILL); gluQuadricNormals(qobj, GLU_SMOOTH); gluCylinder(qobj, rad, rad, len, slices, slices); glPushMatrix(); glRotatef(180.0, 1.0, 0.0, 0.0); gluDisk(qobj, 0.0, rad, slices, slices); glPopMatrix(); glPushMatrix(); glTranslatef(0.0, 0.0, len); gluDisk(qobj, 0.0, rad, slices, slices); glPopMatrix(); glPopMatrix(); } /*! * カプセル描画(円筒の両端に半球をつけた形) * @param[in] rad,len 半径と中心軸方向長さ * @param[in] axis 軸方向 * @param[in] slices ポリゴン近似する際の分割数 */ static void DrawCapsule(double rad, double len, int axis, int slices) { GLUquadricObj *qobj; qobj = gluNewQuadric(); glPushMatrix(); switch(axis){ case 0: glRotatef(-90.0, 0.0, 1.0, 0.0); glTranslatef(0.0, 0.0, -0.5*len); break; case 1: glRotatef(-90.0, 1.0, 0.0, 0.0); glTranslatef(0.0, 0.0, -0.5*len); break; case 2: glTranslatef(0.0, 0.0, -0.5*len); break; default: glTranslatef(0.0, 0.0, -0.5*len); } gluQuadricDrawStyle(qobj, GLU_FILL); gluQuadricNormals(qobj, GLU_SMOOTH); gluCylinder(qobj, rad, rad, len, slices, slices); glPushMatrix(); glutSolidSphere(rad, slices, slices); glPopMatrix(); glPushMatrix(); glTranslatef(0.0, 0.0, len); glutSolidSphere(rad, slices, slices); glPopMatrix(); glPopMatrix(); } }} ワイヤフレーム描画時に不自然にならないように両端の球をちゃんと半球として描画したい場合. #code(C){{ /*! * カプセル描画(円筒の両端に半球をつけた形) * - ワイヤフレーム描画時に不自然にならないように両端の球を半球として描画 * @param[in] rad,len 半径と中心軸方向長さ * @param[in] axis 軸方向 * @param[in] slices ポリゴン近似する際の分割数 */ void DrawCapsule(double rad, double len, int axis, int slices) { GLUquadricObj *qobj; qobj = gluNewQuadric(); glPushMatrix(); switch(axis){ case 0: glRotatef(-90.0, 0.0, 1.0, 0.0); glTranslatef(0.0, 0.0, -0.5*len); break; case 1: glRotatef(-90.0, 1.0, 0.0, 0.0); glTranslatef(0.0, 0.0, -0.5*len); break; case 2: glTranslatef(0.0, 0.0, -0.5*len); break; default: glTranslatef(0.0, 0.0, -0.5*len); } gluQuadricDrawStyle(qobj, GLU_FILL); gluQuadricNormals(qobj, GLU_SMOOTH); gluCylinder(qobj, rad, rad, len, slices, slices); double c_init[4] = {0, 0, 0, 0}; double c_bottom[4] = {0, 0, -1, 0}; double c_top[4] = {0, 0, 1, 0}; glEnable(GL_CLIP_PLANE0); glPushMatrix(); glClipPlane(GL_CLIP_PLANE0, c_bottom); glutSolidSphere(rad, slices, slices); glPopMatrix(); glPushMatrix(); glTranslatef(0.0, 0.0, len); glClipPlane(GL_CLIP_PLANE0, c_top); glutSolidSphere(rad, slices, slices); glPopMatrix(); glClipPlane(GL_CLIP_PLANE0, c_init); glDisable(GL_CLIP_PLANE0); glPopMatrix(); } }} GLUを使わないで円筒を描画する場合. z軸平行で描画される. #code(C){{ /*! * 円筒形の描画(z軸平行,底面が原点) * @param[in] r 円筒半径 * @param[in] h 返答長さ * @param[in] slice 円の分割数 * @param[in] stack 長さ方向の分割数 */ void DrawCylinder(double r, double h, int slice) { double theta = 2.0*RX_PI/(double)slice; double n_norm; Vec3 origin = Vec3(0.0); vector<Vec3> vert; vert.resize(slice); Vec3 normal; glPushMatrix(); // 天面の描画(y = cen[1]+h) glNormal3f(0.0, 1.0, 0.0); glBegin(GL_POLYGON); for(int i = 0; i < slice; ++i){ vert[i][0] = origin[0]+r*sin(theta*(double)i); vert[i][1] = origin[1]+r*cos(theta*(double)i); vert[i][2] = origin[2]+h; glVertex3f(vert[i][0], vert[i][1], vert[i][2]); } glEnd(); // 底面の描画(y = cen[1]) glNormal3f(0.0, -1.0, 0.0); glBegin(GL_POLYGON); for(int i = 0; i < slice; ++i){ vert[i][2] = origin[2]; glVertex3f(vert[i][0], vert[i][1], vert[i][2]); } glEnd(); // 側面の描画 glBegin(GL_QUAD_STRIP); int j; for(int i = 0; i < slice; ++i){ j = (i+1)%slice; normal = 0.5*(vert[i]+vert[j]); normal = origin-normal; n_norm = norm(normal); if(n_norm > RX_EPS) normal /= n_norm; glNormal3f(normal[0], normal[1], normal[2]); glVertex3f(vert[i][0], vert[i][1], vert[i][2]); glVertex3f(vert[i][0], vert[i][1], vert[i][2]+h); } glVertex3f(vert[j][0], vert[j][1], vert[j][2]); glVertex3f(vert[j][0], vert[j][1], vert[j][2]+h); glEnd(); glPopMatrix(); } }} ***キューブマップ描画 [#j8bc13ff] #code(C){{ /*! * キューブマップテクスチャを内部に貼り付けた立方体の描画 * @param[in] cube_map キューブマップ * @param[in] side 立方体の一辺の長さ */ void RxGLDraw::DrawCubeMap(GLuint cube_map, double side) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_CULL_FACE); // キューブマップテクスチャをバインド glEnable(GL_TEXTURE_CUBE_MAP); glBindTexture(GL_TEXTURE_CUBE_MAP, cube_map); // GL_OBJECT_LINEARテクスチャ座標を設定 glPushMatrix(); GLfloat s_plane[] = { 1.0, 0.0, 0.0, 0.0 }; GLfloat t_plane[] = { 0.0, 1.0, 0.0, 0.0 }; GLfloat r_plane[] = { 0.0, 0.0, 1.0, 0.0 }; glTexGenfv(GL_S, GL_OBJECT_PLANE, s_plane); glTexGenfv(GL_T, GL_OBJECT_PLANE, t_plane); glTexGenfv(GL_R, GL_OBJECT_PLANE, r_plane); glPopMatrix(); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); // シーンを覆う大きさの立方体を描画 glPushMatrix(); glutSolidCube(side); glPopMatrix(); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_GEN_R); glBindTexture(GL_TEXTURE_CUBE_MAP, 0); glDisable(GL_TEXTURE_CUBE_MAP); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); } }} ***矢印描画 [#j5da7c54] 2Dの場合 #code(C){{ /*! * 矢印の描画 * @param[in] s 矢印の始点 * @param[in] e 矢印の始点 * @param[in] scale 傘の部分の大きさ(全体の長さに対する係数) */ inline static void DrawArrow2D(const Vec2 &s, const Vec2 &e, double scale = 0.2) { // 始点,方向,長さ Vec2 origin = s; Vec2 dir = e-s; double length = normalize(dir); // ベクトル(1,0)との間の角度 double theta = 180.0/RX_PI*acos(dot(Vec2(1, 0), dir))*RX_SIGN(dir[1]); // 矢印の傘部分の設定 double arrow_x = scale*length; // 軸方向の長さ //double arrow_y = arrow_x*0.174532925; // 軸に垂直な方向の開き量(傘の開き角度20deg) double arrow_y = arrow_x*0.363970234; // 軸に垂直な方向の開き量(傘の開き角度40deg) glPushMatrix(); glTranslatef(origin[0], origin[1], 0.0); // 矢印原点に移動 glRotatef(theta, 0.0, 0.0, 1.0); // 矢印方向に回転(z軸中心) glBegin(GL_LINES); // 軸 glVertex2d(0.0, 0.0); glVertex2d(length, 0.0); // 傘 glVertex2d(length, 0.0); glVertex2d(length-arrow_x, arrow_y); glVertex2d(length, 0.0); glVertex2d(length-arrow_x, -arrow_y); glEnd(); glPopMatrix(); } }} 3Dの場合(3DベクトルクラスVec3と上の円筒描画,下の任意ベクトル周りの回転の関数を使用). #code(C){{ /*! * ベクトルを矢印で描画 * @param[in] pos 原点座標 * @param[in] vec ベクトル * @param[in] r 軸の半径 * @param[in] dr 矢印の傘部分の半径(軸の半径を1としたときの割合) * @param[in] dl 矢印の傘部分の長さ(全体の長さを1としたときの割合) [0,1] */ void DrawArrow(Vec3 pos, Vec3 vec, double r, double dr = 2.5, double dl = 0.1) { double vlen = norm(vec); Vec3 pos1 = pos+vec*(1.0-dl*0.5); Vec3 init = Vec3(0.0, 0.0, 1.0); // 円筒と円錐描画はデフォルトでz軸平行 // vecとz軸の間の回転角度と回転軸 double rot_ang = acos(dot(init, Unit(vec)))*57.295779513082320876798154814114; Vec3 rot_axis = Unit(cross(init, Unit(vec))); glPushMatrix(); glTranslatef(pos[0], pos[1], pos[2]); // 原点に移動 glRotatef(rot_ang, rot_axis[0], rot_axis[1], rot_axis[2]); // vec方向に座標系を回転 // ベクトルの軸部分 DrawCylinder(r, vlen*(1.0-dl*0.5), 16); // ベクトルの傘部分 double alen = dl*vlen; // 円錐の高さ double arad = dr*r; // 円錐の半径 pos1 = pos+vec; glTranslatef(0.0, 0.0, vlen-alen); glutSolidCone(arad, alen, 16, 16); glPopMatrix(); } }} ***文字描画 [#f4c43bc4] #code{{ /*! * 文字列描画 * @param[in] static_str 文字列 * @param[in] w,h ウィンドウサイズ */ static void DrawStrings(vector<string> &static_str, int w, int h) { glDisable(GL_LIGHTING); // 平行投影にする glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, w, 0, h); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); float x0 = 5.0f; float y0 = h-20.0f; // 画面上部にテキスト描画 for(int j = 0; j < (int)static_str.size(); ++j){ glRasterPos2f(x0, y0); int size = (int)static_str[j].size(); for(int i = 0; i < size; ++i){ char ic = static_str[j][i]; glutBitmapCharacter(GLUT_BITMAP_9_BY_15, ic); } y0 -= 20; } glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } }} 呼び出す前にglColorで色の設定をしておく. boost::circular_bufferを使ってコマンドプロンプトのように文字列を次々と描画していく. #code(C){{ typedef boost::circular_buffer<string> CircularBuf; // 循環バッファ static CircularBuf g_cbDrawDef(5); static vector<string> g_cbDrawStaticDef(3); template<typename T> inline CircularBuf &operator<<(CircularBuf &cb, const T &a) { string buf = boost::lexical_cast<std::string>(a); if(buf == "\n"){ cb.push_back(""); } else if(cb.empty()){ cb.push_back(buf); } else{ cb.back() += buf; } return cb; } template<typename T> inline string &operator<<(string &cb, const T &a) { cb += boost::lexical_cast<std::string>(a); return cb; } /*! * 文字列描画 * @param[in] cir_str 文字列循環バッファ * @param[in] static_str 静的な文字列バッファ * @param[in] w,h ウィンドウサイズ */ static void DrawStrings(CircularBuf cir_str, vector<string> &static_str, int w, int h) { // MRK:PrintD glDisable(GL_LIGHTING); //glColor3f(0.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, w, 0, h); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); float x0 = 5; float y0 = h-20; // 画面上部にスタティックなテキスト for(int j = 0; j < (int)static_str.size(); ++j){ glRasterPos2f(x0, y0); int size = (int)static_str[j].size(); for(int i = 0; i < size; ++i){ char ic = static_str[j][i]; glutBitmapCharacter(GLUT_BITMAP_9_BY_15, ic); } y0 -= 20; } // 画面下部に循環バッファを使ったテキスト x0 = 5; y0 = 20*cir_str.size();; for(int j = 0; j < (int)cir_str.size(); ++j){ glRasterPos2f(x0, y0); int size = (int)cir_str[j].size(); for(int i = 0; i < size; ++i){ char ic = cir_str[j][i]; glutBitmapCharacter(GLUT_BITMAP_9_BY_15, ic); } y0 -= 20; } glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); } }} ***三角形メッシュ描画(法線計算付き) [#yee58253] #code(C){{ /*! * 三角形メッシュ描画 * @param[in] vrts 頂点列 * @param[in] idxes メッシュを構成する頂点インデックス(0始まり) * @param[in] normal 法線描画ON/OFF */ void DrawMesh(const vector<Vec3> &vrts, const vector< vector<int> > &idxes, bool normal) { for(int i = 0; i < (int)idxes.size(); ++i){ vector<int> idx = idxes[i]; int nv = (int)idx.size(); // 法線 Vec3 nrm; nrm = cross(vrts[idx[1]]-vrts[idx[0]], vrts[idx[nv-1]]-vrts[idx[0]]); normalize(nrm); if(normal){ // 重心を求める Vec3 mc(0.0); for(int j = 0; j < nv; ++j){ mc += vrts[idx[j]]; } mc /= (double)nv; int lighting = glIsEnabled(GL_LIGHTING); glDisable(GL_LIGHTING); glBegin(GL_LINES); glVertex3dv(mc.data); glVertex3dv((mc+0.05*nrm).data); glEnd(); lighting ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING); } glNormal3dv(nrm.data); // 面 glBegin(GL_POLYGON); for(int j = 0; j < nv; ++j){ glVertex3dv(vrts[idx[j]].data); } glEnd(); } } }} 法線は面の重心に描画される.Vec3はオペレータ[]で各要素にアクセスできる3次元ベクトルクラス. ***球の描画 [#sc7c38dc] #code(C){{ /*! * 球の描画 * @param[in] cen 球の中心 * @param[in] rad 球の半径 * @param[in] col 描画色(拡散反射色) */ inline void DrawSphere(const Vec3 &cen, const double &rad, const Vec4 &col) { glPushMatrix(); glTranslatef(cen[0], cen[1], cen[2]); glRotated(90, 1.0, 0.0, 0.0); glutSolidSphere(rad, 20, 10); glPopMatrix(); } }} ***球の(滑らかな)ワイヤーフレーム描画 [#t159f84d] #code(C){{ /*! * 原点中心の円のワイヤーフレーム描画 * @param rad 円の半径 * @param n 分割数 */ static void DrawWireCircle(const double &rad, const int &n) { double t = 0.0; double dt = 2.0*RX_PI/(double)n; glBegin(GL_LINE_LOOP); do{ glVertex3f(rad*cos(t), rad*sin(t), 0.0); t += dt; }while(t < 2.0*RX_PI); glEnd(); } /*! * 原点中心の円のワイヤーフレーム描画(XZ平面) * @param rad 円の半径 * @param n 分割数 */ static void DrawWireCircleXZ(const double &rad, const int &n) { double t = 0.0; double dt = 2.0*RX_PI/(double)n; glBegin(GL_LINE_LOOP); do{ glVertex3f(rad*cos(t), 0.0, rad*sin(t)); t += dt; }while(t < 2.0*RX_PI); glEnd(); } /*! * 球のワイヤーフレーム描画 * @param cen 球の中心 * @param rad 球の半径 * @param col 描画色 */ void DrawWireSphere(const Vec3 &cen, const float &rad, const Vec3 &col) { glDisable(GL_LIGHTING); glPushMatrix(); glTranslatef(cen[0], cen[1], cen[2]); glRotatef(90, 1.0, 0.0, 0.0); glColor3f(col[0], col[1], col[2]); // 緯度(x-y平面に平行) float z, dz; dz = 2.0*rad/8.0f; z = -(rad-dz); do{ glPushMatrix(); glTranslatef(0.0, 0.0, z); DrawWireCircle(sqrt(rad*rad-z*z), 32); glPopMatrix(); z += dz; }while(z < rad); // 経度(z軸まわりに回転) float t, dt; t = 0.0f; dt = 180.0/8.0; do{ glPushMatrix(); glRotatef(t, 0.0, 0.0, 1.0); DrawWireCircleXZ(rad, 32); glPopMatrix(); t += dt; }while(t < 180); //glutWireSphere(rad, 10, 5); glPopMatrix(); } }} ***円の描画 [#w796138f] x-y平面上に円を描画. #code(C){{ /*! * 円の描画 * @param cen 円の中心 * @param rad 円の半径 * @param n 分割数 */ static void DrawCircle(Vec3 cen, double rad, int n) { double t = 0.0; double dt = 2.0*RX_PI/(double)n; glPushMatrix(); glTranslatef(cen[0], cen[1], cen[2]); glBegin(GL_POLYGON); do{ glVertex3f(rad*cos(t), rad*sin(t), 0.0); t += dt; }while(t < 2.0*RX_PI); glEnd(); glPopMatrix(); } /*! * 円のワイヤーフレーム描画 * @param cen 円の中心 * @param rad 円の半径 * @param n 分割数 */ static void DrawWireCircle(Vec3 cen, double rad, int n) { double t = 0.0; double dt = 2.0*RX_PI/(double)n; glPushMatrix(); glTranslatef(cen[0], cen[1], cen[2]); glBegin(GL_LINE_LOOP); do{ glVertex3f(rad*cos(t), rad*sin(t), 0.0); t += dt; }while(t < 2.0*RX_PI); glEnd(); glPopMatrix(); } }} Vec3はオペレータ[]で各要素にアクセスできる3次元ベクトルクラス.RX_PIは円周率. *アフィン変換 [#w6072353] ***回転 [#hc5f8f47] #code(C){{ //! degree -> radian の変換係数(pi/180.0) const double RX_DEGREES_TO_RADIANS = 0.0174532925199432957692369076848; //! degree -> radian の変換 template<class T> inline T RX_TO_RADIANS(const T &x){ return static_cast<T>((x)*RX_DEGREES_TO_RADIANS); } /*! * 座標の回転 * @param[in] pos 回転したい座標値 * @param[in] rot_deg x,y,z軸周りの回転角(deg) * @return 回転後の座標値 */ inline Vec3 RxRotate(const Vec3 &pos, const Vec3 &rot_deg) { Vec3 pos1; Vec3 rot = RX_TO_RADIANS(rot_deg); Vec3 S(sin(rot[0]), sin(rot[1]), sin(rot[2])); Vec3 C(cos(rot[0]), cos(rot[1]), cos(rot[2])); pos1[0] = C[1]*C[2]*pos[0] -C[1]*S[2]*pos[1] +S[1]*pos[2]; pos1[1] = (S[0]*S[1]*C[2]+C[0]*S[2])*pos[0] +(-S[0]*S[1]*S[2]+C[0]*C[2])*pos[1] -S[0]*C[1]*pos[2]; pos1[2] = (-C[0]*S[1]*C[2]+S[0]*S[2])*pos[0] +(C[0]*S[1]*S[2]+S[0]*C[2])*pos[1] +C[0]*C[1]*pos[2]; return pos1; } /*! * 座標の回転(2D) * @param[in] pos 回転したい座標値 * @param[in] rot_deg z軸周りの回転角(deg) * @return 回転後の座標値 */ inline Vec2 RxRotate2D(const Vec2 &pos, double rot_deg) { double rot = RX_TO_RADIANS(rot_deg); return Vec2(pos[0]*cos(rot)-pos[1]*sin(rot), pos[0]*sin(rot)+pos[1]*cos(rot)); } }} ***任意ベクトル周りの回転 [#i46bfc4d] #code(C){{ /*! * 任意ベクトル周りの回転 * @param[in] pos 元の座標値 * @param[in] axis 回転軸 * @param[in] ang 回転角度(deg) * @return 回転した座標値 */ inline Vec3 Rotate(const Vec3 &pos, const Vec3 &axis, const double &ang_deg) { Vec3 pos1; // 回転後の座標値 double ang = RX_TO_RADIANS(ang_deg); double c = cos(ang); double s = sin(ang); double x, y, z; x = axis[0]; y = axis[1]; z = axis[2]; // | xx(1-c)+c xy(1-c)-zs xz(1-c)+ys 0 | // | yx(1-c)+zs yy(1-c)+c yz(1-c)-xs 0 | // | xz(1-c)-ys yz(1-c)+xs zz(1-c)+c 0 | // | 0 0 0 1 | pos1[0] = (x*x*(1.0-c)+c)*pos[0] +(x*y*(1.0-c)-z*s)*pos[1] +(x*z*(1.0-c)+y*s)*pos[2]; pos1[1] = (y*x*(1.0-c)+z*s)*pos[0] +(y*y*(1.0-c)+c)*pos[1] +(y*z*(1.0-c)-x*s)*pos[2]; pos1[2] = (x*z*(1.0-c)-y*s)*pos[0] +(y*z*(1.0-c)+x*s)*pos[1] +(z*z*(1.0-c)+c)*pos[2]; return pos1; } }} ***オイラー角から回転行列 [#dcb3ea9d] #code(C){{ /*! * オイラー角から回転行列(4x4)を生成 * @param[in] * @param[out] * @return */ inline void EulerToMatrix(double *m, double pitch, double yaw, double roll) { yaw = RX_TO_RADIANS(yaw); pitch = RX_TO_RADIANS(pitch); roll = RX_TO_RADIANS(roll); double cy = cos(yaw); double sy = sin(yaw); double cp = cos(pitch); double sp = sin(pitch); double cr = cos(roll); double sr = sin(roll); double cc = cy*cr; double cs = cy*sr; double sc = sy*cr; double ss = sy*sr; m[0] = cc+sp*ss; m[1] = cs-sp*sc; m[2] = -sy*cp; m[3] = 0.0; m[4] = -cp*sr; m[5] = cp*cr; m[6] = -sp; m[7] = 0.0; m[8] = sc-sp*cs; m[9] = ss+sp*cc; m[10] = cy*cp; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } }} ***射影 [#i5f51162] #code(C){{ /*! * 任意の平面へ影を射影する行列構築関数 * @param[out] m 作成する行列(4x4)m[16]へのポインタ * @param[in] plane[4] 射影する表面の平面方程式 * @param[in] light[4] 光源の座標値(同次座標) */ inline void ProjectShadowMatrix(double *m, double plane[4], double light[4]) { double dot = plane[0]*light[0]+plane[1]*light[1]+plane[2]*light[2]+plane[3]*light[3]; m[0] = dot-light[0]*plane[0]; m[4] = -light[0]*plane[1]; m[8] = -light[0]*plane[2]; m[12] = -light[0]*plane[3]; m[1] = -light[1]*plane[0]; m[5] = dot-light[1]*plane[1]; m[9] = -light[1]*plane[2]; m[13] = -light[1]*plane[3]; m[2] = -light[2]*plane[0]; m[6] = -light[2]*plane[1]; m[10] = dot-light[2]*plane[2]; m[14] = -light[2]*plane[3]; m[3] = -light[3]*plane[0]; m[7] = -light[3]*plane[1]; m[11] = -light[3]*plane[2]; m[15] = dot-light[3]*plane[3]; } }} *その他関数 [#rdc4e1f5] ***球形状ポリゴン生成 [#k0cf6d98] #code(C){{ /*! * 球形状ポリゴン生成 * @param[in] rad 半径 * @param[in] slices z軸まわりの分割数(経線) * @param[in] stacks z軸に沿ったの分割数(緯線) * @param[out] vrts 頂点座標 * @param[out] nrms 法線座標 * @param[out] txcs テクスチャ座標 * @param[out] fces ポリゴン(頂点接続) * @param[in] tri trueで三角形ポリゴン, falseで四角形(ただし,極点付近は三角形) * @return 生成頂点数 */ int MakeSphere(double rad, int slices, int stacks, vector<Vec3> &vrts, vector<Vec3> &nrms, vector<Vec2> &txcs, vector< vector<int> > &fces, bool tri = true) { int vn = 2+(stacks-1)*slices; // 頂点数(極点2つ+経線・緯線の交点) vrts.resize(vn, Vec3(0.0)); // 頂点座標 nrms.resize(vn, Vec3(0.0)); // 頂点法線 txcs.resize(vn, Vec2(0.0)); // テクスチャ座標 vrts[0] = Vec3(0.0, 0.0, rad); // 北極点 vrts[vn-1] = Vec3(0.0, 0.0, -rad); // 南極点 double dp = RX_PI/(double)stacks; // Φ(経線に沿った方向の角度)の増分量 double dt = 2.0*RX_PI/(double)slices; // Θ(緯線に沿った方向の角度)の増分量 double phi = dp; // 経線に沿った方向の角度(北極点で0) double theta = 0.0; // 緯線に沿った方向の角度 // 球を構成する頂点の生成 for(int i = 0; i < stacks-1; ++i){ double z = rad*cos(phi); theta = 0.0; for(int j = 0; j < slices; ++j){ double rad_t = rad*sin(phi); int idx = 1+i*slices+j; vrts[idx] = Vec3(rad_t*cos(theta), rad_t*sin(theta), z); nrms[idx] = Unit(vrts[idx]); txcs[idx] = Vec2(theta/(2.0*RX_PI), phi/(RX_PI)); theta += dt; } phi += dp; } // ポリゴン数 int fn = 2*slices+(stacks-2)*slices*(tri ? 2 : 1); fces.reserve(fn); // ポリゴン生成 for(int i = 0; i < stacks; ++i){ if(i == 0){ // 北極点と最初の緯線を接続 vector<int> f(3); for(int j = 0; j < slices; ++j){ int k0 = 1+i*slices+j; int k1 = 1+i*slices+(j == slices-1 ? 0 : j+1); f[0] = 0; f[1] = k0; f[2] = k1; fces.push_back(f); } } else if(i == stacks-1){ // 南極点と最後の緯線を接続 vector<int> f(3); for(int j = 0; j < slices; ++j){ int k0 = 1+(i-1)*slices+j; int k1 = 1+(i-1)*slices+(j == slices-1 ? 0 : j+1); f[0] = vn-1; f[1] = k1; f[2] = k0; fces.push_back(f); } } else{ for(int j = 0; j < slices; ++j){ int k0 = 1+i*slices+j; int k1 = 1+i*slices+(j == slices-1 ? 0 : j+1); int k2 = 1+(i-1)*slices+j; int k3 = 1+(i-1)*slices+(j == slices-1 ? 0 : j+1); vector<int> f; if(tri){ // 三角形ポリゴンを用いる場合 f.resize(3); f[0] = k0; f[1] = k1; f[2] = k3; fces.push_back(f); f[0] = k0; f[1] = k3; f[2] = k2; fces.push_back(f); } else{ // 四角形ポリゴンを用いる場合 f.resize(4); f[0] = k0; f[1] = k1; f[2] = k3; f[3] = k2; fces.push_back(f); } } } } return 0; } /*! * 球形状ポリゴン生成(極点,経度0degでの重複あり) * @param[in] rad 半径 * @param[in] slices z軸まわりの分割数(経線) * @param[in] stacks z軸に沿ったの分割数(緯線) * @param[out] vrts 頂点座標 * @param[out] nrms 法線座標 * @param[out] txcs テクスチャ座標 * @param[out] fces ポリゴン(頂点接続) * @param[in] tri trueで三角形ポリゴン, falseで四角形 * @return 生成頂点数 */ int MakeSphereC(double rad, int slices, int stacks, vector<Vec3> &vrts, vector<Vec3> &nrms, vector<Vec2> &txcs, vector< vector<int> > &fces, bool tri = true) { int vn = (stacks+1)*(slices+1); // 頂点数(経線・緯線の交点) vrts.resize(vn, Vec3(0.0)); // 頂点座標 nrms.resize(vn, Vec3(0.0)); // 頂点法線 txcs.resize(vn, Vec2(0.0)); // テクスチャ座標 double dp = RX_PI/(double)stacks; // Φ(経線に沿った方向の角度)の増分量 double dt = 2.0*RX_PI/(double)slices; // Θ(緯線に沿った方向の角度)の増分量 double phi = 0; // 経線に沿った方向の角度(北極点で0) double theta = 0.0; // 緯線に沿った方向の角度 // 球を構成する頂点の生成 for(int i = 0; i < stacks+1; ++i){ double z = rad*cos(phi); theta = 0.0; for(int j = 0; j < slices+1; ++j){ double rad_t = rad*sin(phi); int idx = i*(slices+1)+j; vrts[idx] = Vec3(rad_t*cos(theta), rad_t*sin(theta), z); nrms[idx] = Unit(vrts[idx]); txcs[idx] = Vec2(theta/(2.0*RX_PI), phi/(RX_PI)); theta += dt; } phi += dp; } // ポリゴン数 int fn = stacks*slices*(tri ? 2 : 1); fces.reserve(fn); // ポリゴン生成 for(int i = 1; i < stacks+1; ++i){ for(int j = 0; j < slices; ++j){ int k0 = i*(slices+1)+j; int k1 = i*(slices+1)+(j+1); int k2 = (i-1)*(slices+1)+j; int k3 = (i-1)*(slices+1)+(j+1); vector<int> f; if(tri){ // 三角形ポリゴンを用いる場合 f.resize(3); f[0] = k0; f[1] = k1; f[2] = k3; fces.push_back(f); f[0] = k0; f[1] = k3; f[2] = k2; fces.push_back(f); } else{ // 四角形ポリゴンを用いる場合 f.resize(4); f[0] = k0; f[1] = k1; f[2] = k3; f[3] = k2; fces.push_back(f); } } } return 0; } }} ***ミップマップテクスチャのサイズの計算 [#y1859c15] #code(C){{ /*! * ミップマップのサイズの計算 * @param[in] x 任意の整数(画像の大きさ) * @param[out] d x以下の最大の2^d * @return x以下の最大の2^dとなる解像度 */ inline int CalMipmapSize(const int &x, int &d) { d = (int)(log((double)x)/log(2.0)); return (int)pow(2.0, (double)d); } }} ***グラデーション色の作成 [#m477d227] #code(C){{ //! 値のクランプ(クランプした値を返す) template<class T> inline T RX_CLAMP(const T &x, const T &a, const T &b){ return ((x < a) ? a : (x > b) ? b : x); } //! 1次元線型補間 template<class T> inline T RX_LERP(const T &a, const T &b, const T &t){ return a + t*(b-a); } /*! * 青->緑->赤->白と変化するサーモグラフ用の色生成 * @param[out] col 生成された色 * @param[in] x 値 * @param[in] xmin 最小値 * @param[in] xmax 最大値 */ inline void CalThermograph(double col[3], double x, const double xmin = 0.0, const double xmax = 1.0) { double l = xmax-xmin; if(fabs(l) < 1e-10) return; const int ncolors = 7; double base[ncolors][3] = { {0.0, 0.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 1.0, 1.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 1.0} }; x = RX_CLAMP(((x-xmin)/l), 0.0, 1.0)*(ncolors-1); int i = (int)x; double dx = x-floor(x); col[0] = RX_LERP(base[i][0], base[i+1][0], dx); col[1] = RX_LERP(base[i][1], base[i+1][1], dx); col[2] = RX_LERP(base[i][2], base[i+1][2], dx); } /*! * グラデーション色生成 * @param[out] col 生成された色 * @param[in] col1 x=xminのときの色 * @param[in] col2 x=xmaxのときの色 * @param[in] x 値 * @param[in] xmin 最小値 * @param[in] xmax 最大値 */ inline void CalGradation(double col[3], const double col1[3], const double col2[3], double x, const double xmin = 0.0, const double xmax = 1.0) { double l = xmax-xmin; if(fabs(l) < 1e-10) return; double dx = RX_CLAMP(((x-xmin)/l), 0.0, 1.0); col[0] = RX_LERP(col1[0], col2[0], dx); col[1] = RX_LERP(col1[1], col2[1], dx); col[2] = RX_LERP(col1[2], col2[2], dx); } }} *クラス [#vb8f996e] ***テクスチャ管理クラス [#da4250ba] #code(C){{ //----------------------------------------------------------------------------- // MARK:テクスチャデータの基底クラス //----------------------------------------------------------------------------- class rxTexObj { protected: GLenum m_iTarget; bool m_bValid; bool m_bManageObjects; GLuint m_iTexName; public: // managed = true : デストラクタでオブジェクトを破棄したいとき rxTexObj(GLenum tgt, bool managed) : m_iTarget(tgt), m_bValid(false), m_bManageObjects(managed) {} ~rxTexObj() { if(m_bManageObjects) Delete(); } void Bind(void) { if(!m_bValid){ Generate(); } glBindTexture(m_iTarget, m_iTexName); } void UnBind(void) { glBindTexture(m_iTarget, 0); } void SetParameter(GLenum pname, GLint i){ glTexParameteri(m_iTarget, pname, i); } void SetParameter(GLenum pname, GLfloat f){ glTexParameterf(m_iTarget, pname, f); } void SetParameter(GLenum pname, GLint *ip){ glTexParameteriv(m_iTarget, pname, ip); } void SetParameter(GLenum pname, GLfloat *fp){ glTexParameterfv(m_iTarget, pname, fp); } void Enable(void){ glEnable(m_iTarget); } void Disable(void){ glDisable(m_iTarget); } GLuint GetTexName(void) const { return m_iTexName; } GLenum GetTexTarget(void) const { return m_iTarget; } void Delete() { if(m_bValid){ glDeleteTextures(1, &m_iTexName); m_bValid = false; } } void Generate() { glGenTextures(1, &m_iTexName); m_bValid = true; } public: bool IsValid() const { return m_bValid; } }; //----------------------------------------------------------------------------- // MARK:2Dテクスチャデータ //----------------------------------------------------------------------------- template <class T> class rxTexObj2D_T : public rxTexObj { public: T *m_pImage; int m_iW, m_iH, m_iC; GLenum m_iFormat; public: //! コンストラクタ rxTexObj2D_T(bool managed = false) : rxTexObj(GL_TEXTURE_2D, managed) { m_pImage = NULL; m_iW = 0; m_iH = 0; m_iC = 3; m_iFormat = GL_RGB; } //! デストラクタ ~rxTexObj2D_T() { if(m_pImage != NULL) delete [] m_pImage; } /*! * テクスチャサイズの設定 * @param[in] iW,iH テクスチャの縦横ピクセル数 * @param[in] iC テクスチャの1ピクセルごとのチャンネル数 */ void SetSize(int iW, int iH, int iC = 3) { if(m_iW != iW || m_iH != iH || m_iC != iC){ m_iW = iW; m_iH = iH; m_iC = iC; m_iFormat = (m_iC == 4) ? GL_RGBA : GL_RGB; if(m_pImage != NULL) delete [] m_pImage; m_pImage = new T[m_iW*m_iH*m_iC]; } } /*! * テクスチャサイズの取得 * @param[out] iW,iH テクスチャの縦横ピクセル数 * @param[out] iC テクスチャの1ピクセルごとのチャンネル数 */ void GetSize(int &iW, int &iH, int &iC) { iW = m_iW; iH = m_iH; iC = m_iC; } /*! * ピクセルの色情報の取得 * @param[in] ic,jc ピクセル座標 * @param[out] r,g,b ピクセルの色 */ void GetColor(int ic, int jc, T &r, T &g, T &b) { r = m_pImage[m_iC*(m_iW*jc+ic)+0]; g = m_pImage[m_iC*(m_iW*jc+ic)+1]; b = m_pImage[m_iC*(m_iW*jc+ic)+2]; } /*! * ピクセルの色情報の取得(4チャンネルRGBA) * @param[in] ic,jc ピクセル座標 * @param[out] r,g,b,a ピクセルの色 */ void GetColor4(int ic, int jc, T &r, T &g, T &b, T &a) { r = m_pImage[m_iC*(m_iW*jc+ic)+0]; g = m_pImage[m_iC*(m_iW*jc+ic)+1]; b = m_pImage[m_iC*(m_iW*jc+ic)+2]; if(m_iC == 4) a = m_pImage[m_iC*(m_iW*jc+ic)+3]; } /*! * ピクセルの色情報の設定 * @param[in] ic,jc ピクセル座標 * @param[in] r,g,b ピクセルの色 */ void SetColor(int ic, int jc, const T &r, const T &g, const T &b) { m_pImage[m_iC*(m_iW*jc+ic)+0] = r; m_pImage[m_iC*(m_iW*jc+ic)+1] = g; m_pImage[m_iC*(m_iW*jc+ic)+2] = b; if(m_iC == 4) m_pImage[m_iC*(m_iW*jc+ic)+3] = 0; } /*! * ピクセルの色情報の設定(4チャンネルRGBA) * @param[in] ic,jc ピクセル座標 * @param[in] r,g,b,a ピクセルの色 */ void SetColor(int ic, int jc, const T &r, const T &g, const T &b, const T &a) { m_pImage[m_iC*(m_iW*jc+ic)+0] = r; m_pImage[m_iC*(m_iW*jc+ic)+1] = g; m_pImage[m_iC*(m_iW*jc+ic)+2] = b; if(m_iC == 4) m_pImage[m_iC*(m_iW*jc+ic)+3] = a; } /*! * テクスチャメモリへ画像データを転送 */ void SetTexture(void){ GLenum type = GL_UNSIGNED_BYTE; if(sizeof(T) == 1){ type = GL_UNSIGNED_BYTE; } else if(sizeof(T) == 4){ type = GL_FLOAT; } glTexImage2D(m_iTarget, 0, GL_RGBA, m_iW, m_iH, 0, m_iFormat, type, m_pImage); } }; typedef rxTexObj2D_T<unsigned char> rxTexObj2D; typedef rxTexObj2D_T<float> rxTexObj2Df; }} ***材質クラス [#be975cfa] OpenGLでの表面材質を管理するクラス. g_matDefaultはデフォルトマテリアルを定義している. #code(C){{ //----------------------------------------------------------------------------- // 材質データ //----------------------------------------------------------------------------- class rxMaterial { public: Vec4 m_vDiff, m_vSpec, m_vAmbi, m_vEmit; double m_fDiffS, m_fSpecS, m_fAmbiS, m_fEmitS; double m_fShin; Vec4 m_vColor; // 屈折,鏡面反射パラメータ double m_fEta; //!< 屈折率 double m_fBias; //!< Fresnelバイアス double m_fPower; //!< Fresnel指数 double m_fScale; //!< Fresnel倍率 string m_strName; int m_iID; int m_iIllum; string m_strTexFile; unsigned int m_uTexName; public: rxMaterial() { SetColor(Vec3(0.0, 0.0, 1.0), Vec3(1.0), Vec3(1.0), Vec3(0.0), 30.0); SetScale(1.0, 0.75, 0.2, 0.0); m_fEta = 0.9; m_fBias = 1.0; m_fPower = 0.98; m_fScale = 5.0; } void SetColor(const Vec4 &diff, const Vec4 &spec, const Vec4 &ambi, const Vec4 &emit, const double &shin) { m_vDiff = diff; m_vSpec = spec; m_vAmbi = ambi; m_vEmit = emit; m_fShin = shin; } void SetColor(const GLfloat diff[4], const GLfloat spec[4], const GLfloat ambi[4], const GLfloat emit[4], const GLfloat shine) { m_vDiff = Vec4(diff[0], diff[1], diff[2], diff[3]); m_vSpec = Vec4(spec[0], spec[1], spec[2], spec[3]); m_vAmbi = Vec4(ambi[0], ambi[1], ambi[2], ambi[3]); m_vEmit = Vec4(emit[0], emit[1], emit[2], emit[3]); m_fShin = shine; } void SetColor(const Vec3 &diff, const Vec3 &spec, const Vec3 &ambi, const Vec3 &emit, const double &shin) { m_vDiff = diff; m_vDiff[3] = 1.0; m_vSpec = spec; m_vSpec[3] = 1.0; m_vAmbi = ambi; m_vAmbi[3] = 1.0; m_vEmit = emit; m_vEmit[3] = 1.0; m_fShin = shin; } void SetDiff(const Vec4 &col){ m_vDiff = col; } void SetSpec(const Vec4 &col){ m_vSpec = col; } void SetAmbi(const Vec4 &col){ m_vAmbi = col; } void SetEmit(const Vec4 &col){ m_vEmit = col; } void SetDiff3(const Vec3 &col){ m_vDiff = col; m_vDiff[3] = 1.0; } void SetSpec3(const Vec3 &col){ m_vSpec = col; m_vSpec[3] = 1.0; } void SetAmbi3(const Vec3 &col){ m_vAmbi = col; m_vAmbi[3] = 1.0; } void SetEmit3(const Vec3 &col){ m_vEmit = col; m_vEmit[3] = 1.0; } void SetScale(const double &sdiff, const double &sspec, const double &sambi, const double &semit) { m_fDiffS = sdiff; m_fSpecS = sspec; m_fAmbiS = sambi; m_fEmitS = semit; } void SetRefrac(const double &eta, const double &bias, const double &power, const double &scale) { m_fEta = eta; m_fBias = bias; m_fPower = power; m_fScale = scale; } void SetGL(void) { GLfloat mat_diff[] = { (float)(m_fDiffS*m_vDiff[0]), (float)(m_fDiffS*m_vDiff[1]), (float)(m_fDiffS*m_vDiff[2]), (float)m_vDiff[3] }; GLfloat mat_spec[] = { (float)(m_fSpecS*m_vSpec[0]), (float)(m_fSpecS*m_vSpec[1]), (float)(m_fSpecS*m_vSpec[2]), (float)m_vDiff[3] }; GLfloat mat_ambi[] = { (float)(m_fAmbiS*m_vAmbi[0]), (float)(m_fAmbiS*m_vAmbi[1]), (float)(m_fAmbiS*m_vAmbi[2]), (float)m_vDiff[3] }; GLfloat mat_shin[] = { (float)m_fShin }; glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diff); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_spec); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambi); glMaterialfv(GL_FRONT, GL_SHININESS,mat_shin); glColor3fv(mat_diff); } void SetGL(const Vec4 &diff, const Vec4 &spec, const Vec4 &ambi) { GLfloat mat_diff[] = { (float)(m_fDiffS*diff[0]), (float)(m_fDiffS*diff[1]), (float)(m_fDiffS*diff[2]), (float)diff[3] }; GLfloat mat_spec[] = { (float)(m_fSpecS*spec[0]), (float)(m_fSpecS*spec[1]), (float)(m_fSpecS*spec[2]), (float)spec[3] }; GLfloat mat_ambi[] = { (float)(m_fAmbiS*ambi[0]), (float)(m_fAmbiS*ambi[1]), (float)(m_fAmbiS*ambi[2]), (float)ambi[3] }; GLfloat mat_shin[] = { (float)m_fShin }; glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diff); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_spec); glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambi); glMaterialfv(GL_FRONT, GL_SHININESS,mat_shin); glColor4fv(mat_diff); } // アクセスメソッド Vec4 GetDiff(void) const { return m_vDiff*m_fDiffS; } Vec4 GetSpec(void) const { return m_vSpec*m_fSpecS; } Vec4 GetAmbi(void) const { return m_vAmbi*m_fAmbiS; } Vec4 GetEmit(void) const { return m_vEmit*m_fEmitS; } Vec3 GetDiff3(void) const { return Vec3(m_vDiff[0], m_vDiff[1], m_vDiff[2])*m_fDiffS; } Vec3 GetSpec3(void) const { return Vec3(m_vSpec[0], m_vSpec[1], m_vSpec[2])*m_fSpecS; } Vec3 GetAmbi3(void) const { return Vec3(m_vAmbi[0], m_vAmbi[1], m_vAmbi[2])*m_fAmbiS; } Vec3 GetEmit3(void) const { return Vec3(m_vEmit[0], m_vEmit[1], m_vEmit[2])*m_fEmitS; } double GetShin(void) const { return m_fShin; } Vec3 GetReflec(const Vec3 &irr, const Vec3 &nrm) { double ref_coef = m_fBias+m_fScale*pow((1.0+dot(irr, nrm)), m_fPower); RXFunc::Clamp(ref_coef, 0.0, 1.0); return ref_coef*GetSpec3(); } Vec3 GetRefrac(const Vec3 &irr, const Vec3 &nrm) { double ref_coef = m_fBias+m_fScale*pow((1.0+dot(irr, nrm)), m_fPower); RXFunc::Clamp(ref_coef, 0.0, 1.0); return (1.0-ref_coef)*GetSpec3(); } void Get(Vec3 &diff, Vec3 &spec, Vec3 &ambi, Vec3 &emit, double &shin) { diff = Vec3(m_vDiff[0], m_vDiff[1], m_vDiff[2]); spec = Vec3(m_vSpec[0], m_vSpec[1], m_vSpec[2]); ambi = Vec3(m_vAmbi[0], m_vAmbi[1], m_vAmbi[2]); emit = Vec3(m_vEmit[0], m_vEmit[1], m_vEmit[2]); shin = m_fShin; } }; static rxMaterial g_matDefault; }} ***マウスピッククラス [#e411292a] コンストラクタかSet関数で描画関数,投影変換関数を指定して, Pick関数にマウス座標(スクリーン座標系)を渡すことで,ポリゴンなどを選択する. クラスに渡す描画関数内ではglLoadNameで各オブジェクトのインデックスを指定しておくこと. Pick関数はこのインデックスを返す. #code(C){{ //----------------------------------------------------------------------------- // OpenGLによるオブジェクトピック //----------------------------------------------------------------------------- class rxGLPick { boost::function<void (void)> m_fpDraw; //!< ピック用描画関数 boost::function<void (void)> m_fpProj; //!< 投影変換関数 int m_pSelBufferSize; public: rxGLPick() { m_pSelBufferSize = 128; } rxGLPick(boost::function<void (void)> draw, boost::function<void (void)> proj) : m_fpDraw(draw), m_fpProj(proj) { m_pSelBufferSize = 128; } ~rxGLPick(){} void Set(boost::function<void (void)> draw, boost::function<void (void)> proj) { m_fpDraw = draw; m_fpProj = proj; } protected: /*! * OpenGLによるピックでヒットしたものから最小のデプス値を持つものを選択する * @param hits ヒット数 * @param buf 選択バッファ * @return ヒットしたオブジェクト番号 */ int selectHits(GLint hits, GLuint buf[]) { GLuint hit_name; float depth_min = 100.0f; float depth1 = 1.0f; float depth2 = 1.0f; GLuint depth_name; GLuint *ptr; // ヒットしたデータなし if(hits <= 0) return -1; // ポインタを作業用ptrへ渡す. ptr = (GLuint*)buf; for(int i = 0; i < hits; ++i){ // 識別番号の階層の深さ depth_name = *ptr; ptr++; depth1 = (float) *ptr/0x7fffffff; ptr++; depth2 = (float) *ptr/0x7fffffff; ptr++; // 最小デプスの確認 if(depth_min > depth1){ depth_min = depth1; hit_name = *ptr; } ptr++; } return hit_name; } /*! * マウス選択 * @param[in] x,y マウス座標 * @retval int ピックオブジェクト番号 */ int pick(int x, int y) { // HCK:Pick GLuint* selbuf = new GLuint[m_pSelBufferSize]; GLint hits; GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); glSelectBuffer(m_pSelBufferSize, selbuf); glRenderMode(GL_SELECT); glInitNames(); glPushName(0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix(x, viewport[3]-y, 10.0, 10.0, viewport); m_fpProj(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); m_fpDraw(); glLoadName(0); glMatrixMode(GL_PROJECTION); glPopMatrix(); glPopName(); hits = glRenderMode(GL_RENDER); int obj_number = selectHits(hits, selbuf); glMatrixMode(GL_MODELVIEW); return obj_number; } public: /*! * オブジェクトのマウス選択 * @param[in] x,y マウス座標 * @retval true ピック成功 * @retval false ピック失敗 */ int Pick(int x, int y) { int obj_number; if((obj_number = pick(x, y)) != -1){ return obj_number; } else{ return -1; } //Zバッファ値をゲット // object_depth = PickDepth(x,y); return -1; } }; }}