3D:線分と無限平面

線分と無限平面の当たり判定です。
無限平面を表現するのは困難なので、今回は代わりに三角ポリゴンを表示しています。

ファイル
main.cpp
font.h

main.cpp

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

#define PAI 3.14159

#define WIDTH 320
#define HEIGHT 240

//3つのベクトル
struct Vector3f{
 float x;
 float y;
 float z;
 Vector3f(){};
 Vector3f(float _x,float _y,float _z){
  x=_x;y=_y;z=_z;
 };
     //ベクトル引き算( this - v )
    Vector3f operator - ( const Vector3f& v ) const { return Vector3f( x - v.x, y - v.y, z - v.z ); }
    
    //ベクトル外積( this × vr )
    Vector3f operator * ( const Vector3f& vr ) const { return Vector3f( (y * vr.z) - (z * vr.y), (z * vr.x) - (x * vr.z), (x * vr.y) - (y * vr.x) ); }
    
    //自身を単位ベクトルにする
    void Normalize() {
        double length = pow( (double)( x * x ) + ( y * y ) + ( z * z ), 0.5 );//ベクトルの長さ
        x /= length;
        y /= length;
        z /= length;
    }
}vec3d;
Vector3f & operator*(Vector3f &v,float size){
 v.x *= size;
 v.y *= size;
 v.z *= size;
 return v;
}
Vector3f & operator+(Vector3f &a,Vector3f &b){
 a.x+=b.x;
 a.y+=b.y;
 a.z+=b.z;
 return a;
}

//頂点ABCで作られたポリゴンから法線を計算する。
Vector3f CreatePolygonNormal( Vector3f A, Vector3f B, Vector3f C ) {

    Vector3f AB( B - A );
    Vector3f BC( C - B );

    Vector3f normal = AB * BC;    //AB BCの外積
    normal.Normalize();//単位ベクトルにする

    return normal;
}

//内積
void dot(Vector3f& src1,Vector3f& src2,float& dst){
 dst= src1.x*src2.x+src1.y*src2.y+src1.z*src2.z;
}

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 LineSegment(Vector3f a,Vector3f b){
    Line3D(a.x,a.y,a.z,b.x,b.y,b.z);
    glPointSize(5.0f);
    glBegin(GL_POINTS);
    glVertex3f(a.x , a.y , a.z);
    glVertex3f(b.x , b.y , b.z);
    glEnd();
}

void TriangleDraw(Vector3f a,Vector3f b,Vector3f c){
    glBegin(GL_POLYGON);
    glVertex3f(a.x , a.y , a.z);
    glVertex3f(b.x , b.y , b.z);
    glVertex3f(c.x , c.y , c.z);
    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);
}

//黄色
GLfloat yerrow[] = { 1.0f, 1.0f, 0.0f, 1.0f };
//紫
GLfloat purple[] = { 0.5f, 0.0f, 1.0f, 1.0f };
//ライトの位置
GLfloat lightpos[] = { 0.0, 0.0, 200.0, 1.0 };

GLFONT *font;

Vector3f point_A(100 , 50 , 50),point_B(100 ,-50 , 50);
Vector3f Triangle_A(150,10,75),Triangle_B(0,10,75),Triangle_C(150,10,-75);

Vector3f normal(0,0,0);
float vector_a,vector_b;

bool flag=false;
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(400.0,400.0,400.0,
      0.0,0.0,0.0,
     0.0,1.0,0.0);

  //ライトの設定
 glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
 glColor3f(1,1,1);
 DrawMeasure(8,40);
 //線分
 glMaterialfv(GL_FRONT, GL_DIFFUSE, yerrow);
 LineSegment(point_A,point_B);
 //三角形(平面)
 glMaterialfv(GL_FRONT, GL_DIFFUSE, purple);
 TriangleDraw(Triangle_A,Triangle_B,Triangle_C);

 normal=CreatePolygonNormal(Triangle_A,Triangle_B,Triangle_C);
 dot(point_A,normal,vector_a);
 dot(point_B,normal,vector_b);
 if((vector_a * vector_b)<=0){
     glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
     font->DrawStringW(-320,0,L"Hit!!");
 }else{
     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
     font->DrawStringW(-320,0,L"NO Hit!!");
 }

 glutSwapBuffers();

}
void idle(void)
{
    if(flag){
        point_A.y-=2.0f;
        point_B.y-=2.0f;
    }else{
        point_A.y+=2.0f;
        point_B.y+=2.0f;
    }
 if(point_A.y>200.0f){flag=true;}
 if(point_A.y<-100.0f){flag=false;}
 Sleep(1);
  glutPostRedisplay();
}

void Init(){
 glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
 glEnable(GL_DEPTH_TEST);
 glEnable(GL_LIGHTING);
 glEnable(GL_LIGHT0);

 font = new GLFONT(L"MS明朝", 24);

}


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年03月04日 23:23
添付ファイル