728x90

이번에는 빌비치 시티를 공략해 봅시다.



맛도 좋고 사람과 포켓몬에게 좋은 코코넛 밀크! 단돈 800원! 하나 사실라우?



상태이상도 치료해줍니다. 나쁘지 않지만 패스.



줍줍



아까 아저씨가 팔던게 여기에 굴러다닙니다.



시계 필요하니? 아 이미 포케포드 가지고 있구나?

이봐, 레인져들에게 나 여깄다고 말하면 안돼 알겠지?


수상해서 찍었습니다.



여기 아이템이!



포켓몬 관장에게 도전했다가 전멸당함 ㅠ



백화점에 한번 가봅시다.



2층. 도구와 몬스터볼을 팝니다.

볼종류가 상당히 많습니다.



3층. 기술머신과 진화의 돌들을 파는데

기술머신이 아주 비쌉니다. 재사용 할 수 있다는 거에 위안을...

특이하게 (5, 6 세대를 안해서 잘 모르지만)

진화의 돌을 종류별로 팝니다. 개이득!



4층. 포켓몬 보충제와 배틀도구를 팝니다.

돈벌고 다시 옵시다.



5층. 희귀 상점으로 매일매일 파는 품목들이 달라집니다.



오늘은 메가진화를 할 수 있는 메가 스톤을 팝니다.

이건 스타팅 포켓몬 중 불꽃포켓몬의 것이라 사지 못했습니다. (사실 살 돈이 없습니다.)



공원에서 시비거는 커플.




날카로운 부리 줍줍.



줍줍줍.



여기도 줍줍.



이 건물에 들어가면



먼 타지에 있는 내 친구한테 이 알을 받았는데 내가 돌볼 수가 없어서



그런데.....



가져갈래?



알 득! 뭐가 나올지는 잘 모릅니다.



여기는 호텔&카지노

예약하려면 18살 이상부터입니다. ㅠ 왼쪽에는 카페 오른쪽에는 카지노가 있습니다.



카페의 이 아저씨한테 말을 걸면 포켓몬 몸단장을 하루에 한번 해줍니다.



Lovely Grooming : 포켓몬 친밀도 업!

Stat Boost Grooming : 받고 나면 선택하여 포켓몬의 스탯을 올릴 수 있습니다.

보충제가 9800원이니 훨씬 쌉니다.

Rare Grooming : 효과는 rare candy 즉 이상한 사탕과 같이 1레벨 업시켜 줍니다. (개이득!)



워이! 애들은 가라.. 오 너 포켓몬 트레이너구나!



어쨌든 간에 포켓몬 배틀도 일종의 도박이니까 (배틀을 돈걸고 하니)

널 막을 이유는 없지 (응? 내 논리는 법보다 위다!!!!!)



니가 우리 카지노에서 상품으로 제공하는 많은 희귀포켓몬들을

따고 싶은건 말할 것도 없지!



코인 케이스 득!



기분좋은 아저씨가 돈 줍니다.



딱히 가지고 싶은 포켓몬이 없습니다.

맨 밑에 있는 Tracton은 강철/드래곤 타입의 포켓몬인데 쓸모는 없어 보입니다.

도감을 위해서 언젠가는 구합시다.



포켓몬 레인저 건물에 들어서자마자 한 녀석이 호들갑을 떨며 말을 겁니다.


너 nobcat 맞지?



대장의 아이다!

어서 누가 Kellyn 데려와!



(아빠 등장)

여기 빌비치에서 뭐하고 있니?



맞아, 밤브오 박사를 위해 조사중이지.



놉캣, 무슨 말을 해야 할지.....

너를 마지막으로 본지 오랜 시간이 지났구나..



너의 도착을 예상하고 있어야 했어.

어쨌든 여기에 포켓몬 체육관이 있으니까.



너가 빌비치로 오는 것은 당연하지.



여전히.. 항상 포켓몬 레인저 본사를 네게 구경시켜 주고 싶었다.



여기는 전 Tandor 서부에서 가장 큰 포켓몬 레인저 본부다.

그리고, 너도 알다시피 난 그 대장이고.



큰 책임이 따르는 자리지.



그래서 너도 알듯이 나는 너무 바뻐왔다....

너무 바빠서 모키 타운의 너에게 갈 수 없었다.



정말.. 많이 컸구나 놉캣.

혼자여 여행도 다니고...



물론 나도 니 나이때 같았다.

나는 Almia 지역의 신입 후보생이었지....



그래, Theo는 어떠니?

너랑 그 아이 같이 모키 타운을 떠났지.



내 기억이 맞다면 그 아이는 여전히 네 뒤를 따라오고 있겠지.



방해해서 죄송합니다. 대장.

편지가 왔습니다.



편지? 음..

새 원자력 발전소의 Cameron (Theo 아빠) 한테서 왔군.



그가 말하길 공사는 순조롭고 새 발전소가 완전히 가동할 거라는 군.



그가 확실히 일을 착착 진행하는건 인정해야지.



새 발전소가 곧...



놉캣 갑작스러운거 알지만 네게 부탁이 있다.



네가 발전소로 가서 Cameron에게 내 대답을 전해주면 좋겠어.



일을 조심스럽게 진행해야 한다.



네 어미.. 루실이.. 10년전 그 very섬에서 사라졌다.

절대 잊어서는 안된다. (짤림)



내가 발전소에 널 기다리라고 말을 해두마.



내 생각에 Cameron이 널 보면 분명 좋아할거야.



나도 가고 싶지만 난 여기 남아서 새 레인저 후보생들을 가르쳐야해.



네가 잘 해낼 거라는걸 난 확신한단다.

넌 재 자식이니까. 어쨌든...


여기서 대화는 끝납니다.



아이템 줍줍.



모든 건물을 다 돌아봤으니 아마도 여기가 체육관일 것입니다.

근데 편지 배달을 먼저 해야 합니다. ㅠ



다음에 이어서 하죠.


끝!


728x90
728x90
원문 : http://mycom333.blogspot.kr/2014/01/axis-angle-rotation.html

위 블로그를 기초로 나름대로 정리해보았다. 정리라 쓰고 복사라 읽는다.



3차원 공간에서 i=(1,0,0), j=(0,1,0)일때  i를 Z축에 대해 회전시키면 다음과 같이 나타낼 수 있다.



이는 xy평면상의 회전과 같습니다.


이 식을 이용하여 i, j대신 v_perp, w를 사용하고 회전축은 A를 사용하겠습니다.





v_proj : 벡터 v를 A축에 대해 projection

v_perp : 벡터 v를 A축에 대해 perpendicular



위 식을 이용해 회전된 v_perp에 v_proj를 더하여 회전된 v를 얻을 수 있다.


즉 회전된 v는 다음과 같다.




먼저 v_proj부터 구하면


:  A의 unit vector


일때


이다.


v_perp + v_proj = v 로 v_perp를 구할 수 있다.




w는 회전축 A와 v의 외적으로 구해진다.



지금까지 구해진 것들로 식을 다시 쓰면




v를 분리하여 (행렬 * 벡터) 식으로 만들기 위해 tensor product와 skew matrix를 사용하여 정리합니다.



[tensor product]


두 벡터 v, w에 대해



세 벡터 u, v, w에 대해 다음 식이 성립한다.


(계산해보면 쉽게 알 수 있다.)



[skew matrix]


벡터 v, w의 외적을 skew matrix로 변환하여 행렬 * 벡터로 바꿀 수 있다.




이제 식을 정리하면


I : identity matrix



벡터 v를 분리 했으니 회전행렬 R이 될 부분을 정리하면





이 유도된 행렬을 이용하여 임의의 축 A를 기준으로 임의의 벡터 v를 회전시킬 수 있습니다.


728x90

'수학' 카테고리의 다른 글

법선 벡터의 변환  (0) 2022.01.02
선형 보간(lerp)과 구면 선형 보간(slerp)  (0) 2016.06.11
로지스틱 함수  (0) 2016.03.17
Perspective Projection Matrix(원근 투영 행렬)의 유도  (0) 2016.01.31
오일러 공식(Euler fomula)  (0) 2016.01.05
728x90

저번에 이어 도둑 잡으러 ㄱㄱ



밖에 나와 교수님을 위해 포켓몬을 잡고 있엉.

근데 재미없어 싸우자.




비킬생각이 없습니다. 위로위로



인간은 통과 못해!



다 쓰러트립시다.



미친놈 등장!



인간 여기서 뭐하는 중인가?

또 포켓몬들을 노예로 만드는 중인가?



포켓몬들은 너희들의 손아귀에서 풀려났다.

포켓몬들은 더이상 너희들의 노예가 되지 않을 것이다.



마늘소년 포켓몬 영웅이 여깄다.

이몸은 포켓몬들을 그 끔찍한 인간의 공간에서 발견했고



해방시켰다.

우리는 우리의 자유를 위해 싸울 것이다!! (우리?)



사.. 사람인가?




이몸이.. 우리가 져? 어떻게?

왜 너의 포켓몬들은 싸우는 거지?



너의 포켓몬들은 자유를 원하지 않는가?

그들은.... 너의 .. 친.. 친구? (눙물)



그건 불가능하다!

포켓몬과 인간은 공존할 수 없다.!



(같이 싸운 포켓몬들 도망)

동무! 다시 그곳으로 돌아가는 겐가? 어째서?

미친놈도 사라집니다.



니 덕분에 잃어버린 모든 포켓몬을 찾았어!



너가 도움이 필요할 것을 대비해 뒤따라왔어.



