게임엔진 제 7 강광원과그림자 이대현교수 한국산업기술대학교게임공학과
학습내용 광원의종류 평면메쉬의생성방법 광원의구현 그림자의종류와구현
광원의종류 : 주변광원 주변광원 (Ambient Light) 동일한밝기의빛이장면안의모든물체의표면에서일정하게반사되는것. 공간안에존재하는빛의평균값 이론적인광원
광원의종류 : 지향광원 지향광원 (Directional Light) 한방향으로무한히뻗어나가는빛. 빛이물체면을향하여일정한방향으로진행. 거리에상관없이특정한한방향 ( 벡터 ) 에대해서빛의세기가일정하게주어진다 방향이중요 태양을흉내낼때주로쓰임. OGRE 엔진 : LT_DIRECTIONAL
광원의종류 : 점광원 점광원 (Point Light) 공간안의한점에서모든방향으로동일하게뻗어나가는빛. 백열전구를모델링. 광원과물체표면과의거리의제곱에비례하여밝기가약해짐 ( 감쇄 : attenuation) 거리가중요 OGRE 엔진 : LT_POINT
광원의종류 : 점적광원 점적광원 (Spot Light) 정해진위치와범위만비추는광원. 일종의점광원이지만, 모든방향으로만퍼지는것이아니고, 특정방향으로지정된각도만큼빛이퍼져나감. 무대조명을모델링. 거리에따라서빛의세기가약해짐. OGRE 엔진 : LT_SPOTLIGHT
이번강의구현내용 : 어둠속의닌자
Y X Z
Y X Z
Y X Z
Y X Z
실습 Light 광원및그림자표현
PlayState.cpp void PlayState::enter() { 중략 mscenemgr->setambientlight(colourvalue(1.0f, 1.0f, 1.0f)); 실습 Plane plane( Vector3::UNIT_Y, 0 ); MeshManager::getSingleton().createPlane( "ground", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 500,500, 1,1, true,1,5,5, Vector3::UNIT_Z ); Entity* groundentity = mscenemgr->createentity( "GroundEntity", "ground" ); mscenemgr->getrootscenenode()->createchildscenenode()->attachobject(groundentity); ninjaentity = mscenemgr->createentity("ninja#1", "ninja.mesh"); ninjanode = mscenemgr->getrootscenenode()->createchildscenenode(); ninjanode->attachobject(ninjaentity); }
실행결과
평면메쉬의생성 생성방법 먼저평면을생성하고 (Plane 클래스사용 ), 그리고이것을메쉬로변환한다 (MeshManager 클래스사용 ) 평면의생성 두개의정보가필요 : 평면의법선벡터 (normal vector) 및평면과원점의거리 Plane plane(vector3::unit_y, 0); Y X Z
메쉬의생성 MeshManager 클래스 프로그램에서로드된모든메쉬들을관리하는클래스 메쉬이름. MeshManager::getSingleton().createPlane("ground", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500,1500,1,1,true,1,5,5,Vector3::UNIT_Z); 평면정보. 너비 : 1500 높이 : 1500
엔터티와장면노드의생성 앞에서만든메쉬의이름. Entity* groundentity = mscenemgr->createentity( "GroundEntity", "ground" ); mscenemgr->getrootscenenode()->createchildscenenode()->attachobject(groundentity); 장면노드의생성 장면노드에엔터티배치.
텍스쳐입히기 setmaterialname() 함수사용 Entity* groundentity = mscenemgr->createentity( "GroundEntity", "ground" ); mscenemgr->getrootscenenode()->createchildscenenode()->attachobject(groundentity); groundentity->setmaterialname( Examples/Rockwall ); material Examples/Rockwall { technique { pass { texture_unit { texture rockwall.tga } } } } lecturepack.zip 내의 Examples.material 에위치. Rockwall.tga 파일을이미지로사용.
텍스쳐가입혀진평면
PlayState.cpp 광원추가 void PlayState::enter() { 중략 mscenemgr->setambientlight(colourvalue(0.0f, 0.0f, 0.0f)); 실습 mlightd = mscenemgr->createlight("lightd"); mlightd->settype(light::lt_directional); mlightd->setdirection( Vector3( 0, -0.5f, -1 ) ); mlightd->setvisible(false); mlightp = mscenemgr->createlight("lightp"); mlightp->settype( Light::LT_POINT ); mlightp->setposition( Vector3(0, 150, -50) ); mlightp->setvisible(false); mlights = mscenemgr->createlight("lights"); mlights->settype( Light::LT_SPOTLIGHT ); mlights->setdirection( 0, -1, 0 ); mlights->setposition( Vector3( 0, 300, 0 ) ); mlights->setspotlightrange( Degree(20), Degree(50) ); mlights->setvisible(false); 후략
bool PlayState::frameStarted(GameManager* game, const FrameEvent& evt) { ninjanode->yaw(degree(1.0f)); 실습 game->captureinput(); if (game->iskeydown(kc_a)) { static float a = 0.0f; a = (a > 0.99f)? 0.0f : a + 0.01f; mscenemgr->setambientlight(colourvalue(a, a, a)); } else if (game->iskeydown(kc_d)) { mlightd->setvisible(!mlightd->getvisible()); } else if (game->iskeydown(kc_p)) { mlightp->setvisible(!mlightp->getvisible()); } else if (game->iskeydown(kc_s)) { mlights->setvisible(!mlights->getvisible()); } return!game->iskeydown(kc_escape); }
실행결과 : 종류별광원의실험
광원의생성 Light 클래스 SceneManager::createLight(): 광원생성 Light::setType(): 광원종류설정 Light::setPosition(): 광원의위치설정 Light::setDirection(): 광원의방향설정 광원객체를장면노드에소속시키면, 광원을이동하는것이가능함. 캐릭터를따라다니는광원을구현할수있슴. 광원의생성 mlightd = mscenemgr->createlight("lightd"); mlightd->settype(light::lt_directional); mlightd->setdirection( Vector3( 0.0f, -0.5f, -1.0f ) ); mlightd->setvisible(false); 광원의종류를설정. 지향광원으로설정함. 광원 ON/OFF 광원의방향설정.
점광원및점적광원의생성및설정 mlightp = mscenemgr->createlight("lightp"); mlightp->settype( Light::LT_POINT ); mlightp->setposition( Vector3(0, 0, -300) ); mlightp->setvisible(false); 점광원의위치결정. mlights = mscenemgr->createlight("lights"); mlights->settype( Light::LT_SPOTLIGHT ); mlights->setdirection( 0, -1, 0 ); mlights->setposition( Vector3( 0, 300, 0 ) ); mlights->setspotlightrange( Degree(20), Degree(50) ); mlights->setvisible(false); 점적광원의확산각도 ( 안쪽각도, 바깥쪽각도 ) 설정. 안쪽각도는 Direct3D 에만적용가능. OpenGL 에서는 0 도로간주.
그림자 실세계에서발생하는현상 공간감을높이는점에서매우중요함.
그림자 실세계에서발생하는현상 공간감을높이는점에서매우중요함.
Hard Shadow vs. Soft Shadow
근사그림자 (Approximate Shadow) 사람은그림자의대략적인모습을인식할뿐, 정확한모습에는낮은인지도를보임 이를이용하여조명과물체간의공간적위치를고려하여직접간단한그림자를추가. 사실성은떨어지지만, 별도의연산이필요없기때문에,
지면그림자 (Ground Shadow) 지면그림자 (Ground Plane Shadows) 투상그림자 (Projection Shadows) 바닥에투상된그림자만을고려. 물체면간의그림자는고려치않음
셰도우맵 (Shadow Map) 화소단위의영상공간알고리즘 1. 광원기준가장가까운물체면과의거리 (A) 를셰도우지 - 버퍼에저장 2. 은면제거를위해시점기준가장가까운물체면화소를구함 3. 해당화소물체면으로부터광원 (B) 까지의거리를구함. 4. B 가 A 보다크면해당화소는그림자영역내부에존재함.
그림자부피 (Shadow Volume) 가시부피와그림자부피가중첩되는곳이그림자영향권 보통 stencil buffer를사용하여구현 Stencil shadow라고도부름
스텐실버퍼생성알고리즘 다수개의다각형에의한그림자 그림자부피안으로들어갈때 + 1, 나갈때 -1 결과적인카운트값이 0보다크면그림자색
PlayState.cpp 그림자추가 void PlayState::enter() { 중략 mscenemgr->setambientlight(colourvalue(0.0f, 0.0f, 0.0f)); 실습 mscenemgr->setshadowtechnique(shadowtype_stencil_additive); 중략 Entity* groundentity = mscenemgr->createentity( "GroundEntity", "ground" ); mscenemgr->getrootscenenode()->createchildscenenode()->attachobject(groundentity); groundentity->setmaterialname("examples/rockwall"); groundentity->setcastshadows(false); ninjaentity = mscenemgr->createentity("ninja#1", "ninja.mesh"); ninjanode = mscenemgr->getrootscenenode()->createchildscenenode(); ninjanode->attachobject(ninjaentity); ninjaentity->setcastshadows(true); 후략
점광원에의한그림자
점적광원에의한그림자
지향광원에의한그림자
오우거엔진의그림자설정 그림자생성기법설정 void Ogre::SceneManager::setShadowTechnique ( ShadowTechnique technique ) SHADOWTYPE_STENCIL_ADDITIVE SHADOWTYPE_STENCIL_MODULATIVE SHADOWTYPE_TEXTURE_MODULATIVE mscenemgr->setshadowtechnique(shadowtype_stencil_additive); 그림자생성기법을스텐실그림자로설정
그림자표시여부결정 void Ogre::MovableObject::setCastShadows( bool enabled ) 기본값은 false: 그림자를표시하지않음. Entity* groundentity = mscenemgr->createentity( "GroundEntity", "ground" ); mscenemgr->getrootscenenode()->createchildscenenode()->attachobject(groundentity); groundentity->setmaterialname("examples/rockwall"); groundentity->setcastshadows(false); 평면은그림자를표시하지않도록설정. ninjaentity = mscenemgr->createentity("ninja#1", "ninja.mesh"); ninjanode = mscenemgr->getrootscenenode()->createchildscenenode(); ninjanode->attachobject(ninjaentity); ninjaentity->setcastshadows(true); 닌자는그림자를표시하도록설정.
Shadow Volume 과 Shadow Map 의비교 Shadow Volume 깨끗한실루엣표현가능 기하정보가증가 ( 속도저하 ) SHADOWTYPE_STENCIL_ADDITIVE SHADOWTYPE_STENCIL_MODULATIVE Shadow Map 빠르고유연함 많은게임에서사용되고있음 SHADOWTYPE_TEXTURE_MODULATIVE Aliasing: 그림자외곽에서계단현상 여러개선알고리즘이있음 PCF (Percentage Closer Filtering) LiSPSM (Light-Space Perspective Shadow Map)