2014년 3월 3일 월요일

[일기]Box2D. 계에 질의하기.

World Querying

- Ray Cast with efficient way

- AABB(axis-aligned bounding box) querying.

각각은 다음의 메서드로 수행된다.

첫째,

계 클래스의 메서드이다.

void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2);

이곳의 콜백은 b2RayCastCallback 클래스의 가상 메서드로
float32 ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float32 fraction);

이다.

 이 가상 메서드는 리턴값을 갖는다.

 리턴값이 0인 경우 RayCast를 중단한다.
 리턴값은 0 ~ 1 사이의 값을 갖는다.
 리턴값이 -1인 경우 현재 시점에 접촉하는 상황을 완전히 무시한다.
 리턴값이 1인 경우 광선의 길이가 변하지 않는다.
 리턴값이 0 초과 1 미만인 경우 이 리턴값이 다음 광선 길이에 영향을 미친다.

 첫째 인자는 접촉된 고정체를 가져온다. 이 고정체들은 가까운 것에서부터 멀리 있는 것 순서에 따라 인자로 넘어오지 않는다. 어떠한 오래된 순서대로 리턴된다.

둘째,

 void QueryAABB(b2QueryCallback* callback, const b2AABB& aabb);

이며 b2QueryCallback 클래스의  가상 메서드인
 bool ReportFixture(b2Fixture* fixture);

이 콜백 메서드가 된다. 참값을 리턴하면 질의(탐색)가 계속 수행되며, 거짓을 리턴하면 질의는 중단된다.

다음은 AABB 질의의 사용 예 코드이다. 마우스로 드래그하여 사각형을 그리면 그 영역에 겹치는 AABB를 갖는 고정체들 중심에 점을 찍어 표시한다.

아쉽게도 MouseMove는 virtual이 아니다. 즉 콜백을 오버라이드 할 수 없었다.

#ifndef __MYWORLDQUERYINGTEST_H__
#define __MYWORLDQUERYINGTEST_H__

class MyQueryCallback : public b2QueryCallback {
  public:
      std::vector<b2Body*> foundBodies;
      
      bool ReportFixture(b2Fixture* fixture) {
          foundBodies.push_back( fixture->GetBody() ); 
          return true;//keep going to find all fixtures in the query area
      }
  };

class MyWorldQueryingTest : public Test {
public:

b2Vec2 mouseDownPos, mouseUpPos;

MyWorldQueryingTest(){
b2BodyDef myBodyDef;
myBodyDef.type = b2_staticBody;
myBodyDef.position.Set(0, 0);
b2Body* staticBody = m_world->CreateBody(&myBodyDef);

b2PolygonShape polygonShape;
b2EdgeShape edgeShape;

b2FixtureDef myFixtureDef;
myFixtureDef.shape = &edgeShape;

b2Vec2 bl(-20, 0);
b2Vec2 br(20, 0);
b2Vec2 tl(-20, 40);
b2Vec2 tr(20, 40);

edgeShape.Set( bl, br );
staticBody->CreateFixture(&myFixtureDef);
edgeShape.Set( tl, tr );
staticBody->CreateFixture(&myFixtureDef);
edgeShape.Set( bl, tl );
staticBody->CreateFixture(&myFixtureDef);
edgeShape.Set( br, tr );
staticBody->CreateFixture(&myFixtureDef);

myBodyDef.type = b2_dynamicBody;
myBodyDef.position.Set(0, 20);
polygonShape.SetAsBox(2, 2);
myFixtureDef.shape = &polygonShape;
myFixtureDef.density = 1;

for(int i = 0; i < 5; i++){
m_world->CreateBody(&myBodyDef)->CreateFixture(&myFixtureDef);
}
b2CircleShape circleShape;
circleShape.m_radius = 2;
myFixtureDef.shape = &circleShape;
for(int i = 0; i <5; i++){
m_world->CreateBody(&myBodyDef)->CreateFixture(&myFixtureDef);
}

m_world->SetGravity( b2Vec2(0, 0) );


}

void Step(Settings* settings){
Test::Step(settings);

b2Vec2 lower( b2Min(mouseDownPos.x,mouseUpPos.x), b2Min(mouseDownPos.y,mouseUpPos.y) );
b2Vec2 upper( b2Max(mouseDownPos.x,mouseUpPos.x), b2Max(mouseDownPos.y,mouseUpPos.y) );

                 //사각형 그리고
glColor3f(1,1,1);//white
glBegin(GL_LINE_LOOP);
glVertex2f(lower.x, lower.y);
glVertex2f(upper.x, lower.y);
glVertex2f(upper.x, upper.y);
glVertex2f(lower.x, upper.y);
glEnd();

MyQueryCallback queryCallback;
b2AABB aabb;
aabb.lowerBound = lower;
aabb.upperBound = upper;
                 //질의!!
m_world->QueryAABB( &queryCallback, aabb );


//draw a point on each body in the query area
glPointSize(6);
glBegin(GL_POINTS);

                 //질의 결과 queryCallback 클래스 멤버변수인 foundBodies에 저장된 고정체를 대상으로 중심점에 점을 박는다.
for (int i = 0; i < queryCallback.foundBodies.size(); i++) {
b2Vec2 pos = queryCallback.foundBodies[i]->GetPosition();
glVertex2f( pos.x, pos.y );
}
  glEnd();

}

void MouseDown(const b2Vec2& p){
b2Vec2 pp = p;
pp.y = pp.y - 1;

mouseDownPos = mouseUpPos = pp;
printf("ddown\n");
Test::MouseDown(pp);
}

void MouseUp(const b2Vec2& p){
b2Vec2 pp = p;
pp.y = pp.y - 1;

mouseUpPos = pp;

Test::MouseUp(pp);
}

        //호출되지 않는다.
void MouseMove(const b2Vec2& p){
b2Vec2 pp = p;
pp.y = pp.y - 1;

mouseUpPos = pp;
printf("dd\n");

Test::MouseMove(pp);
}

static Test* Create(){
return new MyWorldQueryingTest();
}
};

#endif

배운건, 아 전체를 다 뒤지지 않아도 되겠구나. 성능을 이렇게도 높일 수 있구나. 응용해 볼 수 있겠구나.

댓글 없음:

댓글 쓰기