말풍선의 화살표모양이 잘못된 것 같습니다. 주인공 멘트인듯.

여러분 방금 녹색의 남자가 뛰어나가는 것을 봤나요?



그리고 충격적인 말.

걘 사람이 아냐

바로 포켓몬이야! (어쩐지)



우리 "도둑"은 정말로 마늘소년이라 부르는 포켓몬임 ㅇㅇ



서식지는 산의 외딴곳에 있어서 지금까지 사람들과 맞닥뜨리지 않았음 ㅇㅇ

(중략)

(사실 연구원들은 마늘소년이 나타날 것을 예상했고 주인공 테스트겸 겸사겸사 입니다.)



이제 우리 연구소 포켓몬들을 더 자유롭게 해줘야징 (마늘이 볼라고 일부러 가둬둠)



PST는 포켓몬 트레이너들에게 매우 유용한 도구가 될거야.



우리에게 필드 데이터를 주도록 되어 있음 ㅇㅇ



그러니 간수잘하세요. 나쁜놈들에게 가지 않게.



테스트 였다면 성공적으로 통과한 것 같아!

(아마 박사는 몰랐나 봅니다.)



너는 대단한 직관과 재능을 보였어. 님 짱



이봐 친구, 넌 완벽한 트레이너가 되기 위한 너의 길을 잘 걷고 있는 것 같아!



학습장치를 받습니다. 개이득



다음 체육관은 Bealbeach City 맞지?

(포켓몬 레인져 본사가 있는 그 곳입니다.)


이제 준비를 갖추고 빌비치시티로 떠납시다.



내려오는 길에 벌목꾼 한마디 잡아줍시다.




어머 너 누구니? 후훗 너 귀요민데?

(who are you 앞의 Like의 의미를 모르겠네요...)




겜덕. 쓰러트려 줍시다.




줍줍



아침에 빠른 배틀만한게 없어, 그치? 긔긔



캡쳐는 안했지만

위쪽과 왼쪽길로 나뉘는데 위쪽부터 갑시다.



새 여자아이를 낳았어! 여기 사진좀 볼래 우쭈쭈?


짤림;;



요 브로 정말로 노력해야해, 안그래?

(자기를 이기려면 노력해야 한다는 말인가? ㅠㅠ)




오른쪽 아래 이상한 사탕 득!



난 곤충타입 포켓몬을 키우는 걸 좋아해

이게 날 곤충 캐처로 만들까? 말해봐.




이이이이이이이이이봐 친구! 요즘 어때?

잠깐, 너 내 친구가 아닌 것 같은..




내 포켓몬을 훈련시키려고 샌드백을 찾아보고 있어.

얘를 이기고 왼쪽으로 갑시다.

(오른쪽 언덕 내려가면 아까 마늘소년한테 가는길)




개이득



아니 안물어(음?) 흥.

너에게 화풀이좀 할거야!!




오너라 애송아. 기꺼이 내 너에게 몸과 마음의 수양을 주마.



이제 아까 길 나뉘는 곳에서 왼쪽길입니다.



헤헤 벌레 짱.




어이 거기 이상한 녀석! 우리가 눈을 마주치자마자 알았어...

우리가 싸울 운명이라는 걸!




마 느 낚시할떄 미끼 어떤거 쓰는기가? 마 함 낚시해보자.




아까 그 할아버지 있는 곳으로 도착!

계단 올라가서 아래로 가면 막혀있으니 위로 갑시다.


트레이너들이 너무 많아서

배틀장면은 캡처하지 않았습니다. (절대 귀찮은거 아닙니다)



우린 영겁의 시간을 지나오고 있다.



나 킬트(치마) 2백만개를 안드로메다 은하로 배달해달라고 주문 하나를 받았어. 뭐지?



안녕! 나 땅파고 있어! 너만의 동굴을 가져봐!



호잇! 거기 애송이! 재치 대결 좋아하니? 싫어? 그럼 포켓몬 배트은 어때?


처음봐서 찍었음.


누군가 말하길 극한의 장소들에서의 훈련은 너를 터프하게 만들지. 덤벼!



벌레 회피 스프레이!



여기서 포켓몬들 회복시켜 줍니다.



이봐! 내 1337개의 기술들을 보고싶니? 싸우자!



대양은 신선한 물의 포켓몬과는 다른 종들을 가지지.



요! 해변이 꽤 멋지지, 안그래?

좋은 경치야 거기다 모든 종류의.. (짤림)



바다에선 가라앉거나 수영하거나(물에 뜨거나)지.

이건 포켓몬 배틀에서도 같아! (지거나 이기거나)



난 갈등을 초래하는걸 바라지 않아.

그러니 너에게 선택권을 주지. (짤림; 선택이 뭘까?)



검정띠!



히얍! 난 내 개쩌는 유도 기술로 니 포켓몬을 갈기갈기 썰어버릴 거야! (인성보소)



어이! 이게 누구야? 예아! 놉캣이네!

어..... 어 너 그 여행에서 살아남았구나. (동굴에서 도망간 놈)



거기서 얻은거 뭐야? 통역긴가 뭐시기 맞지? 예!



박사가 그거에 관해 알려주려 나한테 연락했고

그리고는 하나 보내줬지!



이제 우리 둘 다 포켓몬을 이해할 수 있어! 



어..어쨌든 나 Rochfale 통과하는데 개빡쳤어. (맞나?)

겁나 지루해 마을이! 나 그 이후 훈련하고 있어.



너보다 먼저 체육관장을 쓰러뜨릴거야 놉캣!

그전에 너부터다!



내가 Comet 동굴때문에 (도망 사건)

쉽게 갈거라고 생각지 마!



2마리 더 있는데 단골이니 안찍음요.



훌쩍. 나..나...나 신경 안써! 내 포켓몬들이 더 강해



그저 우리가 전에 (짤림) 해왔던 모든 배틀때문에 약했던 거야 (피로때문이라는 듯)



어..어쨌든 이 시합에서 경험좀 쌓았을 거야...



아 맞다! 나 지금 바로 체육관에 도전할 거야!

너보다 먼저 딸거니 보기나 해!



쾌청!

여기서 위로 쭉가면



도착!


이번거는 좀 길었네요 사실 밑에 트레이너 몇명 더 있는데

뭐 그정도야 굳이 안찍어도 될 것 같아서... 

다음에는 Bealbeach를 공략해 보죠 끝!

728x90
728x90


가봅시다.

쯧... 나 여기 높은 풀에 숨는거 좋아행.






여기는 잘 안보입니다. 저도 우연히;;



피곤하면 쉬어라.



소닉?



불새





반바지 덕후




길 한복판에 아이템이..



거 싸우기 좋은 곳이구먼




낚시 덕후




부딪혀서 미안해요.



포켓몬 센터로 급하게 가는중이어서

Comet 동굴의 어떤 포켓몬이 저와 제 포켓몬들을 공격했어염.



이 동굴을 지나갈 거라면 같이 갈 누군가를 찾는게 좋을거에요.

동굴로 긔긔



나 코메디언되려고 연습중이야 내가 재밌는 다리 개그 해줄게.



엄청 짧은 다리를 뭐라게 하게?

ABRIDGED! (요약된; 중간에 bridge가 들어감)

노잼을 처참하게 응징합시다.



뇌고기? 물/에스퍼 타입입니다.



번개의 돌!



ㅇㅋㅇㅋ 밟아줍시다.




왼쪽으로 오시면 막혀있습니다. 위로 ㄱㄱ



동굴 근처로 오면 띠오와 아저씨가 티격태격 하고 있습니다.

여기 동굴의 포켓몬은 특히 호전적이야!

트레이너들을 다구리 친단 말이야!



띠오가 배지를 보여주지만 그래도 인정하지 않으시는 아저씨



지나가는 주인공을 보고 띠오가 데려와서 들여보내달라고 합니다.



ㅇㅋㅇㅋ 긔긔

야생포켓몬과 만나고 나면 띠오가 포켓몬들을 회복시켜 줍니다.





이런식으로 더블 배틀이 됩니다.





흠...



실수로 안찍었는데 아이템 있습니다.



줍줍

왼쪽 위로 가시면 띠오는 도망가고 포켓몬들이 광폭해진 원인이 나타납니다.



간지는 좀 나지만 종족값이 마이나.. 땅/드래곤 입니다. (한카리아스?)



뜬금없이 아저씨 등장! 아까 그 사람인가?



님 Terlard랑 싸움? 걔네 짱 위험한데 ㄷㄷ!



Terlard의 두 머리가 싸울때 다른 포켓몬들을 귀찮게 해서

포켓몬들이 화가 났답니다.



탈출!





ㅇㅈ 예쁨



Rochfale 도착!



통통하고 노란 뱀.. 뭘까?

DunsparceSugimori 얘 입니다.


전 데리고 있으므로 바로 보여주니 엄청 좋아라 합니다. 아이템 주는데 또 안찍었네..

한번 더 말을 걸면 이번에는 물타입의 약한 포켓몬인데 진화하면 짱쎄짐 이었나라고 하며

보여달라고 하는데 뭔지 뭘라서 패쓰.

다음에 오죠.



포켓몬 바꾸자고 조르는애



얘네 둘인데 전 둘 다 별로.. 쩝.



왼쪽으로 가면 뱀브오 박사가 나타납니다.



이 마을에 있는 연구소로 급하게 가봐야 한다는데 같이 가자고 합니다.



오 왔구나! 도둑 잡은겨? 이 새끼야?



