절두체
절두체는 near 과 far 끝점으로 실제로 보여지는 공간을 피라미드형태로 표시합니다. 오우거에서는 카메라와 함께 사용되어 출력하는데 이용됩니다(카메라 클래스는 Frustum 클래스로부터 상속받습니다). 이 튜토리얼에서는 데칼을 화면상의 메쉬로 투영시키는데 절두체가 사용될 것 입니다.
프로젝터를 생성하기위해 첫번째로 해야 할 일은 사용될 절두체를 생성하고 SceneNode에 attach하는 일 입니다. createProjector함수에 다음코드를 추가하세요 :
mDecalFrustum = new Frustum();
mProjectorNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("DecalProjectorNode");
mProjectorNode->attachObject(mDecalFrustum);
mProjectorNode->setPosition(0,5,0);
이렇게 만들어진 프로젝터는 필름영사기와 유사하게 멀리갈수록 데칼 크기가 커지는 형태입니다. 거리에 상관없이 일정한 데칼의 크기, 모양을 유지하도록 생성시키고 싶다면 다음 코드를 추가하면 됩니다(하지만 지금은 그렇게 하지마세요) :
// Do not add this to the project
mDecalFrustum->setProjectionType(PT_ORTHOGRAPHIC);
mDecalFrustum->setNearClipDistance(25);
직교성 절두체의 field of view, 화면비율, near clip 거리를 설정하여 프로젝터가 떨어진 거리와는 상관없이 일정한 크기의 데칼이 표시되므로 적절한 크기와 형태를 사전에 예측해야 합니다.
더 진행하기전에 여기서 절두체가 어디로 데칼을 투영하며 비추고 있는지를 알아두세요. 이 프로그램에서는 링 형태로 오우거머리가 나열되어 있고 그 중앙에 절두체가 위치하며(5 unit거리만큼 살짝 떨어져 있긴 합니다) -Z방향을 바라보고 있습니다(방향을 따로 바꾸지 않은 기본값입니다). 최종적으로 데칼이 오우거머리의 뒷면을 투영하게 됩니다.
재질 변경
객체에 데칼이 보여지기 위해서는 객체가 데칼을 받을 수 있도록 되어야 합니다. 일반적인 텍스쳐위에 데칼이 그려지는 과정을 새로 하나 추가함으로써 구현합니다. 절두체는 투영될 데칼의 위치, 크기, 모양을 결정합니다. 이 데모에서는 데칼을 받을 수 있도록 객체의 재질을 직접적으로 수정을 가할 것 이지만 대부분의 실제 프로그램에서는 원본재질의 사본을 따로 보관해둠 으로써 원래재질로 되돌릴 수 있도록 해야 합니다.
가장먼저 해야 할 일은 재질 포인터를 얻고 재질처리단계를 하나 더 추가합니다. makeMaterialReceiveDecal함수를 찾아서 다음코드를 추가하세요 :
MaterialPtr mat = (MaterialPtr)MaterialManager::getSingleton().getByName(matName);
Pass *pass = mat->getTechnique(0)->createPass();
처리단계가 추가되었습니다. 이제 블렌딩과 조명에 대한 설정을 해야 합니다. 객체에 입혀진 기존의 텍스쳐와 혼합된 형태의 새로운 텍스쳐가 추가되어야 합니다. Scene blending을 Transparent alpha로 설정시켜주고 depth bias를 1로 설정합니다(즉 데칼은 투명처리가 되지 않습니다). 마지막으로 조명을 disable 시켜줌으로써 장면상의 조명값에의해 재질이 변함없이 보여질 수 있도록 합니다. 만약 데칼이 조명의 영향을 받도록 설정하고 싶다면 마지막줄 함수호출을 실행하지 않으면 됩니다 :
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
pass->setDepthBias(1);
pass->setLightingEnabled(false);
decal.png 이미지를 이용하여 새로운 텍스쳐상태를 생성합니다. 그리고 두번째 함수는 텍스쳐투영을 활성화시키고 생성된 절두체를 입력받습니다. 마지막 2개 함수들은 필터링과 어드레싱모드를 설정합니다 :
TextureUnitState *texState = pass->createTextureUnitState("decal.png");
texState->setProjectiveTexturing(true, mDecalFrustum);
texState->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
texState->setTextureFiltering(FO_POINT, FO_LINEAR, FO_NONE);
어드레싱모드를 clamp로 바꾸면 데칼이 객체위에 “반복”되어 나타나는걸 방지할 수 있습니다. 필터링옵션으로는 확대시 기본선형(standard linear)으로, 축소시에는(FO_POINT), 밉매핑시에는 아무런 옵션도 사용되지 않습니다. 이러한 옵션은 데칼이 최소화되었을때 데칼의 외곽경계선부분(투명색)이 흐릿해지는것을 방지해 줍니다. 이러한 옵션을 사용하지 않는다면 데칼이 투영된 바깥쪽이 무척 지저분해 보일 것 입니다.
이것으로 재질에 필요한 설정은 모두 끝났습니다.
함수호출
재질과 프로젝터를 설정하는 함수가 완성되었습니다. 설정을 실제로 적용시키기 위해서는 호출되어야 합니다. 다음 코드를 createScene멤버함수 마지막부분에 추가하세요 :
createProjector();
for (unsigned int i = 0; i < ent->getNumSubEntities(); i++)
makeMaterialReceiveDecal(ent->getSubEntity(i)->getMaterialName());
이전루프에서 ent변수에 오우거머리 엔티티를 이미 저장해뒀습니다. 사용되는 모든 오우거머리들은 동일한 재질이 사용되므로 랜덤하게 하나의 객체를 잡아서 그에 해당하는 재질이름을 얻어내기만 하면 됩니다.
컴파일 후 실행시켜보세요. 데칼이 투영된 오우거머리 몇개가 보일겁니다.
소개
프로그램을 실행시켰을때 눈치채셨을지도 모르겠습니다. 실제로는 2개의 데칼이 투영되었습니다. 하나는 절두체가 바라보는 -Z방향으로, 다른하나는 절두체의 뒷면인 +Z방향으로 오우거 머리를 투영하고있습니다. 이렇게 보이는 이유는 절두체의 정면으로 투영될때 절두체의 뒷면으로도 (반전된)데칼이 반응하기 때문입니다.
절대로 이런 결과를 원하지는 않습니다. 잠시후 뒷면투영현상을 제거하기위해 필터에 대해 소개드릴 것 입니다.
프로젝터 수정하기
뒷면투영현상을 걸러내기위해서 보이는방향만을 보여지게끔 필터기능을 가진 새로운 절두체가 필요합니다. createProjector멤버함수에 다음코드를 추가하세요 :
mFilterFrustum = new Frustum();
mFilterFrustum->setProjectionType(PT_ORTHOGRAPHIC);
SceneNode *filterNode = mProjectorNode->createChildSceneNode("DecalFilterNode");
filterNode->attachObject(mFilterFrustum);
filterNode->setOrientation(Quaternion(Degree(90),Vector3::UNIT_Y));
특별하게 새로운 코드는 보이지 않습니다. 이전코드와 다른점이 있다면 노드가 뒤로 바라보게끔 90도 회전한 것 뿐입니다.
재질 수정하기
재질에 추가시킨 텍스쳐 처리단계에 또다른 텍스쳐상태를 추가시켜야 합니다. MakeMaterialReceiveDecal에 다음코드를 추가하세요 :
texState = pass->createTextureUnitState("decal_filter.png");
texState->setProjectiveTexturing(true, mFilterFrustum);
texState->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
texState->setTextureFiltering(TFO_NONE);
이전코드와 큰 차이점이 없습니다. 절두체필터, 텍스쳐필터를 사용하고 필터링기능을 껐습니다. 이제 실행시켜보세요. 이제 정면으로 투영된 데칼만 보일 것 입니다.
간단한 회전
투영을 좀 더 화려하게 보이게 하기 위하여 프로젝터를 회전하고 Field of View를 갱신할 것 입니다. 다음코드를 frameStarted멤버함수에 추가하여 프로젝터를 회전시킵니다 :
mProjectorNode->rotate(Vector3::UNIT_Y, Degree(evt.timeSinceLastFrame * 10));
실행시켜 보세요. 원으로 배치된 오우거머리를 따라돌며 데칼이 투영됨을 볼 수 있을 것 입니다.
Field of View 수정하기
프로젝터의 field of view를 수정해 봅시다. Orthographic(직교성) 프로젝터를 사용하지 않았으므로 field of view값을 조절하여 투영되는 객체의 사이즈를 늘리거나 줄일 수 있습니다. 보여지기 위해서 FOVy (field of view Y)값이 15~25도 사이의 각도값이 되어야 합니다. 다음의 코드는 데칼의 사이즈를 늘리거나 줄이게 됩니다(frameStarted멤버함수에 추가하세요) :
mAnim += evt.timeSinceLastFrame / 2;
if (mAnim >= 1)
mAnim -= 1;
mDecalFrustum->setFOVy(Degree(15 + Math::Sin(mAnim * Math::TWO_PI) * 10));
이제 실행시켜 보세요.