3D:球と球

バウンディングスフィアです。
3Dの当たり判定では最も計算コストが少なく、簡単に実装できるため
多用されます。
仕組みですが、まず、球の中心位置と球の半径を設定します。
そして、球と球の中心間の距離が互いの半径の合計値以下であれば
接触していると判断できます。

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

#define WIDTH 320
#define HEIGHT 240

//平行移動用
float x = 0.0f;
bool flag = false;

//3つのベクトル
struct Vector3f{
 float x;
 float y;
 float z;
}vec3d;

//球構造体
struct Sphere{
 GLfloat Color[4];//色
 GLfloat Radius;//半径
 Vector3f Pos;//位置
 void Draw();
};
void Sphere::Draw(){
 glMaterialfv(GL_FRONT, GL_DIFFUSE, Color);
 glTranslatef(Pos.x,Pos.y,Pos.z);
 glutSolidSphere(Radius,16,16);
}

Sphere Green,Yellow;

//当り判定
bool Calc_Hit(Sphere& a,Sphere& b){
 if(sqrt((a.Pos.x-b.Pos.x)*(a.Pos.x-b.Pos.x)+(a.Pos.y-b.Pos.y)*(a.Pos.y-b.Pos.y)+(a.Pos.z-b.Pos.z)*(a.Pos.z-b.Pos.z))<=a.Radius+b.Radius){
  return true;
 }else{
  return false;
 }
}

//ライトの位置
GLfloat lightpos[] = { 200.0, 150.0, -500.0, 1.0 };

class GLFONT{
public:
 HFONT Hfont;
 HDC Hdc;
 GLFONT(wchar_t *fontname, int size);
 void DrawStringW(int x,int y,wchar_t *format, ...);
};
//コンストラクタ フォント作成
GLFONT::GLFONT(wchar_t *fontname, int size){
 Hfont = CreateFontW(
        size,      //フォント高さ
        0,       //文字幅
        0,       //テキストの角度
        0,       //ベースラインとx軸との角度
        FW_REGULAR,     //フォントの太さ
        FALSE,      //イタリック体
        FALSE,      //アンダーライン
        FALSE,      //打ち消し線
        SHIFTJIS_CHARSET,   //文字セット
        OUT_DEFAULT_PRECIS,   //出力精度
        CLIP_DEFAULT_PRECIS,  //クリッピング精度
        ANTIALIASED_QUALITY,  //出力品質
        FIXED_PITCH | FF_MODERN, //ピッチとファミリー
        fontname);     //書体名

 Hdc = wglGetCurrentDC();
 SelectObject(Hdc, Hfont);
}
//ワイド文字列の描画
void GLFONT::DrawStringW(int x,int y,wchar_t *format, ...){
 wchar_t buf[256];
 va_list ap;
 int Length=0;
 int list=0;
 
 //ポインタがNULLの場合は終了
 if ( format == NULL )
  return;

 //文字列変換
 va_start(ap, format);
 vswprintf_s(buf, format, ap);
 va_end(ap);

 Length = wcslen(buf);
 list = glGenLists(Length);
 for( int i=0; i<Length; i++ ){
  wglUseFontBitmapsW(Hdc, buf[i], 1, list + (DWORD)i);
 }

 glDisable(GL_LIGHTING);
 glRasterPos2i(x, y);
 //ディスプレイリストで描画
 for( int i=0; i<Length; i++ )
 {
  glCallList(list + i);
 }
 glEnable(GL_LIGHTING);
 //ディスプレイリスト破棄
 glDeleteLists(list, Length);
 list = 0;
 Length = 0;
}

GLFONT *font;


void Line3D(float x1,float y1,float z1,float x2,float y2,float z2){
  //線幅
  glLineWidth(1.0);
  //線
  glBegin(GL_LINES);
  glVertex3f(x1,y1,z1);
  glVertex3f(x2,y2,z2);
  glEnd();
}

void DrawMeasure(int measure,float size){
 glDisable(GL_LIGHTING);
 glColor4f(0.5f, 0.5f, 0.5f, 0.5f);
 for(int x=0;x<=measure;x++){Line3D(x*size-(size*measure/2),0,-(size*measure/2),x*size-(size*measure/2),0,measure*size-(size*measure/2));}
 for(int y=0;y<=measure;y++){Line3D(-(size*measure/2),0,y*size-(size*measure/2),measure*size-(size*measure/2),0,y*size-(size*measure/2));}
 glDisable(GL_DEPTH_TEST);
 glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
 Line3D(0,0,0,(measure/2+2)*size,0,0);
 glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
 Line3D(0,0,0,0,(measure/2+2)*size,0);
 glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
 Line3D(0,0,0,0,0,(measure/2+2)*size);
 glEnable(GL_LIGHTING);
 glEnable(GL_DEPTH_TEST);
}

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, 2000.0);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 //視点の設定
 gluLookAt(0.0,300.0,-500.0, //カメラの座標
      0.0,0.0,0.0, // 注視点の座標
     0.0,1.0,0.0); // 画面の上方向を指すベクトル

 if(Calc_Hit(Green,Yellow)){
  glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
  font->DrawStringW(170,130,L"Hit !!");
 }else{
  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  font->DrawStringW(170,130,L"No Hit !!");
 }

 DrawMeasure(16,40);
 //ライトの設定
 glLightfv(GL_LIGHT0, GL_POSITION, lightpos);

 Yellow.Draw();

 glLoadIdentity();
  //視点の設定
 gluLookAt(0.0,300.0,-500.0, //カメラの座標
      0.0,0.0,0.0, // 注視点の座標
     0.0,1.0,0.0); // 画面の上方向を指すベクトル

 Green.Draw();

 glutSwapBuffers();
}
void timer(int value) {
 if(flag){x-=1.0f;}else{x+=1.0f;}
 if(x>100.0f)flag=true;
 if(x<-100.0f)flag=false;
 Green.Pos.x=x;
 glutTimerFunc(10 , timer , 0);
}
void idle(void){
 glutPostRedisplay();
}
void Init(){
 glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
 glEnable(GL_DEPTH_TEST);
 glEnable(GL_LIGHTING);
 glEnable(GL_LIGHT0);
 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 glEnable(GL_BLEND);//ブレンドの有効化
 font = new GLFONT(L"MS明朝", 24);
 Green.Color[0]=0.0f;
 Green.Color[1]=1.0f;
 Green.Color[2]=0.0f;
 Green.Color[3]=0.8f;
 Green.Pos.x=0.0f;
 Green.Pos.y=0.0f;
 Green.Pos.z=0.0f;
 Green.Radius=40.0f;
 Yellow.Color[0]=1.0f;
 Yellow.Color[1]=1.0f;
 Yellow.Color[2]=0.0f;
 Yellow.Color[3]=0.8f;
 Yellow.Pos.x=10.0f;
 Yellow.Pos.y=0.0f;
 Yellow.Pos.z=0.0f;
 Yellow.Radius=20.0f;
}
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);
 glutTimerFunc(10 , timer , 0);
 Init();
 glutMainLoop();
 return 0;
}

 

最終更新:2014年06月14日 15:50
添付ファイル