잘들어 꼬마야 넌 어제 밤 털 연구소를 잘 못 골랐어.



얘 도둑 아냐 내 연구 조수인 Nobcat이야.



게다가 아빠는 레인져 대장이야.

그리고 불라불라 말을 합니다.



연구를 위해 키우는 포켓몬들을 훔쳐갔답니다.



첨단 기술의 포켓몬 말 해석기! 줄여서 PST입니다.

이걸로 잃어버린 포켓몬 중 하나인 Owten에게 말을 겁니다.



<무셩! 무셩! 내 포켓볼 안에서 자고 있었엉. 갑자기 움직였엉!>



나와 친구들을 산 동굴을 향해 데려갔엉!



Owten의 말에 의하면 도둑은 여전히 마을 왼쪽에 있는 6번도로에 있습니다.

ㄱㄱ 합시다. 말이 끝나고 PST를 받습니다.



이렇게 포켓몬과 말을 할 수 있습니다. 다만 몇몇 포켓몬만 가능.



오늘은 여기까지!

728x90
728x90


너네 부모님도 강압적이시니? 우리 아빠에 대해 들어봐.....



나중에 불/벌레 타입이 되는 폭탄 벌레입니다.



포켓몬은 장난감이 아니야 임마.



덤벼 ㅇㅇ

캡쳐는 졸면서 하다보니 안찍었네요 ㅋㅋ



내가 사람들한테 내가 좋아하는 포켓몬을 말할때마다 날 이상하게 봐 ㅠ



바름.



여기 물의 돌이 있습니다.



중2병임.



안찍혔는데 여기 아이템 있습니다.



경험치 줍줍.



기술머신



농땡이?



벌레타입입니다. 진화하면 물/벌레



오랜만에 익숙한 놈.



버린 놈.



줍줍



왜 트래이닝중이었는데 알짱 거리셈?




거 배틀하기 좋은 날 이구먼!




줍줍



Burole Town 도착!!



흔한 Burole뽕.jpg



학교에서 애들이랑 싸웁시다.



무난



얘는 요주 인물 아주 악마입니다.



스타팅 3마리를 모두 가지고 있어서 풀타입 잡는데 애먹었습니다.

(상성이 ㅠㅠ)




이기고 너겟을 받읍시다.



Chyinmunk의 진화인 Kinetmunk가 생각보다 쎕니다.



야호!



이래봬도 상점입니다. 에너지 뿌리등을 팝니다.



이번 가이드도 신선한 물을 줍니다. 아무래도 매번 말을 걸면 주나봅니다.



주먹으로 바위를 부수며 단련했지롱!




난 몇년간 땅을 파오고 있어 넌 뭘 이루고 있니?




동굴에선 야생포켓몬이 어딘가에서 튀어나오지! 조심해!



못찍었는데 (ㅈㅅ)

바위 깨기로 바위를 깨면 막힌 문에 끼울 수 있는 조각이 나옵니다.



도착!



이렇게 4마리가 나옵니다.



알고보니 문의 홈에 끼운 조각이 배지였습니다!!

기술머신도 챙기고 다음 마을로 긔긔


끝!


728x90
728x90


밑으로 갑시다.



가볍게 경험치 줍줍



좋은 포션 줍줍



이 언덕을 1000번 오르면 허리가 강철처럼 단단해 질거라는 아저씨

박살냅시다.



가볍게

여담이지만 Barewl이 최종진화하면 순수 강철타입이 됩니다. (아저씨 복선?)



바위깨기도 있겠다. 이쪽으로 가죠.



줍줍



꺼져!



쓰레기뿐



가볍



글쎄요.. 할머니는 나이가..




전기로 지져줍시다.




여기 있는거 대신에 친구들과 놀고있는 중이어야 한다는건

안그러면 엄마한테 혼난다는 의미인가요?? 쨌든 경험치 줍줍




여기로 온 보람이 있었습니다.



이제 배지도 얻었겠다. 오래된 낚시대를 얻죠.



배지 하나에 이렇게 감동합니다.



득!



바로 나와서 잡았습니다. Nowtoch City로 가서 검은 양으로 바꾸죠.



그려그려



이름하번 예쁘게 지어놓았습니다.

참고로 이름 평가 아저씨한테 가면 매우 아름다운 완벽한 이름이라며

이름을 바꿔주지 않습니다. ㅠ



Moki Town에 도착하니 박사님이 말을 걸며 할말이 많다고 연구실로 데려갑니다.



첫 배지 얻은거 축하행!!



모든 8개 배지를 얻을 생각이면 다음 체육관은 오른쪽에 있는 Burole Town이닷!!



이 얘기만 하려고 데려온게 아니여

불라불라불라....................



포켓몬 잡은거랑 발견한거 검사하면서 열심히 모으라고 선물줄거라고 합니다.



한번더 말을 걸면 이상한 사탕을 주며 20마리 잡으면 상 준다고 합니다. 핡!



오늘은 여기까지!!!


728x90
728x90


Nowtoch City를 공략합시다.



저만 Chyinmunk 어떻게 발음하는지 궁금했던게 아닌가 보군요.

이 꼬마가 읽는법이 아마도 제작자가 읽는 방법이지 않을까 싶네요.



이 할아버지가 나중에 짬차면 특별한 기술을 가르쳐 줄 수 있다는데

언제가야 할지는 모릅니다.

* 여기 관장 깨고 찾아가도 같습니다.



이름 평가및 닉네임 변경하게 해주는 아저씨.

저는 포켓몬에 따로 닉네임 부여 안하니 패쓰.


  

그림 : http://pokemon-uranium.wikia.com/wiki/Tandor_Pokedex


Fortog를 Baashaum으로 바꿔준답니다.

Fortog는 Nowtoch 관장을 깨고 낚시대를 받아서

낚시로 잡을 수 있습니다. 나중에 다시 다루죠.



헤롱헤롱 기술머신을 줍니다.



귀... 귀여웡



줍줍



오늘 공식 오픈인데 안엽니다.

나중에 다시 와야할 것같습니다.



모든 지역 도시들을 연결한다는데

공중날기가 필요없을지도?



체육관을 찾아가면 체육관을 가로막은 아저씨가 관장찾으러 왔냐고 묻습니다.



집에 찾아가보면 있을거라고 자기는 사정이 있어 못간다는데..



마리아의 집열쇠 복사한 것을 건네줍니다.

아무래도 스토커인 것 같습니다.



캡쳐하지 않았지만 도시 남동쪽에 문이 잠겨있는 집이 있습니다.

거기로 가기 전에 옆에 초록색 건물을 들립시다.



아이템 줍줍



여기는 포켓몬 레인져 센터이며 레인져라 하면 주인공의 아버지가 대장으로 근무하고 있죠.

본사는 Bealbeach City에 있답니다. 아무래도 아버지가 거기 있겠죠.



줍줍



마리아의 집은 여기 있습니다.



열쇠 뺐김.



아무래도 평범한 스토커가 아닌가 봅니다. 마리아도 그 남자를 알고 있는 듯 합니다.



체육관으로 ㄱㄱ



ㄷㄷ 과거 리그 챔피언..



스토커의 흔한 변명.

"넌 재능있고 어리고 예쁜데 왜 이 모든 명예를 버렸어!!!"



노멀 타입 관장으로써 노멀함을 추구합니다.



레인져를 부르려 하자 도망갑니다.



(한숨)



드디어 배틀



처음에 체육관 가이드가 신선한 물을 줍니다.



관장을 쓰러트릴 방법을 지가 판단해준답니다.

절망을 줍시다.



무난하게 약합니다.



우리 관장님 첫번째라고 무시하지마! 챔피언 이었어!!



하품(Yawn)이 쫌 짜증납니다.



드뎌 관장

스토커가 말한 것처럼 예쁜것 같지는 않은 것 같습니다.



하품하면서 Owten과 자꾸 바꿉니다.

조져줍시다. 이걸로 끝!!!!!이 음?



더 있네?



패턴은 진화전과 똑같이 하품해대면서

할퀴기 열심히 합니다. 조금 아픔;;


뱃지와 은혜갚기 기술머신을 줍니다.



도시 밑으로 가면 띠오가 와서

관장한테 털렸다에 콩팥건다며 시비를 겁니다.



자기가 먼저 이길 예정이었다고 하니 아직 도전하지 않은것 같습니다.

자라나는 새싹을 사뿐히 즈려 밟아줍시다.

보통 정식 포켓몬 버전들은 라이벌이 먼저 체육관을 깨는데 반해

우라늄은 라이벌이 주인공을 열심히 따라오는 기분입니다.



cubbug의 진화형인 cubblfly입니다.

쓰레기답게 생긴것도 괴상합니다.



한방짜리.



이 치사빵꾸야 훌쩍!

이제야 기분이 좋아집니다.



사실 박사님 심부름으로 온거랍니다. 캡쳐를 못찍었는데

비전머신 바위깨기를 받습니다.

그리고 비전머신의 편지에 Moki Town으로 한번 들리라고 남겨져 있습니다.

Nowtoch City 끝.



728x90
728x90


Nowtoch 시티까지는 외길이니 쭉쭉 가봅시다.

먼저 Kevlar Town( 케블라? )로 가죠.



첫번째 야생 경험치가 배틀을 걸어옵니다.

박사님이 뚜드러 패신 Chyinmunk와 Birbie가 나옵니다.



밑쪽으로도 길이 나 있는데 거기에도 트레이너가 있습니다.

Owten이 나옵니다.



나무열매를 줍줍한 뒤 다시 왼쪽길로 갑시다.

밑에는 언덕이 있어 가지 못합니다.



중간에 집 한채가 있는데 Nowtoch 시티 관장 마리아를 이기면

오래된 낚시대를 준다고 합니다. 그리고 옆에 물가에 다양한 포켓몬이 나온다고 하는데

확인할 방법은 현재 없습니다.



강에 Fortog라는 독포켓몬이 산다고 해독제 들고 다니라고 합니다. 그외 별건 음슴



경험치 줍줍

Cubbug가 나옵니다.



경험치 줍줍

아까 말한 Fortog가 나옵니다.



Kevlar Town 도착!



자전거 집이 있는데 "바퀴"를 구해오면 고물자전거 하나 고쳐서 준다네요.



포켓몬 센터옆에 설명충에게 말을 걸어 줍시다.

해도그만 안해도 그만입니다.



2층에는 네트워크를 통한 통신이 가능합니다.

포켓몬이 구린 저는 당분간 이용할 생각이 없습니다.



포켓몬 센터 죽돌이.

Chyinmunk 3마리를 보유하고 있고

싸워서 이기면 바로 회복시키기 때문에 계속 배틀을 신청할 수 있습니다.

Chyinmunk를 버려야 이길텐데...... 돈은 많지만 좀 모자랍니다.



포켓몬샵 근처 어떤 여자가 울고있습니다. 내버려 두랍니다.



바로 위에 있는 꽃집에 가면 샘플 열매 몇개를 줍니다.



아까 울던 여자애 남자친구인가 봅니다.

삐져있는 여자친구를 위해 꽃을 사러 왔습니다.

이제 Nowtoch City로 갑시다.



Owten 둥지가 여기에 있다고 들었답니다.

경험치나 먹읍시다.



동굴 앞에서 경험치를 먹어줍시다.

망키하고 Barewl이 나오는데 Barewl은 강철/바위 타입입니다.



위쪽 길은 막혔으니 동굴로 ㄱㄱ



왼쪽에서 동굴탈출로프를 줍줍

오른쪽은 물로 막혀있으니 가운데로 갑시다.



남자중의 남자만이 동굴을 지나갈 수 있답니다.

(동굴의 포켓몬들 레벨 5~6 음?)

경험치나 먹읍시다.



복붙아닙니다.

2마리입니다.



100연승 못하면 동굴을 안나간답니다.

못나가게 합시다.



야생 Baashaun은 초반부에 나오지 않습니다.

가..갖고 싶다.



Great 볼 겟!



어디로 가도 상관없습니다.



다닐수 있는 길을 만들려고 조사중인 아저씨

험난하다며 선물을 줍니다.

한국어판으로 기력의 조각입니다.



여기는 오른쪽!

아무 트레이너들에게 해코지 하는걸 즐기는 성격 파탄자입니다.

조져줍시다.



무난하게 잡아줍시다.



모든 양아치들은 끝끝내 벌을 받는것 같다며

갑자기 착해집니다. (근성없는 녀석)



Nowtoch City 도착!


728x90
728x90


처음에 시작하면 게임 모드를 선택하라고 뜹니다.

너즐록 모드는 패널티가 부여된 모드로 배틀중 포켓몬 기절시 사망처리되어 없어지거나

한번 놓친 야생 포켓몬은 더 이상 못잡는 등의 패널티가 있어서 매우 어려운 모드입니다.

그래서 저는 레귤러 모드로 하였습니다.



이번 버전의 포켓몬 박사님.

"밤브오"로 읽는게 맞는건지..... 이 뒤에 발음하기 어려우면

걍 박사님이라고 부르라고 합니다.



참고로 아무생각없이 C버튼을 누르면 계속 이 선택지에서 Adventure가 선택되니

주의하시기 바랍니다.



여느 포켓몬 버전들과 달리 남성, 중성, 여성의 캐릭터들이 있으며 전 남성으로 하였습니다.



이름은 걍 키보드로 ㄷㄷ



그리고 대부분의 회상씬 캡쳐는 귀찮아서 안했습니다.



포켓몬 레인저 아빠, 원자력 에너지를 연구하는 엄마.

잘 지내는 어느 날 원자로의 정기 검사를 하는 도중 온도가 비정상적으로 치솟으며 폭발하였습니다.



엄마를 제외한 모든 연구원들은 무사히 대피하였습니다.



망가진 원자로에서 흘러나온 방사선은 주위 환경을 아무도 살지 못하도록 바꿔놓았습니다.



아내를 잃고 변해버린 아빠, 그 이후 일에만 몰두하였고 포켓몬 레인저의 대장으로 승진하였습니다.

그러나 그러는 와중 아들에게 신경쓰지 않았고 우리의 주인공은 이모에게 맡겨집니다.

그리고 아내인 루실을 찾으려 했지만 모두 물거품이 되었습니다.



그리고 시작!



떠나기에 앞서 이모에게 작별인사를 합시다.



러닝슈즈 겟! Z버튼을 누르고 있으면 달리며 메뉴에서 토글키를 등록할 수 있습니다.

그리고 한동안 이모가 훌쩍거리며 말을 계속하니 쭉쭉 누릅시다.



그리고 바로 연구소(마을 왼쪽 위)로 가면 도중에 라이벌 Theo를 만나는데 이모와의 대화에서도 알 수 있듯이

연구소에서 루실이 사라질때 마지막으로 불렀던 아저씨(이름 까먹음)의 아들입니다.

아무생각도 없었는데 더 강한 포켓몬을 자기보다 먼저 가지려 했다며 뛰어갑니다. 허언증이 있습니다.



그리고 드디어 밤보 박사. 대화내용은 여느 포켓몬과 같이 포켓몬 많이 잡고 여행해서 자기를 도우라고 합니다.



포켓몬 선택에 앞서 적성검사를 해야합니다. (음?)

우라늄버전에서는 원하는 포켓몬을 선택하는 것이 아니라

 트레이너의 성향에 따라 포켓몬을 결정해줍니다.



Q1. 새로운 종류의 포켓몬을 야생에서 만나면 취할 행동은?

저는 물포켓몬을 받고 싶으므로 "파란색"답변만을 선택하였습니다.



Q2. 다음 기술머신중 여러분의 포켓몬에게 어떤 것을 가르치고 싶습니까?

잠재파워!



Q3. 다음 포켓몬중 제일 쎈놈은? (갸라도스 글라이온 전룡순)

전룡



Q4. 포켓몬 트레이너가 되려는 동기는?

친구를 만들려고 (주륵...)



예상대로 물포켓몬인 Eletux를 받았습니다.



특이한 점은 다른 정식 버전들과 달리 라이벌이 상성관계에서 아래로 시작합니다.



그래서 삐지죠.



그래도 마음씨 넓은 박사님 : 섣부르게 허언증인 저 새끼를 판단하지마 어쨌든 아직 애잖아.



Theo를 달래서 1번 도로로 오랍니다.



이 아주머니(?)가 이상한 사탕을 줍니다.



Theo의 집에 오자마자 Theo는 위층으로 가버리고 그걸 본 아저씨는 화를 냅니다.



자초지종을 설명하니 납득하심. 그리고 Theo를 부릅니다.



훌쩍

한참 설교끝에 주인공의 아버지가 보낸 POKEPOD를 Theo와 주인공에게 건네줍니다.



받음

이제 1번 도로로 갑시다. (다른 NPC들은 암것도 안줍니다.)


기다리고 있던 박사님

이제 포켓몬 잡는 법을 가르쳐 주십니다.



포켓몬을 사랑하는 박사님은 오늘도 포켓몬을 잡기위해

사정없이 때려서 기진맥진하게 만들고 너덜너덜해진 포켓몬을

포켓볼에 넣습니다.



이전에 사진을 못찍었는데 (다시 하기 귀찮)

포켓몬 도감을 줍니다. 그리고 포케볼도 겟!

그리고 또 못찍었는데 도감을 채우면 상을 준다고 했습니다. 그리고 박사님은 돌아갑니다.



급 성숙해진 허언 띠오

최고가 될테니 지켜보라며 떠납니다.

띠오는 최고가 될 것입니다. 최고의 경험치 셔틀이..



이것으로 모키타운 끝!


728x90
728x90

원문 : http://www.rastertek.com/dx11tut16.html



Tutorial 16: Frustum Culling


모든 것이 그려지는 화면상의 3차원 뷰잉 영역은 "뷰잉 프러스텀(절두체)"이라고 부른다. 프러스텀안에 있는 모든 것들은 비디오카드에 의해 화면에 렌더링될 것입니다. 프러스텀 밖에 있는 모든 것들은 비디오 카드가 조사하고 렌더링 처리시 폐기할 것입니다.


그러나 골라내기 위해 비디오 카드에 의존한 처리는 우리가 큰 씬을 가지고 있다면 비쌀 수 있습니다. 예를 들어 각각 5000개의 폴리곤으로 이루어진 모델이 2000개 이상 있지만 주어진 시간에 10~20개만 볼 수 있는 씬을 가지고 있습니다. 비디오 카드는 씬에서 1990개의 모델들을 지우기 위해 모든 2000개의 모델들의 모든 삼각형들을 조사해야 하며 그래야 모델 10개를 그릴 수 있습니다. 보시다시피 이건 매우 비효율적입니다.


프러스텀 컬링이 우리의 문제를 해결하는 방법은 렌더링 전에 모델이 프러스텀 안에 있는지 아닌지를 대신에 알 수 있습니다. 이는 모든 삼각형을 비디오 카드에 보내는 것을 막아주며 그려질 삼각형만을 보내게 해줍니다. 이것을 하는 방법은 각 모델 주위로 큐브, 직육면체나 구를 놓고 큐브, 직육면체나 구가 볼 수 있는지를 계산하는 것입니다. 이것에 필요한 수학은 코드 몇줄로 되어 있으며 몇천개의 삼각형의 계산을 없애줍니다.


어떻게 동작하는지 설명하기 위해 먼저 랜덤하게 배치된 구 25개가 있는 씬을 만들 것입니다. 우리의 뷰 밖의 구들을 컬링하기 위해 손수 방향키를 왼쪽 오른쪽 누르며 카메라를 회전시킬 것입니다. 또 카운터를 사용하고 그려지고 있는 구들과 컬링 되지 않은 구들의 개수를 나타낼 것입니다. 씬을 만들기 위해 이전 몇몇 강좌들로 부터의 코드를 사용할 것입니다.



Framework


프레임워크는 거의 이전 몇몇 강좌들의 클래스들을 가집니다. 새로운 새 클래스 3개는 FrustumClass, PositionClass, ModelListClass입니다. FrustumClass은 이번 강좌가 포커스를 맞춘 프러스텀 컬링 기술을 캡슐화할 것입니다. ModelListClass는 우리가 프로그램을 실행할 때마다 랜덤하게 생성될 25개 구의 위치와 색상 정보의 리스트를 포함할 것입니다. PositionClass은 사용자가 누르고 있는 방향키에 따라 카메라의 회전을 처리할 것입니다.




Frustumclass.h


FrustumClass의 헤더 파일은 상당히 간단합니다. 클래스는 어떤 초기화나 정리가 필요하지 않습니다. 매 프레임마다 카메라가 렌더링되고 난 뒤 ConstructFrustum 함수가 호출됩니다. ConstructFrustum 함수는 갱신된 보는 위치에 따른 뷰 프러스텀의 6면을 계산하고 저장하기 위해 private m_planes를 사용합니다. 그로부터 점, 큐브, 구, 직육면체가 뷰잉 프러스텀 안에 있는지 아닌지 보기 위해 4가지 체크 함수들 아무거나 호출할 수 있습니다.


////////////////////////////////////////////////////////////////////////////////
// Filename: frustumclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _FRUSTUMCLASS_H_
#define _FRUSTUMCLASS_H_


//////////////
// INCLUDES //
//////////////
#include <d3dx10math.h>


////////////////////////////////////////////////////////////////////////////////
// Class name: FrustumClass
////////////////////////////////////////////////////////////////////////////////
class FrustumClass
{
public:
	FrustumClass();
	FrustumClass(const FrustumClass&);
	~FrustumClass();

	void ConstructFrustum(float, D3DXMATRIX, D3DXMATRIX);

	bool CheckPoint(float, float, float);
	bool CheckCube(float, float, float, float);
	bool CheckSphere(float, float, float, float);
	bool CheckRectangle(float, float, float, float, float, float);

private:
	D3DXPLANE m_planes[6];
};

#endif


Frustumclass.cpp


////////////////////////////////////////////////////////////////////////////////
// Filename: frustumclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "frustumclass.h"


FrustumClass::FrustumClass()
{
}


FrustumClass::FrustumClass(const FrustumClass& other)
{
}


FrustumClass::~FrustumClass()
{
}


ConstructFrustum은 매 프레임마다 GraphicsClass에 의해 호출됩니다. 화면의 깊이와 투영 행렬 그리고 뷰 행렬을 취합니다. 이 파라미터 변수들을 해당 프레임에서 뷰 프러스텀의 행렬을 계산하기 위해 사용합니다. 새 프러스텀 행렬과 함께 뷰 프러스텀을 형성하는 여섯 면을 계산합니다.


void FrustumClass::ConstructFrustum(float screenDepth, D3DXMATRIX projectionMatrix, D3DXMATRIX viewMatrix)
{
	float zMinimum, r;
	D3DXMATRIX matrix;

	
	// Calculate the minimum Z distance in the frustum.
	zMinimum = -projectionMatrix._43 / projectionMatrix._33;
	r = screenDepth / (screenDepth - zMinimum);
	projectionMatrix._33 = r;
	projectionMatrix._43 = -r * zMinimum;

	// Create the frustum matrix from the view matrix and updated projection matrix.
	D3DXMatrixMultiply(&matrix, &viewMatrix, &projectionMatrix);

	// Calculate near plane of frustum.
	m_planes[0].a = matrix._14 + matrix._13;
	m_planes[0].b = matrix._24 + matrix._23;
	m_planes[0].c = matrix._34 + matrix._33;
	m_planes[0].d = matrix._44 + matrix._43;
	D3DXPlaneNormalize(&m_planes[0], &m_planes[0]);

	// Calculate far plane of frustum.
	m_planes[1].a = matrix._14 - matrix._13; 
	m_planes[1].b = matrix._24 - matrix._23;
	m_planes[1].c = matrix._34 - matrix._33;
	m_planes[1].d = matrix._44 - matrix._43;
	D3DXPlaneNormalize(&m_planes[1], &m_planes[1]);

	// Calculate left plane of frustum.
	m_planes[2].a = matrix._14 + matrix._11; 
	m_planes[2].b = matrix._24 + matrix._21;
	m_planes[2].c = matrix._34 + matrix._31;
	m_planes[2].d = matrix._44 + matrix._41;
	D3DXPlaneNormalize(&m_planes[2], &m_planes[2]);

	// Calculate right plane of frustum.
	m_planes[3].a = matrix._14 - matrix._11; 
	m_planes[3].b = matrix._24 - matrix._21;
	m_planes[3].c = matrix._34 - matrix._31;
	m_planes[3].d = matrix._44 - matrix._41;
	D3DXPlaneNormalize(&m_planes[3], &m_planes[3]);

	// Calculate top plane of frustum.
	m_planes[4].a = matrix._14 - matrix._12; 
	m_planes[4].b = matrix._24 - matrix._22;
	m_planes[4].c = matrix._34 - matrix._32;
	m_planes[4].d = matrix._44 - matrix._42;
	D3DXPlaneNormalize(&m_planes[4], &m_planes[4]);

	// Calculate bottom plane of frustum.
	m_planes[5].a = matrix._14 + matrix._12;
	m_planes[5].b = matrix._24 + matrix._22;
	m_planes[5].c = matrix._34 + matrix._32;
	m_planes[5].d = matrix._44 + matrix._42;
	D3DXPlaneNormalize(&m_planes[5], &m_planes[5]);

	return;
}


CheckPoint는 한 점이 뷰잉 프러스텀안에 있는지를 확인합니다. 4개의 확인 알고리즘중 가장 일반적이지만 특정 상황에서 잘 쓰면 매우 효율적입니다. 한 점을 받아서 모든 여섯 면안에 있는지를 확인합니다. 안에 있다면 true를 반환하고 그렇지 않으면 false를 반환합니다.


bool FrustumClass::CheckPoint(float x, float y, float z)
{
	int i;


	// Check if the point is inside all six planes of the view frustum.
	for(i=0; i<6; i++) 
	{
		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3(x, y, z)) < 0.0f)
		{
			return false;
		}
	}

	return true;
}


CheckCube는 큐브의 여덟 꼭지점이 뷰잉 프러스텀에 있는지를 확인합니다. 파라미터로 큐브의 중앙점과 반경을 요구하며 큐브의 여덟 꼭지점을 계산하는데 사용합니다. 그러고는 뷰잉 프러스텀의 모든 6면안에 한 꼭지점이라도 있는지를 확인합니다. 찾으면 true를 그렇지 않으면 false를 반환합니다.


bool FrustumClass::CheckCube(float xCenter, float yCenter, float zCenter, float radius)
{
	int i;


	// Check if any one point of the cube is in the view frustum.
	for(i=0; i<6; i++) 
	{
		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter - radius), (yCenter - radius), (zCenter - radius))) >= 0.0f)
		{
			continue;
		}
		
		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter + radius), (yCenter - radius), (zCenter - radius))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter - radius), (yCenter + radius), (zCenter - radius))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter + radius), (yCenter + radius), (zCenter - radius))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter - radius), (yCenter - radius), (zCenter + radius))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter + radius), (yCenter - radius), (zCenter + radius))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter - radius), (yCenter + radius), (zCenter + radius))) >= 0.0f)
		{
			continue;
		}
		
		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter + radius), (yCenter + radius), (zCenter + radius))) >= 0.0f)
		{
			continue;
		}

		return false;
	}

	return true;
}


CheckSphere는 중심점에서 구의 반경이 뷰잉 프러스텀의 모든 여섯 면안에 있는지를 확인합니다. 밖에 있다면 구는 보여질 수 없고 함수는 false를 반환할 것입니다. 안에 있다면 함수는 구가 보여질 수 있는 true를 반환합니다.


bool FrustumClass::CheckSphere(float xCenter, float yCenter, float zCenter, float radius)
{
	int i;


	// Check if the radius of the sphere is inside the view frustum.
	for(i=0; i<6; i++) 
	{
		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3(xCenter, yCenter, zCenter)) < -radius)
		{
			return false;
		}
	}

	return true;
}


CheckRectangle은 큐브의 단일 반경 대신 직육면체의 x반경, y반경, z반경을 파라미터로 취하는 것을 제외하고는 CheckCube와 똑같이 동작합니다. 직육면체의 여덟 꼭지점을 계산하여 CheckCube 함수와 비슷하게 프러스텀 확인을 합니다.


bool FrustumClass::CheckRectangle(float xCenter, float yCenter, float zCenter, float xSize, float ySize, float zSize)
{
	int i;


	// Check if any of the 6 planes of the rectangle are inside the view frustum.
	for(i=0; i<6; i++)
	{
		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter - xSize), (yCenter - ySize), (zCenter - zSize))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter + xSize), (yCenter - ySize), (zCenter - zSize))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter - xSize), (yCenter + ySize), (zCenter - zSize))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter - xSize), (yCenter - ySize), (zCenter + zSize))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter + xSize), (yCenter + ySize), (zCenter - zSize))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter + xSize), (yCenter - ySize), (zCenter + zSize))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter - xSize), (yCenter + ySize), (zCenter + zSize))) >= 0.0f)
		{
			continue;
		}

		if(D3DXPlaneDotCoord(&m_planes[i], &D3DXVECTOR3((xCenter + xSize), (yCenter + ySize), (zCenter + zSize))) >= 0.0f)
		{
			continue;
		}

		return false;
	}

	return true;
}


Modellistclass.h


ModelListClass은 씬에서 모든 모델들에 관한 정보를 유지하기 위한 새 클래스입니다. 이번 강좌에는 한가지 타입의 모델만 있어서 구 모델들의 위치와 색상을 유지합니다. 이 클래스는 다른 유형의 모델들을 유지하고 모델들의 ModelClass를 색인하기 위해 확장될 수 있으나 지금은 강좌를 간단하게 유지합니다.


///////////////////////////////////////////////////////////////////////////////
// Filename: modellistclass.h
///////////////////////////////////////////////////////////////////////////////
#ifndef _MODELLISTCLASS_H_
#define _MODELLISTCLASS_H_


//////////////
// INCLUDES //
//////////////
#include <d3dx10math.h>
#include <stdlib.h>
#include <time.h>


///////////////////////////////////////////////////////////////////////////////
// Class name: ModelListClass
///////////////////////////////////////////////////////////////////////////////
class ModelListClass
{
private:
	struct ModelInfoType
	{
		D3DXVECTOR4 color;
		float positionX, positionY, positionZ;
	};

public:
	ModelListClass();
	ModelListClass(const ModelListClass&);
	~ModelListClass();

	bool Initialize(int);
	void Shutdown();

	int GetModelCount();
	void GetData(int, float&, float&, float&, D3DXVECTOR4&);

private:
	int m_modelCount;
	ModelInfoType* m_ModelInfoList;
};

#endif


Modellistclass.cpp


///////////////////////////////////////////////////////////////////////////////
// Filename: modellistclass.cpp
///////////////////////////////////////////////////////////////////////////////
#include "modellistclass.h"


생성자는 모델 정보 리스트를 null로 초기화합니다.


ModelListClass::ModelListClass()
{
	m_ModelInfoList = 0;
}


ModelListClass::ModelListClass(const ModelListClass& other)
{
}


ModelListClass::~ModelListClass()
{
}


bool ModelListClass::Initialize(int numModels)
{
	int i;
	float red, green, blue;


먼저 사용될 모델들의 개수를 저장하고 ModelInfoType 구조체를 사용하여 모델들의 리스트 배열을 생성합니다.


	// Store the number of models.
	m_modelCount = numModels;

	// Create a list array of the model information.
	m_ModelInfoList = new ModelInfoType[m_modelCount];
	if(!m_ModelInfoList)
	{
		return false;
	}


난수 발생기의 Seed값을 현재 시간으로 하고 모델들의 색상과 위치를 무작위로 생성하고 리스트 배열에 저장합니다.


	// Seed the random generator with the current time.
	srand((unsigned int)time(NULL));

	// Go through all the models and randomly generate the model color and position.
	for(i=0; i<m_modelCount; i++)
	{
		// Generate a random color for the model.
		red = (float)rand() / RAND_MAX;
		green = (float)rand() / RAND_MAX;
		blue = (float)rand() / RAND_MAX;

		m_ModelInfoList[i].color = D3DXVECTOR4(red, green, blue, 1.0f);

		// Generate a random position in front of the viewer for the mode.
		m_ModelInfoList[i].positionX = (((float)rand()-(float)rand())/RAND_MAX) * 10.0f;
		m_ModelInfoList[i].positionY = (((float)rand()-(float)rand())/RAND_MAX) * 10.0f;
		m_ModelInfoList[i].positionZ = ((((float)rand()-(float)rand())/RAND_MAX) * 10.0f) + 5.0f;
	}

	return true;
}


Shutdown 함수는 모델 정보 리스트 배열을 해제합니다.


void ModelListClass::Shutdown()
{
	// Release the model information list.
	if(m_ModelInfoList)
	{
		delete [] m_ModelInfoList;
		m_ModelInfoList = 0;
	}

	return;
}


GetModelCount은 이 클래스가 정보를 가지는 모델들의 개수를 반환합니다.


int ModelListClass::GetModelCount()
{
	return m_modelCount;
}


GetData 함수는 주어진 인덱스 위치의 구의 위치와 색상을 추출합니다.


void ModelListClass::GetData(int index, float& positionX, float& positionY, float& positionZ, D3DXVECTOR4& color)
{
	positionX = m_ModelInfoList[index].positionX;
	positionY = m_ModelInfoList[index].positionY;
	positionZ = m_ModelInfoList[index].positionZ;

	color = m_ModelInfoList[index].color;

	return;
}


Graphicsclass.h


////////////////////////////////////////////////////////////////////////////////
// Filename: graphicsclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _GRAPHICSCLASS_H_
#define _GRAPHICSCLASS_H_


/////////////
// GLOBALS //
/////////////
const bool FULL_SCREEN = true;
const bool VSYNC_ENABLED = true;
const float SCREEN_DEPTH = 1000.0f;
const float SCREEN_NEAR = 0.1f;


이번 강좌의 GraphicsClass는 이전 강좌들에서 사용했던 많은 클래스들을 인클루드합니다. 새로운 frustumclass.h와 modellistclass.h도 인쿨루드합니다.


///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "d3dclass.h"
#include "cameraclass.h"
#include "textclass.h"
#include "modelclass.h"
#include "lightshaderclass.h"
#include "lightclass.h"
#include "modellistclass.h"
#include "frustumclass.h"


////////////////////////////////////////////////////////////////////////////////
// Class name: GraphicsClass
////////////////////////////////////////////////////////////////////////////////
class GraphicsClass
{
public:
	GraphicsClass();
	GraphicsClass(const GraphicsClass&);
	~GraphicsClass();

	bool Initialize(int, int, HWND);
	void Shutdown();
	bool Frame(float);
	bool Render();

private:


새로운 두 private 클래스 객체는 m_Frustum와 m_ModelList입니다.


	D3DClass* m_D3D;
	CameraClass* m_Camera;
	TextClass* m_Text;
	ModelClass* m_Model;
	LightShaderClass* m_LightShader;
	LightClass* m_Light;
	ModelListClass* m_ModelList;
	FrustumClass* m_Frustum;
};

#endif


Graphicsclass.cpp


이전 강좌들 이후 달라진 함수들만 다룰 것입니다.


////////////////////////////////////////////////////////////////////////////////
// Filename: graphicsclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "graphicsclass.h"


생성자는 private 멤버 변수들을 null로 초기화합니다.


GraphicsClass::GraphicsClass()
{
	m_D3D = 0;
	m_Camera = 0;
	m_Text = 0;
	m_Model = 0;
	m_LightShader = 0;
	m_Light = 0;
	m_ModelList = 0;
	m_Frustum = 0;
}


bool GraphicsClass::Initialize(int screenWidth, int screenHeight, HWND hwnd)
{
	bool result;
	D3DXMATRIX baseViewMatrix;

		
	// Create the Direct3D object.
	m_D3D = new D3DClass;
	if(!m_D3D)
	{
		return false;
	}

	// Initialize the Direct3D object.
	result = m_D3D->Initialize(screenWidth, screenHeight, VSYNC_ENABLED, hwnd, FULL_SCREEN, SCREEN_DEPTH, SCREEN_NEAR);
	if(!result)
	{
		MessageBox(hwnd, L"Could not initialize Direct3D.", L"Error", MB_OK);
		return false;
	}

	// Create the camera object.
	m_Camera = new CameraClass;
	if(!m_Camera)
	{
		return false;
	}

	// Initialize a base view matrix with the camera for 2D user interface rendering.
	m_Camera->SetPosition(0.0f, 0.0f, -1.0f);
	m_Camera->Render();
	m_Camera->GetViewMatrix(baseViewMatrix);

	// Create the text object.
	m_Text = new TextClass;
	if(!m_Text)
	{
		return false;
	}

	// Initialize the text object.
	result = m_Text->Initialize(m_D3D->GetDevice(), m_D3D->GetDeviceContext(), hwnd, screenWidth, screenHeight, baseViewMatrix);
	if(!result)
	{
		MessageBox(hwnd, L"Could not initialize the text object.", L"Error", MB_OK);
		return false;
	}

	// Create the model object.
	m_Model = new ModelClass;
	if(!m_Model)
	{
		return false;
	}


이번 강좌를 위해 큐브 모델 대신 구 모델을 로드합니다.


	// Initialize the model object.
	result = m_Model->Initialize(m_D3D->GetDevice(), L"../Engine/data/seafloor.dds", "../Engine/data/sphere.txt");
	if(!result)
	{
		MessageBox(hwnd, L"Could not initialize the model object.", L"Error", MB_OK);
		return false;
	}

	// Create the light shader object.
	m_LightShader = new LightShaderClass;
	if(!m_LightShader)
	{
		return false;
	}

	// Initialize the light shader object.
	result = m_LightShader->Initialize(m_D3D->GetDevice(), hwnd);
	if(!result)
	{
		MessageBox(hwnd, L"Could not initialize the light shader object.", L"Error", MB_OK);
		return false;
	}

	// Create the light object.
	m_Light = new LightClass;
	if(!m_Light)
	{
		return false;
	}

	// Initialize the light object.
	m_Light->SetDirection(0.0f, 0.0f, 1.0f);


여기서 새로운 ModelListClass를 만들고 25개의 무작위로 위치하고 칠해진 구 모델들을 생성시킵니다.


	// Create the model list object.
	m_ModelList = new ModelListClass;
	if(!m_ModelList)
	{
		return false;
	}

	// Initialize the model list object.
	result = m_ModelList->Initialize(25);
	if(!result)
	{
		MessageBox(hwnd, L"Could not initialize the model list object.", L"Error", MB_OK);
		return false;
	}


여기서 새로운 FrustumClass객체를 만듭니다. ConstructFrustum 함수를 이용하여 매 프레임마다 수행되게 때문에 초기화할 필요는 없습니다.


	// Create the frustum object.
	m_Frustum = new FrustumClass;
	if(!m_Frustum)
	{
		return false;
	}

	return true;
}


void GraphicsClass::Shutdown()
{


Shutdown 함수의 여기서 새로운 FrustumClass와 ModelListClass 객체를 해제합니다.


	// Release the frustum object.
	if(m_Frustum)
	{
		delete m_Frustum;
		m_Frustum = 0;
	}

	// Release the model list object.
	if(m_ModelList)
	{
		m_ModelList->Shutdown();
		delete m_ModelList;
		m_ModelList = 0;
	}

	// Release the light object.
	if(m_Light)
	{
		delete m_Light;
		m_Light = 0;
	}

	// Release the light shader object.
	if(m_LightShader)
	{
		m_LightShader->Shutdown();
		delete m_LightShader;
		m_LightShader = 0;
	}

	// Release the model object.
	if(m_Model)
	{
		m_Model->Shutdown();
		delete m_Model;
		m_Model = 0;
	}

	// Release the text object.
	if(m_Text)
	{
		m_Text->Shutdown();
		delete m_Text;
		m_Text = 0;
	}

	// Release the camera object.
	if(m_Camera)
	{
		delete m_Camera;
		m_Camera = 0;
	}

	// Release the Direct3D object.
	if(m_D3D)
	{
		m_D3D->Shutdown();
		delete m_D3D;
		m_D3D = 0;
	}

	return;
}


Frame 함수는 호출하는 SystemClass로 부터 카메라 회전값을 받습니다. 그리고는 카메라의 위치와 회전이 설정되며 Render 함수에서 뷰 행렬을 적절히 갱신할 수 있습니다.


bool GraphicsClass::Frame(float rotationY)
{
	// Set the position of the camera.
	m_Camera->SetPosition(0.0f, 0.0f, -10.0f);

	// Set the rotation of the camera.
	m_Camera->SetRotation(0.0f, rotationY, 0.0f);

	return true;
}


bool GraphicsClass::Render()
{
	D3DXMATRIX worldMatrix, viewMatrix, projectionMatrix, orthoMatrix;
	int modelCount, renderCount, index;
	float positionX, positionY, positionZ, radius;
	D3DXVECTOR4 color;
	bool renderModel, result;


	// Clear the buffers to begin the scene.
	m_D3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);

	// Generate the view matrix based on the camera's position.
	m_Camera->Render();

	// Get the world, view, projection, and ortho matrices from the camera and d3d objects.
	m_D3D->GetWorldMatrix(worldMatrix);
	m_Camera->GetViewMatrix(viewMatrix);
	m_D3D->GetProjectionMatrix(projectionMatrix);
	m_D3D->GetOrthoMatrix(orthoMatrix);


Render 함수의 주요한 변화는 매 프레임마다 갱신된 뷰 행렬에 따라 뷰잉 프러스텀을 만드는 것입니다. 이 작업은 뷰 행렬이 바뀌거나 프러스텀 컬링이 바르지 못할때마다 발생해야 합니다.


	// Construct the frustum.
	m_Frustum->ConstructFrustum(SCREEN_DEPTH, projectionMatrix, viewMatrix);

	// Get the number of models that will be rendered.
	modelCount = m_ModelList->GetModelCount();

	// Initialize the count of models that have been rendered.
	renderCount = 0;


ModelListClass 객체의 모든 모델에 대한 루프를 돕니다.


	// Go through all the models and render them only if they can be seen by the camera view.
	for(index=0; index<modelCount; index++)
	{
		// Get the position and color of the sphere model at this index.
		m_ModelList->GetData(index, positionX, positionY, positionZ, color);

		// Set the radius of the sphere to 1.0 since this is already known.
		radius = 1.0f;


이곳은 새로운 FrustumClass 객체를 사용하는 곳입니다. 뷰잉 프러스텀에서 구를 볼 수 있는지 확인합니다. 볼 수 있다면 렌더하고 안보인다면 넘어가고 다음 거를 확인합니다. 프러스텀 컬링을 사용함으로 빠른속도를 얻을 곳입니다.


		// Check if the sphere model is in the view frustum.
		renderModel = m_Frustum->CheckSphere(positionX, positionY, positionZ, radius);

		// If it can be seen then render it, if not skip this model and check the next sphere.
		if(renderModel)
		{
			// Move the model to the location it should be rendered at.
			D3DXMatrixTranslation(&worldMatrix, positionX, positionY, positionZ); 

			// Put the model vertex and index buffers on the graphics pipeline to prepare them for drawing.
			m_Model->Render(m_D3D->GetDeviceContext());

			// Render the model using the light shader.
			m_LightShader->Render(m_D3D->GetDeviceContext(), m_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, 
					      m_Model->GetTexture(), m_Light->GetDirection(), color);

			// Reset to the original world matrix.
			m_D3D->GetWorldMatrix(worldMatrix);

			// Since this model was rendered then increase the count for this frame.
			renderCount++;
		}
	}


실제로 렌더되는 구가 몇개인지 나타내도록 살짝 바뀐 TextClass를 사용합니다. 또 렌더되지 않은 대신에 FrustumClass 객체를 이용하여 제거된 구들의 숫자를 추정할 수 있습니다.


	// Set the number of models that was actually rendered this frame.
	result = m_Text->SetRenderCount(renderCount, m_D3D->GetDeviceContext());
	if(!result)
	{
		return false;
	}

	// Turn off the Z buffer to begin all 2D rendering.
	m_D3D->TurnZBufferOff();

	// Turn on the alpha blending before rendering the text.
	m_D3D->TurnOnAlphaBlending();

	// Render the text string of the render count.
	m_Text->Render(m_D3D->GetDeviceContext(), worldMatrix, orthoMatrix);
	if(!result)
	{
		return false;
	}

	// Turn off alpha blending after rendering the text.
	m_D3D->TurnOffAlphaBlending();

	// Turn the Z buffer back on now that all 2D rendering has completed.
	m_D3D->TurnZBufferOn();

	// Present the rendered scene to the screen.
	m_D3D->EndScene();

	return true;
}


Positionclass.h


이번 강좌에서 왼쪽 오른쪽 방향키를 이용하여 카메라 움직임을 하기 위해 뷰어의 위치를 계산하고 유지하는 새로운 클래스를 만듭니다. 이 클래스는 지금은 왼쪽 오른쪽으로 도는것만 다룰 것이지만 다른 모든 움직임을 하도록 확장될 수 있습니다. 그 움직임은 또한 부드러운 카메라 효과를 만들기 위해 가속, 감속을 포함합니다.


////////////////////////////////////////////////////////////////////////////////
// Filename: positionclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _POSITIONCLASS_H_
#define _POSITIONCLASS_H_


//////////////
// INCLUDES //
//////////////
#include <math.h>


////////////////////////////////////////////////////////////////////////////////
// Class name: PositionClass
////////////////////////////////////////////////////////////////////////////////
class PositionClass
{
public:
	PositionClass();
	PositionClass(const PositionClass&);
	~PositionClass();

	void SetFrameTime(float);
	void GetRotation(float&);

	void TurnLeft(bool);
	void TurnRight(bool);

private:
	float m_frameTime;
	float m_rotationY;
	float m_leftTurnSpeed, m_rightTurnSpeed;
};

#endif


Positionclass.cpp


////////////////////////////////////////////////////////////////////////////////
// Filename: positionclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "positionclass.h"


생성자는 private 멤버 변수들을 0으로 초기화합니다.


PositionClass::PositionClass()
{
	m_frameTime = 0.0f;
	m_rotationY = 0.0f;
	m_leftTurnSpeed  = 0.0f;
	m_rightTurnSpeed = 0.0f;
}


PositionClass::PositionClass(const PositionClass& other)
{
}


PositionClass::~PositionClass()
{
}


SetFrameTime 함수는 이 클래스에서 프레임 속도를 설정하는데 사용됩니다. PositionClass은 프레임 시간 스피드를 카메라가 얼마나 빠르게 움직이고 회전하는지를 계산하기 위해 사용할 것입니다. 이 함수는 항상 이 클래스를 이용하여 카메라 위치를 움직이기 전에 각 프레임의 시작부분에서 호출되어야 합니다.


void PositionClass::SetFrameTime(float time)
{
	m_frameTime = time;
	return;
}


GetRotation는 카메라의 Y축 회전을 반환합니다. 이 함수는 카메라의 위치에 관한 더 많은 정보를 얻도록 확장될 수 있습니다.


void PositionClass::GetRotation(float& y)
{
	y = m_rotationY;
	return;
}


이동 함수는 둘다 동일하게 동작합니다. 각 keydown 파라미터 변수는 사용자가 왼쪽 혹은 오른쪽 키를 누르고 있는지를 나타냅니다. 사용자들이 키를 누르고 있다면 각 프레임마다 스피드가 최대치가 될때까지 가속합니다. 엄청 민감하고 부드러운 효과를 제공하는 탈 것(차량 같은)에서 가속하는 것처럼 카메라가 빨라집니다. 비슷하게 사용자가 키를 떼며 keydown변수가 false가 되면 각 프레임마다 스피드가 0이 될때까지 부드럽게 느려질 것입니다. 프레임 비율에 상관없이 스피드를 일정하게 하기 위해 스피드를 스페임 시간에 대해 계산합니다. 각 함수는 카메라의 새 위치를 계산하기 위해 약간의 기본적인 수학을 사용합니다.


void PositionClass::TurnLeft(bool keydown)
{
	// If the key is pressed increase the speed at which the camera turns left.  If not slow down the turn speed.
	if(keydown)
	{
		m_leftTurnSpeed += m_frameTime * 0.01f;

		if(m_leftTurnSpeed > (m_frameTime * 0.15f))
		{
			m_leftTurnSpeed = m_frameTime * 0.15f;
		}
	}
	else
	{
		m_leftTurnSpeed -= m_frameTime* 0.005f;

		if(m_leftTurnSpeed < 0.0f)
		{
			m_leftTurnSpeed = 0.0f;
		}
	}

	// Update the rotation using the turning speed.
	m_rotationY -= m_leftTurnSpeed;
	if(m_rotationY < 0.0f)
	{
		m_rotationY += 360.0f;
	}

	return;
}


void PositionClass::TurnRight(bool keydown)
{
	// If the key is pressed increase the speed at which the camera turns right.  If not slow down the turn speed.
	if(keydown)
	{
		m_rightTurnSpeed += m_frameTime * 0.01f;

		if(m_rightTurnSpeed > (m_frameTime * 0.15f))
		{
			m_rightTurnSpeed = m_frameTime * 0.15f;
		}
	}
	else
	{
		m_rightTurnSpeed -= m_frameTime* 0.005f;

		if(m_rightTurnSpeed < 0.0f)
		{
			m_rightTurnSpeed = 0.0f;
		}
	}

	// Update the rotation using the turning speed.
	m_rotationY += m_rightTurnSpeed;
	if(m_rotationY > 360.0f)
	{
		m_rotationY -= 360.0f;
	}

	return;
}


Systemclass.h


SystemClass는 새로운 PositionClass를 사용하기 위해 수정되었습니다.


////////////////////////////////////////////////////////////////////////////////
// Filename: systemclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _SYSTEMCLASS_H_
#define _SYSTEMCLASS_H_


///////////////////////////////
// PRE-PROCESSING DIRECTIVES //
///////////////////////////////
#define WIN32_LEAN_AND_MEAN


//////////////
// INCLUDES //
//////////////
#include <windows.h>


///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "inputclass.h"
#include "graphicsclass.h"
#include "timerclass.h"
#include "positionclass.h"


////////////////////////////////////////////////////////////////////////////////
// Class name: SystemClass
////////////////////////////////////////////////////////////////////////////////
class SystemClass
{
public:
	SystemClass();
	SystemClass(const SystemClass&);
	~SystemClass();

	bool Initialize();
	void Shutdown();
	void Run();

	LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);

private:
	bool Frame();
	void InitializeWindows(int&, int&);
	void ShutdownWindows();

private:
	LPCWSTR m_applicationName;
	HINSTANCE m_hinstance;
	HWND m_hwnd;

	InputClass* m_Input;
	GraphicsClass* m_Graphics;
	TimerClass* m_Timer;
	PositionClass* m_Position;
};


/////////////////////////
// FUNCTION PROTOTYPES //
/////////////////////////
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);


/////////////
// GLOBALS //
/////////////
static SystemClass* ApplicationHandle = 0;


#endif


Systemclass.cpp


이전 강좌들에서 달라진 함수들만 다룰 것입니다.


////////////////////////////////////////////////////////////////////////////////
// Filename: systemclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "systemclass.h"


SystemClass::SystemClass()
{
	m_Input = 0;
	m_Graphics = 0;
	m_Timer = 0;


생성자에서 새로운 PositionClass객체가 null로 초기화됩니다.


	m_Position = 0;
}


bool SystemClass::Initialize()
{
	int screenWidth, screenHeight;
	bool result;


	// Initialize the width and height of the screen to zero before sending the variables into the function.
	screenWidth = 0;
	screenHeight = 0;

	// Initialize the windows api.
	InitializeWindows(screenWidth, screenHeight);

	// Create the input object.  This object will be used to handle reading the keyboard input from the user.
	m_Input = new InputClass;
	if(!m_Input)
	{
		return false;
	}

	// Initialize the input object.
	result = m_Input->Initialize(m_hinstance, m_hwnd, screenWidth, screenHeight);
	if(!result)
	{
		MessageBox(m_hwnd, L"Could not initialize the input object.", L"Error", MB_OK);
		return false;
	}

	// Create the graphics object.  This object will handle rendering all the graphics for this application.
	m_Graphics = new GraphicsClass;
	if(!m_Graphics)
	{
		return false;
	}

	// Initialize the graphics object.
	result = m_Graphics->Initialize(screenWidth, screenHeight, m_hwnd);
	if(!result)
	{
		return false;
	}
	
	// Create the timer object.
	m_Timer = new TimerClass;
	if(!m_Timer)
	{
		return false;
	}

	// Initialize the timer object.
	result = m_Timer->Initialize();
	if(!result)
	{
		MessageBox(m_hwnd, L"Could not initialize the Timer object.", L"Error", MB_OK);
		return false;
	}


새로운 PositionClass 객체를 여기서 생성합니다. 초기화할 필요는 없습니다.


	// Create the position object.
	m_Position = new PositionClass;
	if(!m_Position)
	{
		return false;
	}

	return true;
}


void SystemClass::Shutdown()
{


Shutdown 함수의 이곳에서 PositionClass 객체가 해제됩니다.


	// Release the position object.
	if(m_Position)
	{
		delete m_Position;
		m_Position = 0;
	}

	// Release the timer object.
	if(m_Timer)
	{
		delete m_Timer;
		m_Timer = 0;
	}

	// Release the graphics object.
	if(m_Graphics)
	{
		m_Graphics->Shutdown();
		delete m_Graphics;
		m_Graphics = 0;
	}

	// Release the input object.
	if(m_Input)
	{
		m_Input->Shutdown();
		delete m_Input;
		m_Input = 0;
	}

	// Shutdown the window.
	ShutdownWindows();
	
	return;
}


bool SystemClass::Frame()
{
	bool keyDown, result;
	float rotationY;


	// Update the system stats.
	m_Timer->Frame();

	// Do the input frame processing.
	result = m_Input->Frame();
	if(!result)
	{
		return false;
	}


각 프레임동안 PositionClass 객체가 프레임 시간을 통하여 갱신됩니다.


	// Set the frame time for calculating the updated position.
	m_Position->SetFrameTime(m_Timer->GetTime());


그 후 현재 키보드 상태에 따라 이동 함수가 갱신됩니다. 이동 함수는 카메라의 위치를 이번 프레임에 대한 새로운 위치로 갱신할 것입니다.


	// Check if the left or right arrow key has been pressed, if so rotate the camera accordingly.
	keyDown = m_Input->IsLeftArrowPressed();
	m_Position->TurnLeft(keyDown);

	keyDown = m_Input->IsRightArrowPressed();
	m_Position->TurnRight(keyDown);


새로운 카메라의 회전은 검색되어지고 Graphics::Frame 함수로 카메라 위치를 갱신시키기 위해 보내집니다.


	// Get the current view point rotation.
	m_Position->GetRotation(rotationY);

	// Do the frame processing for the graphics object.
	result = m_Graphics->Frame(rotationY);
	if(!result)
	{
		return false;
	}

	// Finally render the graphics to the screen.
	result = m_Graphics->Render();
	if(!result)
	{
		return false;
	}

	return true;
}


요약


이제 여러분은 오브젝트 고르기를 어떻게 하는지 보셨습니다. 서로 다른 오브젝트들을 컬링하기 위한 유일한 트릭은 물체를 감싸는 큐브, 직육면체, 구를 결정하거나 점을 잘 사용하는 것입니다.




연습하기


1. 코드 컴파일 후 프로그램을 실행해 보세요. 왼쪽 오른쪽 방향키를 사용하여 카메라 움직임과 왼쪽 상단에 렌더 카운트가 바뀌는지 확인해 보세요.


2. 큐브 모델로 로드하고 CheckCube 함수로 바꿔보세요.


3. 다른 모델들을 생성하고 그 모델을에 대해 어떤 컬링 확인이 가장 좋은지 테스트해 보세요.

728x90

+ Recent posts