선 개념 : 원 순열의 반대말은 직순열이다

위 A, B, C 는 보기에는 달라 보이지만 돌려 보면 모두다 같다

즉 원순열 기준으로는 모두다 같다고 본다 (돌렸을때 같으면 같다고 보는것이 원순열, 특정 기준 없이)

주의 : 원순열에선 보기엔 A 가 위에 있을지라도 맨 위에 있다 옆에 있다 그런 개념이 없다, 특정 기준 없이는

직순열과 원순열의 차이는 자리마자 고유번호가 있다인데 이것은 특정 원소를 기준으로 자리를 매길 수 있다는 말입니다

아래 것은 왼쪽이 첫번째 것이라고 특정 기준을 잡은것임으로 직순열이다

하지만 원순열은 고유번호가 없다, 돌려도 같기 때문

그래서 원순열을 풀때는 기준을 잡고 직순열로 바꿔서 푼다

즉 고유번호 엇는 것을 고유번호 있게 만드는 것이 첫번째 과정이다

=> 원순열에 누군가 한명이 앉으면 그때부턴 기준이 생기게 됨으로 원순열이 아닌 직순열이 된다

첫번재 앉은 사람 왼쪽 또는 오른쪽에 누구를 앉힐 지 정할 수 있는 기준이 되는사람이 앉았음으로

문제 1)

이런 볼품 없는 원탁의자가 있다(그림은 저모양 일지라도 의지는 모두다 같고 구분 할수 없다 가정한다)

이때 첫번째 사람이 앉는 경우의 수는?

답 = 1가지 , 3가지가 아닌데 왜냐면 원순열에서는 돌려도 같기 때문에 처음엔 어떤 기준이 없어서 첫번째 앉는 사람이 어디에 앉든 모두다 같은 경우가 됨으로, 즉 어디에 앉든 다 똑같다( 기준이 애초에 없었음으로 1명이 앉기 전까진)

문제 2)

문제 1 에서 모두다 앉는 경우의 수는?

답 1 * 2! 인데

1명이 앉고 나머지 2명이 앉는 경우의 수임으로 직순열(Permutation) 로 풀면 된다

문제 3)

6명이 원탁에 앉는 경우의 수는?

답 = 1 * 5!

n 명이 원탁에 둘러 앉는 경우의 수는?

$1\ \cdot \ \left(n-1\right)!$1 · (n1)!

문제)

A, B 를 포함한 6명이 있는데

A, B 가 이웃하여 앉는 경우의 수를 구하시오

이땐 순열 top 5중

A, B 를 주머니에 넣고 하나라 생각한 후 풀면 됩니다

그래서 우선 총 개수는 5개라 생각하면

1 * 4!

그리고 주머니에 있는 것 2! 을 곱하면

답 = 1 * 4! * 2!

문제 )

A, B 가 마주보며 앉는 경우의 수는?

원으로 생각하면 어려우니깐 일단 기준을 잡아야 한다

즉 A 를 먼저 앉힌다음 생각해보면

A 를 앉히는 경우의 수 1 가지 , 앉히면 직순열이 됨

그런데 그리고 B 가 앉는 경우의 수 1 가지 왜냐면 A 의 반대편아 앉아야 함으로

여기까진 1 * 1 이 된다 그런다음

그림 처럼 4자리에 나머지 4명이 앉으면 됨으로

4!

A 가 처음 앉을때 원을 돌아가면서 앉을때도 고려해야 하는것 아닌가? 라고 생각 할수 있지만

원순열에서 A 가 앉음과 동시에 직순열이 되었음으로 이건 이미 고려 대상에선 끝

답 = 1 * 1 * 4!

반응형

'수학 (Mathematics) > 확률과통계' 카테고리의 다른 글

조합 Top5 (1)  (0) 2023.01.06
조합 (Combination)  (0) 2023.01.06
순열 Top5 간단 정리  (0) 2023.01.06
조합(combination)  (0) 2012.11.02
순열 permutation  (0) 2012.11.02

 

조합 Top 5

1. 포함되도록

2. 포함되지 않도록

3. 적어도 1명이 포함되도록

4. 악수하는 방법의 수

5. 조 나누기

출처 입력

 

 

 

 

[포함되도록]

 

문제) 갑,을 을 포함한 학생 총 10명이 있다

이때 학생 대표단 3명을 뽑는데 갑과 을이 모두 포함되도록 뽑는 경우의 수는?

 

 

답 = 1 * 8C1

 

1은 갑과 을은 이미 뽑아 놓았음으로

 

Permutation 과 헷갈리면 안되는건 사람을 뽑는 것은 줄을 세우는 것이아니기 때문에

갑과을에 대한 줄을 세우는 경우의 수는 고려할 필요가 없습니다

그래서 나머지 8 명 중에서 한명만 뽑으면 됨으로 8C1

 

 

 

[포함되지 않도록]

 

문제) 문제 갑과 을이포함 되지 않도록 3명을 뽑는 경우의 수는?

 

 

답 = 8C3

갑과 을을 배제하고 3명을 뽑으면 됨으로

 

 

 

 

[적어도 1명이 포함되도록]

 

갑과 을 중 적어도 1명이 10명 중 대표 3명에 포함되도록 하는 경우의 수는?

 

 

갑과 을 중 한명을 뽑아서

나머지 8명중 2명을 뽑는 경우의 수

 

(case 1) 2C1 * 8C2 = 56

 

 

갑과을 두명을 뽑아서 나머지 8명중 1명을 뽑는 경우의 수

(case 2) 2C2 * 8C1

 

2C2 * 8C1 = 1 * 8C1 = 8

 

 

 

답 = 56 + 8 = 64

 

적어도 한명이라고 하면 1명인 케이스와 요건을 충족하는 인원수 까지

카운팅 하면서 각각 맞는 경우들을 계산하여 더한다는 개념

=> 즉 분류해서 더한다(위 문장을 외우는 것이 아닌 분류하고 합치는 개념이 중요)

 

 

적어도 1명이 포함되도록 의 케이스는 여사건으로 풀어도 가능하다

 

10C3 - 8C3 전체 중에 3명 뽑는것에서 8명중에서 3명 뽑는 경우의 수

 

120 - 56 = 64

 

 

 

 

 

[악수하는 방법의 수]

 

5명이 서로 악수하는 경우의 수는?

 

악수할때는 2명이 필요하니

5명중에서 2명씩만 뽑으면 된다 그래서

 

답 = 5C2

 

 

 

 

[조 나누기]

이건 다음에..

 

 

조합 계산기 : https://ko.numberempire.com/combinatorialcalculator.php

이미지 썸네일 삭제
조합 계산기

조합 계산기

ko.numberempire.com

 

 

반응형

'수학 (Mathematics) > 확률과통계' 카테고리의 다른 글

원 순열  (0) 2023.01.06
조합 (Combination)  (0) 2023.01.06
순열 Top5 간단 정리  (0) 2023.01.06
조합(combination)  (0) 2012.11.02
순열 permutation  (0) 2012.11.02

 

순열 : N 명중에서 R 명을 뽑는 수, 하지만 줄을 세운다

 

조합 : N 명중에서 R 명을 뽑는 수, 하지만 줄을 세우진 않는다 = 순서 상관 없다 = 즉 뽑는 Action 만 따진다

= 선택하는 경우의 수로 말하기도 함 ex) 10명중에서 5명을 선택하는 경우의 수

 

 

이렇게 되는데

 

n명중에 r명을 뽑아 줄을 세운다음 줄 세운것을 취소하면 n명 중에서 r 명을 뽑기만 하는것이 된다

 

 

 

다른 말로

 

순열 nPr 이란 얘기는 n명중에서 r명을 뽑고(여기까지가 nCr ) 다음 그 이후 줄까지 세운 것을 말한다

 

 

 

ex) 10 명중에서 3명을 줄을 세우는 방법의 수는?

 

 

10C3 = 10P3 / 3! = 120

 

 

콤비네이션은 Permutation 으로 풀어서 푸는것이 좋다

 

 

 

 

ex) 서로다른 5권의 책이 있는데 그 중 2권을 책을 가지고 가고 싶을때?

 

5C2 = 5P2 / 2! = 10

 

 

 

외우편 편합 조합들

 

 

문제 )

100명이 있는데 도시락이 만원이다

 

100명의 도시락을 사려 했더니 98만원 밖에 없다

 

이때 98명을 뽑는 경우의 수는?

 

 

100C98 = 100P98 / 98!

 

그런데 계산하기 너무 많다 이럴때

 

 

단) n은 r 보다 크거나 같다는 조건이 있습니다

 

 

nCr = nC(n-r) 과 같다는 조합의 성질이 있다 (계산해보면 같다는 것을 알수 있습니다)

 

즉 100C98 = 100C2

 

100*99/2 = 4950

 

 

 

[특징]

 

0! = 1

nP0 = 1 (약속임 이건 그냥 정의)

nC0 = 1 , n 명중에 한명도 안뽑은 것도 개수를 쳐서 1이라 함

 

nP1 =n

nC1 = n

 

 

그래서 아래와 같은 특성이 생기게 됩니다

이 성질을 잘 생각하면서 보면 4C2 를 기준으로 대칭이 된다는 것을 알 수 있습니다

 

 

 

 

 

 

 

반응형

'수학 (Mathematics) > 확률과통계' 카테고리의 다른 글

원 순열  (0) 2023.01.06
조합 Top5 (1)  (0) 2023.01.06
순열 Top5 간단 정리  (0) 2023.01.06
조합(combination)  (0) 2012.11.02
순열 permutation  (0) 2012.11.02

 

이웃하도록 = 주머니

이웃하지 않도록 = 칸막이

남녀 교대로 = 남여 중 어떤 한쪽에서 한명이 적거나 또는 둘이 같거나, 2개 이상 적은 케이스는 수학에서 없다

~사이에 ~가 오도록 = Box치고 Box 계산 이후 Box도 줄을 서야 함으로 주머니 처럼 계산

적어도 한쪽 끝에 ~가 오도록 = 여사건

 

반응형

'수학 (Mathematics) > 확률과통계' 카테고리의 다른 글

원 순열  (0) 2023.01.06
조합 Top5 (1)  (0) 2023.01.06
조합 (Combination)  (0) 2023.01.06
조합(combination)  (0) 2012.11.02
순열 permutation  (0) 2012.11.02

 

반응형

f 의 의미









함수 개수 맞추기 문제 : http://tv.naver.com/v/904250






이미지 URL :  https://blog.naver.com/jklee517/150148625123

반응형

Feedback : smile.k06@gmail.com

 

오랜만에 쓰는 포스팅 입니다. 흐흐.

그간 멘탈이 나가기도 한적도 있었고, 바쁘기도 했었다는 핑계로 살짝 밑밥을 깔아 두고생각나는 수학 주제가 있을 때마다 쓸 주제들을 나열하고는 있었는데, 정리가 안되서 사실 올리지 못했습니다. (약간의 완벽주의가…)

어쨌거나 오늘의 주제는 연립방정식의 가감법과 등호의 관계 입니다.

시작!

 

 

 

이번 포스팅의 내용은, 과거 필자가 연립방정식을 처음 공부할 때 느꼈던 궁금증에서 시작하였다.

우리가 중2과정에서 처음 배우는 연립방정식은, 아주 익숙한 주제중에 하나기도 하다.

사실 고등학교 수1에서 배우는 함수와 직선의 방정식 으로 설명하면 좀더 완벽하게 설명 할 수 있겠지만, 일단은 중학교 과정안에서 어떻게든 해보려고 한다.

우선 예제를 보자.

 

 

 

[1] 연립방정식의 기본 문제

 

[1] 을 보면 습관적으로 가장 먼저 하고 싶은 일이 무엇일까.

맞다. 위의 식에서 밑의 식을 빼고 싶겠지.. 크크.

그걸 우리는 흔히 말해 가감법 이라고 알고 있다.

 

사실 연립방정식을 풀 때 가장 중요한 것은 미지수를 줄이는 것이다.

여러 문자가 있으면 하나의 식으로 해결이 안되므로(사실 해결이 안되는 것은 아니지만, 유한한 개수의 답으로 정해지지 않는다 가 정확한 표현이다.) 여러 식을 이용해 미지수의 개수를 줄이는 것이다.

그 방법중에 하나는 대입법이고, 또 하나는 가감법이라고 알고 있을 것이다.

 

[예제1]을 한번 풀어보도록 하자.

  

[풀이1] 연립방정식의 기본 문제

 

2x가 같으니까 두식을 빼주면 y = 2 만 남게되고,

두 식중에 어떠한 한 식에다 y = 2를 대입하면 쉽게 나머지 x 를 구할 수가 있게 된다.

 

여기까지개 대략적인 가감법에 대한 이야기 인데

 

자 여기서 질문.

어째서 위의 식에서 밑에 식을 뺄 수 있을까. 혹은 더할 수 있을까.

누구 마음대로 식을 더하거나 뺀 것일까.

 

중학교 과정의 연립방정식 전에는 식을 뺀다는 개념이 없어서, 처음 가감법을 배우게 되면 통상 아 그냥 이렇게 풀면 되는구나하고 넘어가기 마련이다.

 

필자의 생각으로는 수학을 공부할 때는 항상 궁금증을 가지는 것이 유리한데,

왜냐면 그 궁금증이 증명을 이끌어 낼 수 있기 때문이다.

증명은 지금까지 가지고 있는 공리를 이용해서 새로운 공리를 만들어 내는 과정이므로, 자연스레 수학의 폭이 넓어 지게 해준다.

 

어쨌거나 질문으로 돌아가보면

어째서 식을 뺄 수 있는가.

그것은 등호의 성질에서 찾아보면 쉽게 알 수 있다.

 

이전 포스팅에서 등호의 성질에 관한 포스팅을 했었는데..

이하와 같다.

 

 

1.     양 변에 같은 수를 더하여도 등식은 성립한다.

a = b 이면, a + c = b + c

2.     양 변에 같은 수를 빼주어도 등식은 성립한다.

a = b 이면, a - c = b - c

3.     양 변에 같은 수를 곱하여도 등식은 성립한다.

a = b 이면, a x c = b x c

4.     양 변에 0이 아닌 같은 수로 나누어도 등식은 성립한다.

a = b 이면, a ÷ c = a ÷ c ( c ≠ 0)

[2] 등호의 성질

 

등호의 성질의 1번과 2번을 보자.

양변에 같은 수를 더하여도 등식은 성립하고 마찬가지로 양변에 같은 수를 빼더라도 등식은 성립한다.

여기서 다시 풀이 1의 중간과정을 보도록 하자

 

 

[풀이1-1]

 

①의 좌변(2x + 3)에는 의 좌변(2x – 2y)을 빼주었고,

의 우변(5)에는 의 우변(5)을 빼주었다.

 

그런데 잘 생각해보자.

2x + 2y = 3 이다.

다시말해, 2x + 2y 를 다르게 표현하면 3 으로 표현할 수 있다라는 이야기다.

2x + 2y가 아닌 3을 양변에 빼준 것과 같다라는 이야기다.

 

, 의 좌변에는 의 좌변을 빼주었고,

의 우변에는 의 우변을 빼주었던 이 행위는.

의 양 변에 3을 빼준 것과 같다.

 

정리하면,

연립방정식의 가감법은 등호의 성질 중 양변에 같은수를 더하거나 빼주어도 등호는 성립한다라는 성질을 이용한 것에 불과하다.

라는 것이다.

 

대부분의 풀이 방법들은 어떠한 과정을 통해 생겨났다는 점을 생각해보면,

즐겁게 할 수 있을것이다.

 

그럼 안녕~

 

Feedback : smile.k06@gmail.com

 

반응형

 

Feedback : smile.k06@gmail.com

 

닫혀있다의 개념

 

고등학교 수학을 올라가면 자주듣는 수학용어중에는 닫혀있다라는 말이 있다. 우리가 일반적으로 쓰는 닫혀있다와 어떤 차이가 있는 것 일까.

우선 사전상의 의미를 보자. 닫혀있다의 표제어인 닫히다를 봐야 할 것이다.

 

-히다[발음 : 다치다] (동사)

활용 : 닫히어[닫히어/닫히여](닫혀), 닫히니

1 . ‘닫다2(1. 열린 문짝, 뚜껑, 서랍 따위를 도로 제자리로 가게 하여 막다)’의 피동사.

ž   성문이 닫혀 있다.

ž   열어 놓은 문이 바람에 닫혔다.

ž   병뚜껑이 너무 꼭 닫혀서 열 수가 없다.

2 . ‘닫다2(3. 하루의 영업을 마치다)’의 피동사.

ž   지금 시간이면 은행 문이 닫혔을 겁니다.

3 . ‘닫다2(4. 굳게 다물다)’의 피동사.

ž   무언가 생각을 하는지 그의 입이 굳게 닫혔다.

ž   뒷실댁이 바락바락 내질러도 뒷실 어른의 한번 닫힌 입은 조개처럼 다시는 열릴 줄을 모른다. 출처 : 김춘복, 쌈짓골

ž   한바탕 와글거린 후 처음보다 더 무겁게 말문이 닫힌다. 다시는 아무도 입을 열지 않는다. 출처 : 최인훈, 광장

 

출처 : 네이버 국어사전

 

1, 2, 3번의 뜻이 있는데 엄밀히 말해, 수학의 닫히다와는 조금 거리가 있다. 사전상의 의미들은 close의 의미를 지니고 있다. 하지만 수학에서는 closure(폐쇠) 의 의미에 가깝다고 하겠다.

 

닫혀있다의 예를 보도록 하자.

              i.         자연수는 덧셈과 곱셈에 관하여 닫혀있다.

             ii.         자연수는 뺄셈과 나눗셈에 관하여 닫혀있지 않다.

            iii.         정수는 덧셈, 뺄셈, 곱셈에 관하여 닫혀있다.

            iv.         정수는 나눗셈에 관하여 닫혀있지 않다.

눈치가 빠른 사람이면 이쯤되면 어림짐작 할 수도 있다. 집합으로 설명하기 전에 우선예를 기준으로 상식적인 이야기를 해보자

i.              자연수는 덧셈과 곱셈에 관하여 닫혀있다.

자연수와 자연수를 더하면 어떻게 될까. 자연수인 아무 수나 대입해서 한번 풀어보자.

2 + 1 = 3

3 + 4 = 7

이렇게 당연히 자연수가 나온다.

 

곱셈도 보자.

2 x 1 = 2

3 x 4 = 12

마찬가지로 당연히 자연수가 나온다.

이것이 닫혀있다 인데. 일단 두번째 예도 한번 해석을 해보자.

ii.             자연수는 뺄셈과 나눗셈에 관하여 닫혀있지 않다

첫번째처럼 대입해서 한번 보도록 하자. 우선 뺄셈.

2 – 1 = 1

3 – 4 = -1

첫번째 대입에는 자연수 였지만, 두번째 대입에는 음수가 나왔다. 뺄셈의 결과에는 반드시 자연수가 나오지는 않는다는 결론.

 

나눗셈도 보자.

2 ÷ 1 = 2

3 ÷ 4 = 0.75

첫번째 대입에는 2가 자연수 였지만, 두번째는 0.75이므로 자연수가 아니다.

 

다른 예들을 보기 전에, 일반적일 결론을 내려보자.

A라는 집합이 있다고 해보자. 집합이 있으면 그에 따른 원소도 있다. 원소들 끼리 B라는 행동을 한다. 그 결과가 A의 집합의 원소로 된다면, 그 때 닫혀있다라고 할 수 있다.

이 말을 그림으로 설명한 것이 [그림1] 이다.

 

                                                                 [그림 1]

 

 

간단히 말해, 어떤 집합끼리 무언가를 해서 해당 집합이 나오면 닫혀있다라고 보면된다.

이 닫혀있다라는 개념은 증명할 때 반드시 나오는 언어이므로, 충분히 인지하는 것이 중요할 것이다.

 

나머지 두 예는 여러분들이 한번 생각해 보도록 하자 :)

 

그럼 안녕~

 

반응형




음... 원래 글을 쓸때, 개인적인 백업도 있고 해서 Microsoft Word 로 편집하고 복붙하는 방법을 굉장히 선호 했습니다만....

어째서인지 수식복사를 막아놨군요.. 전에는 가능했었는데. 이것참.. 굉장히 불편하네요.

뭔가 티스토리에 문의를 해봐야겠다는 생각을 하면서,,,

자.. 스따뜨!



우리는 흔히 등호를 사이에 두고 이항을 하는 것을 당연시 하곤 한다.

덧셈의 이항의 예를 보자.


[예1] 덧셈 이항 예제


다른부분은 그렇다 치고.

첫번째줄과 두번째줄을 보자.

우리는 -2a 를 좌변으로 이항하고 2를 우변으로 이항하였다. 이항시에는 연산부호를 바꾸어 준다.

조금만 단항식, 다항식의 사칙연산 문제를 풀어본 경험이 있다면 자연스럽게 느껴지는 부분이다.

덧셈(뺄셈)을 이항시 - 는 + 로 + 는 - 로 바꾸어 준다.

가 이항의 원칙이 되겠다.


자 그렇다면 어째서 이항시 부호를 바꾸어 줘도 되는 것일까.

사실 이 질문을 하면 난감한 표정을 짓는 학생들이 상당히 많다.

그도 그럴것이, 너무 당연한 것을 질문하면 너무 당연하니까... 대답을 못하는 것이 어찌보면 당연 할 정도.


이항을 한다는 개념은 사실 등호의 성질에서 나왔다.

애시당초 등호라는 것은


두 개의 대상이 서로 같다는 것을 나타낼 때 사용하는 기호 ‘  ’를 등호라고 한다. 등호는 '같음을 나타내는 기호’라는 의미이며,   의 왼쪽에 있는 것과 오른쪽에 있는 것이 서로 같다는 것을 나타내는 기호이다.

[네이버 지식백과] 등호 [equal sign, equality sign] (수학백과, 2015.5, 대한수학회)


이렇게 정의 할 수 있다.




[예2] 등호의 예제

너무 당연한 이야기지만, [예2]와 같이 좌변과 우변이 완벽하게 일치하는 상황이다.

등호를 기준으로 좌변과 우변은 완벽하게 동일해야 하므로, 사칙연산상으로 이하가 성립한다.


  1. 양 변에 같은 수를 더하여도 등식은 성립한다. 
    a = b 이면, a + c = b + c

  2. 양 변에 같은 수를 빼주어도 등식은 성립한다.
    a = b 이면, a - c = b - c

  3. 양 변에 같은 수를 곱하여도 등식은 성립한다.
    a = b 이면, a x c = b x c

  4. 양 변에 0이 아닌 같은 수로 나누어도 등식은 성립한다.
    a = b 이면, a ÷ c = a ÷ c ( c ≠ 0)


1, 2번을 이항과 접하여 생각해보면 [예1]을 이렇게 바꾸어 볼 수 있겠다.



[예1 - 1] 등식의 성질을 이용한 계산


2번째 줄과 4번째 줄이 등식의 성즐을 이용한 곳이다.

2번째 줄에서는 양변에 2a 를 더했으며,

4번째 줄에서는 양변에 2를 빼 주었다.

양변에 더하거나 빼주어서, 한변에  0을만들어 해당항을 없애는 효과를 내 준것이다.


결론은 이러하다.

이항은 등식의 성질에서 나왔다.


따라서, 등호가 없으면 이항도 불가하다.

이부분은 다음에 자주틀리는 문제에서 다루어 보도록 하자.


그럼 안녕~



Feedback : smile.k06@gmail.com



반응형

 

 

….. 쓴글이 다 날라갔지만그것도 두번.. 와 멘탈 날라가네 ㅠㅠ

눈물을 머금고 다시 작성해 봅니다.

이 시리즈는 간단한 수학의 개념에 대해 다룰텐데요.

중학수학을 처음 접하는 학생, 수학에 대한 공포심이 있는 학생, 수학의 기본을 알고 싶은 학생들에게 도움이 될 듯 합니다.

제가 실제로 학생들과 접했을 때 당연하지만 애매하게 생각하는 부분들을 정리해 보았습니다.

편의상 반말체로 글을 쓸 생각입니다

도움이 되었으면 좋겠습니다.

 

 

사칙연산에 대해 간단히 정리를 해보자.

덧셈(+), 뺄셈(-), 곱셈(×), 나눗셈(÷) 이 그것이다.

물론 사칙연산이 무엇인지에 대해서는 다루지는 않겠다.. ^^a

 

 

사칙연산에서 개인적으로 개념적으로 알았으면 좋겠부분은, +- 한묶음 ×랑÷을 한묶음 이다 라는 점이다.

곱셈은 무난한데 나눗셈만하면 잦은 실수가 난다거나 하는 경우 이것을 떠올리면 좋겠다.

덧셈과 뺄셈, 곱셈과 나눗셈은 마치 하나씩 봐도 좋을 정도로 성질이 비슷한데..

그 이유는 이러하다.

[예제1] 을 보자

 

[예제1] 덧셈과 뺄셈의 관계

[예제1]을 보면 알 수 있다시피, 뺄셈은 덧셈으로 변환이 가능하다. 또한, 원래 수가 실수라면 반대 부호가 붙은 것도 당연하게 실수 이므로, 실수 범위 안에 덧셈과 뺄셈은 덧셈으로 생각해도 무방하다 라는 점.

곱셈과 나눗셈도 마찬가지다.

[예제2] 를 보자 

[예제2] 곱셈과 나눗셈의 관계

보다시피, 나눗셈도 곱셈으로 변환할 수 있다. 실수범위에서는 원래 수의 역수라 할지라도 당연히 실수이므로, 실수 범위 안에서 곱셈과 나눗셈은 곱셈으로 생각해도 되겠다.

 

그래서 인지 때때로 비슷한 성질을 보이곤 한다.

2-1에서 배우는 부등식의 성질을 보자.

 

[예제3] 부등식의 성질 덧셈과 뺄셈

부등식에서는 부등식의 양변에 같은 수를 더하거나 빼주어도 부등호의 방향은 변하지 않는다.

 

 

[예제4] 부등식의 성질 곱셈과 나눗셈

하지만, 곱셈과 나눗셈에는 주의 해야 할 점이 있는데, 양변에 음수를 곱한다면 부등호의 방향이 바뀐다는 점이다.

이 포스팅에서는 성질들에 대하여 자세히 다루지는 않겠지만,

포인트는 이것이다. 덧셈과 뺄셈, 곱셈과 나눗셈이 다른 성질을 가진다는 것. , 덧셈이 가진성질은 뺄셈도 가지고 있고, 곱셈이 가지는 성질은 나눗셈도 가지고 있게 된다는 것이다.

요점을 인지하면, 사칙연산 중 이게 맞나?’ 라고 생각 되는 부분이 덜하게 될 것이당.

 

급 마무리를 지어야지.

글을 두번이나 날려먹었더니 멘탈이.. 끄아.. ㅋㅋ

그럼 다음 포스팅에서 보아용 ~(-_ - ~)

 

 

Feedback : smile.k06@gmail.com

반응형

중고등 학생들 수학을 알려주다 보면, 수학을 잘하는 사람이던 못하는 사람이던 동일하게 계산 실수가 일어나기 마련입니다. (물론 본인도 예외는 아니지만..) 누구라도 할 수 있는게 바로 계산 실수.

 

이 시리즈는 자주 일어나는 실수(혹은 헷갈리는 부분)을 소개하는데 그 목적이 있다고 하겠습니다.

너무 당연해 보여서 이것을 글로 써야 할지도 의문일정도 일지모르지만.. 그럴싸한 실수들을 소개해서, 학생들이나 수학을 계산할 때 실수를 덜 하게 된다면 그것으로 성공!

계산실수가 많이나는 분, 수학을 포기했다가 다시 시작하려는 분, 문제는 풀리는데 답이 틀린다 하는 분들.. 등등 에게 도움이 되리라 봅니다.

보통 이 시리즈 에서는 대수학을 기반으로 이해를 요구하도록 합니다. 말만 그럴싸하고, 사실은 그냥 최대한 쉽게 이해하게끔 하려 하는 것이지요. , 그리고 이하 내용은 반말체 입니다.. ㅋㅋ

 

 

 

이번 글은 약분에 대해서 다룰 건데..

모름지기 약분이라는 것은 기약분수로 만드는 것에 그 목적이 있다 하겠다. 예를 들면, 이런 것.

분자의 4와 분모의 62를 인수로 가지고 있으므로 두 수를 2로 나누어 주었다. 쉽지?

포인트는, 분모와 분자가 동일하게 가지고 있는 인수로 분모와 분자에 나누어 주는 것 에 그 목적이 있다 는 점. 일단 무슨말인지 인지 모르면 잊자

 

, 조금 더 가보자. 이제 자주하는 실수인데,

이 문제라면 어떠할까. 이런 약분이 단순 문제로 나오기는 힘들지만, 계산 도중 반드시 거쳐가는패턴 중에 하나다. 이런 분수의 약분 시 자주 나오는 실수는 이렇다.

어디가 틀렸을까. 바로 찾기 어렵다면 이하의 예제를 보자.

예제1의 계수들만 떼어서 예를 들어보자. 우선 먼저 약분하지 말고, 단순 계산을 이용해서 방법을 사용하지 않고 풀어보자.

이런 일련의 과정이 나온다. 여기서 중요한 것은 계산이 아니라 정답이다. 답은 3. 3과 같은 정답이 나오도록 다시 예제 1-1 을 보자.

여기서 약분을 분자의 좌측인 2에다만 한다면

라는 결론에 이르게 된다. 이상하지 않은가?

옳은 방법은, 분자에 +(혹은 - ) 로 연결된 인자 모두에게 동시에 약분을 하는 것이다.

이렇게 하면 된다. 포인트는 덧셈(그리고 뺄셈)으로 이루어져 있는 식의 약분은 각 인자 모두에게 동시에 해줘야만 한다는 점.

예제 1로 돌아가서 다시 약분을 진행해 보자.

이렇게 되겠다.

간단한 자연수로 약분을 해 보았는데, 조금 어렵게 설명한다면 이렇다. 상단에서 약분은 분모와 분자가 동일하게 가지고 있는 인수로 분모와 분자에 나누어 주는 것 이라 했다. 중요한 점은 분모와 분자의 인수 인데, 덧셈으로 이루어져 있는 식이 분모 혹은 분자에 있을 경우는, 식 전체의 인수가 아니라면 분모 혹은 분자의 인수가 아니다.

무슨말인고 하면예제1의 분자부분을 인수분해 해 보자.

분자에서 보면,  이 인수라는 얘기다. 따라서 같은 인수인 로 약분을 하는 것이 옳은 방법 이라는 점.

 

이것만 기억해보자.

한줄요약,

덧셈(혹은 뺄셈)으로 이루어져 있는 식이 분모다 분자에 존재한다면, 동시에 약분을 해줘야만 한다는점!

 

다음포스팅에는 흔히 실수하는 등식에서 일어나는 실수를 다루어 보기로 한다. ~(-_ -~)



Feedback : smile.k06@gmail.com


반응형

http://kimdw819.tistory.com/41




조명 효과는 vertex 마다 normal 과 비츼 방향을 내적해 구합니다.  범프 매핑에서는 픽셀마다 normal을 줘서 빛에 대한 효과를 줘서 표면에 울퉁불퉁하거나, 주름지고, 물결치는 것 같이 표면이 불균일하게 보이도록 합니다.  
픽셀마다 normal을 얻어 오기 위해 텍스쳐 맵을 하나 더 사용합니다. 이 텍스쳐에 높이 값을 넣어서, 인접 픽셀간의 높이 차이를 통해 normal을 구할 수 있습니다.

[그림1]


위의 그림1은 높이 맵으로 만들어 놓은 것을 읽어서 법선 맵으로 만드는 소스의 부분입니다. 
우선 텍스쳐를 높이 맵과 동일한 크기로 만들고, 텍스처에 읽은 후에 법선을 만들어 놓습니다. D3DXComputeNormalMap에서 뒤에 D3XCHANNEL_RED 부분은 높이 맵에서 ARGB에서 R 값을 읽어서 10을 scale로 높이를 만들어 비교후에 법선을 만든다는 뜻입니다.  R * 10 이 해당 픽셀의 높이. 근처 픽셀의 높이 값을 구해 법선으 구한다.

 월드 좌표계에 있는 빛과 픽셀에 있는 normal을 내적을 통해 계산을 하려면 같은 공간에 일치 시켜야 합니다. 2개의 공간에 있으니 둘 중에 하나를 변환시켜 같은 공간에 있으면 되는데, 월드 좌표계에 있는 빛을 픽셀이 위치한 좌표계로 옮기는게 좀 더 간단합니다. 픽셀이 위치한 좌표계는 여러 책을 보니 다양하게 정의를 하는데 vertex 공간 좌표계, tangent 공간 , 텍스쳐 공간 좌표계 라는 정의가 있습니다.  
이 공간은 법선은 항상 양의 z축을 가리키는 좌표계입니다.  tangent 공간이라고 정의하고 설명을 하겠습니다.
tangent 공간의 법선과 월드 공간 좌표계에 위치한 빛을 내적하려면, 위에 말했다시피 월드 공간 좌표계의 빛을 tangent 공간으로 변환을 해야 합니다.  object space -> tangent space로 변환 하는 행렬을 찾도록 하겠습니다.

 tangent 공간의 2가지 접선 벡터 T,B는 텍스쳐 맵에 정렬된 접선 벡터입니다.( 여기서 접선 벡터는 2개의 벡터가 붙어있다는 것에 중점을 두고 있습니다. 이 2개의 벡터를 외적하면 2개의 벡터와 직교하는 벡터가 만들어 집니다)

T는 텍스쳐 가로 좌표 u 에 따른 위치 변화 , B는 텍스쳐 세로 좌표 v에 따른 위치 변화로 구할 수 있습니다


밑에 그림에서 P, P1 ,P2 는 정점(vertex)의 위치를 나타냅니다. Q1,Q2는 이를 연결하는 벡터르 의미합니다.
밑에 위치한 식들은 T,B를 구하는 방법을 나타냅니다.




앞에 상수항은 후에  T,B 벡터들을 재 정규화 할때 normalize 가 되서 없어지기 때문에 생략 가능합니다.


참고 도서.  Real-Time rendering -  Tomas Eric 공저
                DirectX 9 셰이더 프로그래밍   - 타카시 이마가레 저 
               3D 게임 프로그래밍 & 컴퓨터 그래픽을 위한 수학  - Eric Lengyel  저
               Direct3D ShaderX          - wolfgang F. engel 공저


반응형
1. 호도법, 평면각(라디안,rd), 입체각(스테라디안,sr) 이란?

  ※ 호도법 (Circular Measure)
     - 일반 각도법으로는, 무리수 표현이 어려워지는 등, 여러가지로 불편하여, 
     - 길이 비율에 따라 각도를 표현하는 방법

  ㅇ 평면각 (Plane Angle) (라디안)
     - 두 `길이`의 비율로 표현되는 각도

  ㅇ 입체각 (Solid Angle) (스테라디안) 
     - `넓이`와 `길이의 제곱`과의 비율로 표현되는 각도


2. 평면각(라디안) 및 입체각(스테라디안)의 단위 [ SI 단위계의 보조단위 ]

  ※ 평면각,입체각은 순수한 수(數)로 된 단위로써 사실상 무 차원의 물리량이나,
     - 호도법 표기를 강조하기 위해 단위를 각각 radian, steradian 으로 씀

  ㅇ radian     :  평면각의 단위 [rad]
     - 1 radian 은, 
         . 반지름과 동일한 호의 길이가 품는 각도
            .. 즉, 원주 상에서 그 반경과 같은 길이의 호를 끊어서 얻어진,
            .. 2개의 반경 선 사이에 낀 (평면의) 각을 말함

     - 반지름 r인 원에서, 호의 길이 s인 평면각은,  α = s / r = 원주 길이 / 반지름 길이

     - 일반 각도 및 라디안의 관계는,
        . 완전한 원은 원주 길이가 2πr 이므로, 2πr/r [rad]= 2 π [rad] = 360 [˚]

     - 例) 원 전체 원주(1원주) =>  2π[rad] = 360[˚] => 1 [rad] = 180/π[˚] ≒ 57.2958[˚]

  ㅇ steradian  :  입체각의 단위 [sr]
     - 1 steradian 은, 
         . 단위 구에서, 구면 상의 단위 면적을 품는 입체 각도
         . 또는, 구의 반경의 제곱과 같은 표면적에 해당하는 공간 입체 각도
            .. 구의 중심을 정점으로한 구표면에서 그 구의 반경을 한 변으로 하는,
            .. 정사각형 면적(r²)과 같은 곡면 표면적(r²)을 갖는 공간적인 각을 말함

     - 반지름 r인 구에서, 표면적 A에 해당하는 입체각은,  ω = A / r2

     - 例) 전 구의 입체각은,
        . 구의 전 표면적이 4πr²이므로,  4π [sr]


3. 구의 미소 면적 및 미소 입체각(differential solid angle) (구좌표계에서)

  ㅇ 구 전체 표면적  A   = 4πr2   [㎡] 
  ㅇ 미소 면적소     dA  = r2 sinθdθdΦ  [㎡]
  ㅇ 미소 입체각     dΩ = sinθdθdΦ  [sr]
 
 

 

 

 

입체각

[ solid angle , 立體角 ]
 
요약
공간에서 O를 한 끝점으로 하는 사선(射線:ray) OA가 O의 둘레를 회전하여 처음의 위치로 되돌아올 때, 그려진 도형을 입체각이라 하며 O를 꼭지점이라 한다. 입체각의 단위는 1sr(스테라디안:steradian)이라고 한다.

공간에서 O를 한 끝점으로 하는 사선(射線:ray) OA가 O의 둘레를 회전하여 처음의 위치로 되돌아올 때, 그려진 도형을 입체각이라 하며 O를 꼭짓점이라 한다. 이 경우 입체각의 크기는 O를 중심으로 하여 반지름 1인 구(球)가 이 입체각의 변과 만나서 이루어지며, 구면 위의 도형 S의 넓이로 측정된다.

S의 넓이가 1일 때, 이 입체각을 1sr(스테라디안:steradian)이라고 한다. 이것이 입체각의 단위이며, 평면의 경우의rad(라디안:radian)의 정의를 구면 위로 확장한 것이라고 할 수 있다. 또 전 구면의 중심점에 대한 입체각의 1/(4π)이 1sr이 된다.

[네이버 지식백과] 입체각 [solid angle, 立體角] (두산백과)

 

 

 


 



출처 : 위키

스테라디안

위키백과, 우리 모두의 백과사전.
 
 
1 스테라디안.

스테라디안(steradian, 기호 sr)은 입체각의 국제 단위이다. 평면에서 각도를 나타내는 라디안처럼, 3차원 공간에서 각도로 나타나는 2차원의 영역을 나타낼때 사용된다. 용어는 견고함을 의미하는 그리스어: στερεός 

스테레오스[*]

 와 광선을 의미하는 라틴어: radius 

라디우스

에서 유래한다.

스테라디안은 라디안 처럼 무차원상수이다. 즉, 1 sr = m2·m-2 = 1. 구 전체의 입체각은 4\pi sr이 된다.

정의[편집]

1 스테라디안은 반지름이 r인 의 표면에서 r2인 면적에 해당하는 입체각이다.

콘의 단면(1) 과 잘린 반구(spherical cap) (2)

면적 A가 r2 와 같고, 반구의 표면적 (

A = 2\pi rh

)과도 같다면, 

\frac{h}{r}=\frac{1}{2\pi}

 이 관계를 따르게 된다. 그러므로, 각 

\theta

를 갖는 콘의 입체각은 다음과 같아진다.

 \begin{align} \theta & = \arccos \left( \frac{r-h}{r} \right)\\        & = \arccos \left( 1 - \frac{h}{r} \right)\\        & = \arccos \left( 1 - \frac{1}{2\pi} \right) \approx 0.572 \,\text{rad} \mbox{ or } 32.77^\circ \end{align}

이것은 축으로부터의 각(apex angle)의 2

\theta

 ≈ 1.144 rad or 65.54°에 대응된다.

구의 면적이 

4\pi

 r2이므로, 정의에 의해 구는 4

\pi

 =12.56637 스테라디안이다. 같는 논리로, 최대 입체각은 4

\pi

sr 이다. 스테라디안은 squared radian으로 불리기도한다.

스테라디안은 1 라디안의 angle excess(angle excess)를 갖는 다각형의 구면, 또는 완전한 구의 1/(4

\pi

), 또는 (180/

\pi

)2 제곱 각(square degree), 또는 3282.80635 제곱 각과 같다.

스테라디안은 SI 보조 단위였으나, 1995년 SI 보조 단위가 폐지 되면서, SI 유도 단위가 되었다.

라디안과 유사성[편집]

2차원 평면에서, 라디안으로 표현되는 각은 잘려지는 호의 길이와 관련이 있다.

\theta = \frac{l}{r} \,
l 은 호의 길이
r 은 원의 반지름.

3차원에서, 스테라디안으로 표현되는 입체각은 잘려지는 면적과 관련이 있다.

\Omega = \frac{S}{r^2} \,
S 은 표면적
r 은 구의 반지름.

 

 

 

 

 


 

 

http://goo.gl/QgJXjg

 

1스테라디안(1sr)은 몇도인가요??

 

 

호도법의 360도는 라디안으로 고치면 2∏ 라디안이 됩니다.

따라서 1라디안 = 360/2∏ 이고 ∏는 3.14정도되므로 1라디안 = 57.32도 정도가 됩니다.

 

스테라디안은 원의 각도를 나타내는 단위가 아니고 구(공)의 각도를 나타내는 단위입니다.

즉, 구 반지름의 제곱과 같은 구 표면적에 대응하는 구의 입체각으로 정의됩니다.

예를들어 공의 반지름이 1m 라고 하면 반지름의 제곱은 1m^2 가 됩니다.

공의 표면상에 한면이 1m인 정사각형을 그리고 이 정사각형의 각 꼭지점에서 공의 중심까지

선을 그린다고 하면 4개의 선이 공의 중심에서 만나게 됩니다. 이때 이 4개의 선이 만든

입체각을 나타내는 단위가 스테라디안입니다.

구의 표면적은 잘 알려져있다시피 4∏r^2 입니다. 여기서 r은 구의 반지름이지요.

따라서 구의 중심각은 4∏가 됩니다. (원의 중심각은 360도 인것처럼)

 

 


 

 

Solid Angle (입체각) 


복사http://blog.naver.com/hsg556/110130248554

 

 

 

기본 개념

 

평면각이 평면에서의 퍼짐 정도를 나타내는 척도의 개념이라면 입체각은 말 그대로 공간에서의 퍼짐 정도를 나타내는 척도로서의 각도이다. 이러한 공간에서의 퍼짐을 표시하는 각도의 개념은 등방위성으로 퍼지는 현상, 예를 들어 점원(point source)으로부터의 빛, 전파, 방사선이 발산될때의 세기를 기술하는 데 아주 유용한 도구가 된다.

아래 그림에서 점0에 점광원이 놓여져 있을 때, 비록 면‘가’와‘가`’는 서로 면적의 형상 및 크기가 다르지만 두 면 다 빛의 동일한 퍼짐 각도 이내에 있기에 이 두 면에 도달하는 빛 에너지의 합은 같게 된다. 이와같이 이러한 의미로 정의되는 각도를 공간에서 정의하면 공간에서의 세기와 같은 문제를 쉽게 다룰수 있는 도구가 된다.

(그림1 입체각의 개념 및 투영)

입체각의 정성적 및 정량적 정의

 

이러한 기능의 개념인 입체각의 정의는?

이의 정성적 정의는 위에서 설명한 그대로 공간에서의 퍼짐을 표시하는 척도.

 

실제사용을위해서는?

정량적 정의가 필요

 

정량적 정의의 이해를 위해서 먼저 위의 정성적 정의의 입체각 성격을 보면,

이 각도는 점원으로부터 공간의 어느 지점까지의 거리에 반비례하고,

좀더 정확히 이야기하면 거리의 제곱에 반비례하고, 또 그 지점에서 얼마나 펼쳐지는 가에 비례함을 알 수 있다.

 

즉 이러한 특성에 따라 입체각의 크기를 다음 식과 같이 정량적으로 정의하면 필요한 특성을 지니게 된다.

 

   ......      1)

 

그런데 이 식에서 면적은 점원에 기울어진 면적이 아니라 점원으로부터 그 면까지 그려지는 선분에 수직한 면적이어야만 위에서 이야기된 입체각에 요구된 특성이 만족될 수 있다. 즉,

 

   

     ........   2)

 

이를 vector 연산식으로 표시하면 표현은 매우 간단해지는 데,  미소면적 dA에 대한  입체각 dΩ는,

........   3)

n 은 해당 면의 단위 표면 vector, dA는 수직성분 여부와 관련없이 그 면의 실제크기, r은 점원에서 해당 면까지의 거리 vector

 

식2) 또는 대등하게 식3)이 고체각에 대한 정량적 정의다. 참고로, 3)에서 분모의 r의 지수가 2가 아닌 3이지만 분자에 r이 있기에 결국은 앞에서 식2) 와 같이 r의 지수는 2가 된다.

 

정의식 식3) 을 이용하여 미소면적이 아닌 유한 면적에 대해 적용하고 , 식3) 의 vector연산을 간략히 하기 위하여 적용면적에 투영 면적의 개념을 적용한다. 달리 표현하면 그 면의 거리 vector r 에 대해 수직하면서 동일한 고체각도인 면에 대해 적용한다.

즉 그림 1)의 면  '나'는,  면 '가'를 동일 원점을 중심으로 하는 구에 투영시킨 면이고 이 두 면은 공간에서 퍼짐의 정도가 서로 같기에  고체각 역시 서로 같다. 따라서 면 '나'에 대한 고체각 작업 결과는 '가'에 대한 결과와 동일. (단, 그림에서는 두 면의 개념상의 차이를 나타내기 위해 면 '가'와 '나'의 r 이 서로 다르게 그려져있는 데, 이해를 쉽게 하기 위해  면 '나'를 당겨와 r 이 면 '가'의 r 이 되는 지점에 면 '나'가 위치한 것으로 상정한다.)

 

면 '나'에서

 ....... 4)

식 4) 를 식 2) 또는 식 3)에 대입하면,

..........  5)

 

식 5)  로부터 알 수 있듯이 입체각은 무차원인데 편의상 steradian 단위 또는 sr이란 약자를 붙여서 표시하기도 한다.

또한 고체각이라는 용어가 사용되기도 한데 이는 입체각에 해당되는 영어표현 solid angle을 그대로 옮긴 것으로 바람직스럽지 못한 용어다.

 

반구에 대한 고체각은 식 5) 로 부터

 ....... 6)

또는 식 2)로부터도 역시 같은 결과를 얻을 수 있다.

 

즉, 구의 표면적 = 

 이기에

.............................     7)

 

유사하게,

 

입체각의 적용

 

고체각의 개념은 이러하고, 좀 현실적인 감을 익히기 위해 다음 그림과 같이

(그림 2. 원추의 입체각)

 

사이각이 θ 인 직삼각형 1-2-3을 한바퀴 회전시켰을 때 만들어지는 원추의  입체각은

........... 8)

 

식 8) 에 의해 몇가지 사이각θ에 대한 입체각은 다음과 같다

 평면각 θ(도)  입체각sr
 0  0
 10  0.0954
 20  0.379
 30  0.842
 40  1.470
 45  1.840
 60  3.142
 90  6.283 (= 
:반구)
 180  12.6 (=
:공간전체)

 

===========================================================================================================================

[출처] : 네이버 오픈사전

네이버 스마트 에디터 수식입력기로 수식 입력... 좋은데?

띄어쓰기 및 줄 맞춤, 단어 맞춤 추가

[출처] Solid Angle (입체각)|작성자 GUNN

 

ref : http://www.ktword.co.kr/test/view/view.php?id=545&m_temp1=975&nav=1

 

 

반응형

BLOG main image




투영행렬로 변환 한 후 다시 카메라 공간의 위치,벡터(norm) 을 구하는 방법


D3DXVECTOR3 p1InCamera(33,-24,-2),p2InCamera(0,0,2);


D3DXVECTOR3 normC,norm(10,0,-10),normP;

D3DXVECTOR4 outP1InProj,outP1InProj_w,outP2InProj,outP2InProj_w,outNorm,resultCameraP;

D3DXVec3Normalize( &norm,&norm );

D3DXVECTOR3 outP1InProj_( outP1InProj.x,outP1InProj.y,outP1InProj.z ),cameraP,projP;


/*

* D3DXVec3Transform 는 w 로 결과 벡터를 나누지 않고 그대로 D3DXVECTOR4 를 만들지만

* D3DXVec3TransformCoord 는 결과 벡터를 w 로 나누고 w 값을 1 로 채우는 형식이다

* D3DXVec3TransformCoord 로써 투영행럴의 역행렬 을 적용하여 카메라공간에서의 를 점을 얻을 수 있다

**/


D3DXVec3Transform( &outP1InProj, &p1InCamera, &matProjection );

projP.x=outP1InProj.x;

projP.y=outP1InProj.y;

projP.z=outP1InProj.z;

projP/=outP1InProj.w;

D3DXVec3Transform( &resultCameraP,  &projP, &invProj );

resultCameraP/=resultCameraP.w;



필요한경우 노멀벡터또한 투영행렬로 변환했다가 역투영행렬로 변환 할 수 있는데 다음과 같다


D3DXVec3TransformCoord( &normP, &norm, &matProjection );        //normP 는 내부적트로 계산된 normPInner/=normPInner.w 의 형태임을 주의해야한다!!!

D3DXVec3TransformCoord( &normP,  &normP, &invProj );             // 아래또한 같다


D3DXVec3TransformNormal 은 투영행렬의 특성상 z 값이 소실될 수 있음으로 z 값이 제대로 나오지 못한다



한가지 주의사항은 normal 을 투영행렬 공간에서 어떠한 연산을 하면 안된다는 것이다

왜냐하면 D3DXVec3TransformCoord 를 적용한 투영공간상의 z 는  0 < z  < 1  의 값으로 그려지는 오브젝트에 대해서 z값이 

항상 양수임으로



아래는 d3dx9math.h 내용

언젠가 올려놓은적이 있는것 같은데 긁어옴








 

http://cafe.naver.com/jzsdn/6192

 

 

Matematika v Direct3DX

(English info)

V této kapitole je seznam matematických funkcí Direct3DX (což je jakýsi toolkit pro Direct3D (DirectXGraphics), jistá obdoba knihovny GLUT pro OpenGL), spolu s popisem matematiky, kterou tyto funkce provádí.

Upozorňuji, že toto není oficiální dokumentace k Direct3DX (ta se nalézá někde na MSDN).

Vektory

D3DXVecNAdd(Out, V1, V2)

Out = V1 + V2

D3DXVecNBaryCentric(Out, V1, V2, V3, f, g)

Out = V1 + f⋅(V2V1) + g⋅(V3V1)

D3DXVecNCatmullRom(Out, V1, V2, V3, V4, s)

/0100\/V1\
||||
|−0,500,50||V2|
Out = (1,s,s²,s³)||||
|1−2,52−0,5||V3|
||||
\−0,51,5−1,50,5/\V4/

D3DXVecNDot(U, V)

Result = U ⋅ V = ∑iUiVi

D3DXVecNHermite(Out, V1, T1, V2, T2, s)

/1000\/V1\
||||
|0010||V2|
Out = (1,s,s²s³)||||
|−33−2−1||T1|
||||
\2−211/\T2/

D3DXVecNLength(V)

Result = |V| = √(∑iVi²)

D3DXVecNLengthSq(V)

Result = |V|² = ∑iVi²

D3DXVecNLerp(Out, V1, V2, s)

Out = V1 + s(V2V1);

D3DXVecNMaximize(Out, U, V)

Outi = max(Ui, Vi)

D3DXVecNMinimize(Out, U, V)

Outi = min(Ui, Vi)

D3DXVecNNormalize(Out, V)

Out = 1|V|V

D3DXVecNScale(Out, V, s)

Out = sV

D3DXVecNSubtract(Out, V1, V2)

Out = V1 − V2


2D Vektory

D3DXVec2CCW(U, V)

Result = UxVy − UyVx

D3DXVec2Transform(Out, V, M)

a = (Vx, Vy, 0, 1)
b = (a×M)T
Out = (bx, by)

D3DXVec2TransformCoord(Out, V, M)

a = (Vx, Vy, 0, 1)
b = (a×M)T
Out = 1bw(bx, by)

D3DXVec2TransformNormal(Out, V, M)

a = (Vx, Vy, 0, 0)
b = (a×M)T
Out = (bx, by)


3D Vektory

D3DXVec3Cross(Out, V1, V2)

Out = V1 × V2

D3DXVec3Project(Out, V, Viewport, Proj, View, World)

a = (Vx, Vy, Vz, 1)
b = a×World×View×Proj
c = bbw
Outx = ViewportX + ViewportWidth*(1+cx)/2
Outy = ViewportY + ViewportHeight*(1-cy)/2
Outz = ViewportMinZ + cz*(ViewportMaxZ-ViewportMinZ)

D3DXVec3Transform(Out, V, M)

a = (Vx, Vy, Vz, 1)
b = (a×M)T
Out = (bx, by, bz)

D3DXVec3TransformCoord(Out, V, M)

a = (Vx, Vy, Vz, 1)
b = (a×M)T
Out = 1bw(bx, by, bz)

D3DXVec3TransformNormal(Out, V, M)

a = (Vx, Vy, Vz, 0)
b = (a×M)T
Out = (bx, by, bz)

D3DXVec3Unproject(Out, V, Viewport, Proj, View, World)

M = (World×View×Proj)−1
ax = (Vx-Viewportx)*2/ViewportWidth - 1
ay = 1 - (Vy-Viewporty)*2/ViewportHeight
az = (Vz-ViewportMinZ)/(ViewportMaxZ-ViewportMinZ)
aw = 1
b = (a×M)T
Out = 1bw(bx, by, bz)


4D Vektory

D3DXVec4Cross(Out, U, V, W)

a = VxWy − VyWx
b = VxWz − VzWx
c = VxWw − VwWx
d = VyWz − VzWy
e = VyWw − VwWy
f = VzWw − VwWz
Outx = fUy − eUz + dUw
Outy = fUx + cUz − bUw
Outz = eUx − cUy + aUw
Outw = dUx + bUy − aUz

D3DXVec4Transform(Out, V, M)

Out = (V×M)T


Matice (4×4)

D3DXMatrixAffineTransformation(Out, s, c, r, t)

/s(2(ry² + rz²) − 1)2s(rxry + rzrw)2s(rxrz − ryrw)0\
||
|2s(rxry − rzrw)s(2(rx² + rz²) − 1)2s(ryrz + rxrw)0|
Out =||
|2s(rxrz + ryrw)2s(ryrz − rxrw)s(2(rx² + ry²) − 1)0|
||
\tx+2(cxry²+cxrz²−cyrxry+cyrzrw−czrxrz−czryrw)ty+2(cyrx²+cyrz²−cxrxry−cxrzrw−czryrz+czrxrw)tz+2(czrx²+czry²−cxrxrz+cxryrw−cyryrz−cyrxrw)1/

D3DXMatrixfDeterminant(M)

Result = det M

D3DXMatrixIdentity(Out)

/1000\
||
|0100|
Out = E =||
|0010|
||
\0001/

D3DXMatrixInverse(Out, D, M)

D = det M
Out = M−1

D3DXMatrixIsIdentity(M)

Result = ME

D3DXMatrixLookAtRH(Out, Eye, At, Up)

v = Normalized(EyeAt)
l = Up×v
u = v×l

/lxuxvx0\
||
|lyuyvy0|
Out =||
|lzuzvz0|
||
\−l⋅Eye−u⋅Eye−v⋅Eye1/

D3DXMatrixLookAtLH(Out, Eye, At, Up)

v = Normalized(AtEye)
r = Up×v
u = v×r

/rxuxvx0\
||
|ryuyvy0|
Out =||
|rzuzvz0|
||
\−r⋅Eye−u⋅Eye−v⋅Eye1/

D3DXMatrixMultiply(Out, M1, M2)

Out = M1×M2

D3DXMatrixOrthoRH(Out, w, h, n, f)

Q = (f−n)−1

/2w000\
||
|02h00|
Out =||
|00−Q0|
||
\00−Qn1/

D3DXMatrixOrthoLH(Out, w, h, n, f)

Q = (f−n)−1

/2w000\
||
|02h00|
Out =||
|00Q0|
||
\00−Qn1/

D3DXMatrixOrthoOffCenterRH(Out, l, r, t, b, n, f)

Q = (f−n)−1
w = r−l
h = b−t

/2w000\
||
|02h00|
Out =||
|00−Q0|
||
\−(r+l)2−(t+b)2−Qn1/

D3DXMatrixOrthoOffCenterLH(Out, l, r, t, b, n, f)

Q = (f−n)−1
w = r−l
h = b−t

/2w000\
||
|02h00|
Out =||
|00Q0|
||
\−(r+l)2−(t+b)2−Qn1/

D3DXMatrixPerspectiveRH(Out, w, h, n, f)

Q = (f−n)−1

/2w000\
||
|02h00|
Out =||
|00−Qf−1|
||
\00−Qnf0/

D3DXMatrixPerspectiveLH(Out, w, h, n, f)

Q = (f−n)−1

/2w000\
||
|02h00|
Out =||
|00Qf1|
||
\00−Qnf0/

D3DXMatrixPerspectiveFovRH(Out, Fovy, Aspect, n, f)

Q = (f−n)−1
y = cotg(Fovy)2

/yAspect000\
||
|0y00|
Out =||
|00−Qf−1|
||
\00−Qnf0/

D3DXMatrixPerspectiveFovLH(Out, Fovy, Aspect, n, f)

Q = (f−n)−1
y = cotg(Fovy)2

/yAspect000\
||
|0y00|
Out =||
|00Qf1|
||
\00−Qnf0/

D3DXMatrixPerspectiveOffCenterRH(Out, l, r, t, b, n, f)

Q = (f−n)−1
w = r−l
h = b−t

/2w000\
||
|02h00|
Out =||
|(r+l)w(t+b)h−Qf−1|
||
\00−Qnf0/

D3DXMatrixPerspectiveOffCenterLH(Out, l, r, t, b, n, f)

Q = (f−n)−1
w = r−l
h = b−t

/2w000\
||
|02h00|
Out =||
|−(r+l)w−(t+b)hQf1|
||
\00−Qnf0/

D3DXMatrixReflect(Out, Plane)

(a,b,c,d) = (Planea,Planeb,Planec,Planed)√(Planea²+Planeb²+Planec²)

/1−2a²−2ba−2ca0\
||
|−2ab1−2b²−2cb0|
Out =||
|−2ac−2bc1−2c²0|
||
\−2ad−2bd−2cd1/

D3DXMatrixRotationAxis(Out, V, Angle)

s = sin Angle
c = cos Angle
d = 1−c
(x,y,z) = V

/dx²+cdxy+zsdxz−ys0\
||
|dxy−zsdy²+cdyz+xs0|
Out =||
|dxy+ysdyz−xsdz²+c0|
||
\0001/

D3DXMatrixRotationQuaternion(Out, Q)

(x,y,z,w) = Q

/1−2y²−2z²2xy+2zw2xz−2yw0\
||
|2xy−2zw1−2x²−2z²2yz+2xw0|
Out =||
|2xz+2yw2yz−2xw1−2x²−2y²0|
||
\0001/

D3DXMatrixRotationX(Out, Angle)

s = sin Angle
c = cos Angle

/1000\
||
|0cs0|
Out =||
|0−sc0|
||
\0001/

D3DXMatrixRotationY(Out, Angle)

s = sin Angle
c = cos Angle

/c0−s0\
||
|0100|
Out =||
|s0c0|
||
\0001/

D3DXMatrixRotationYawPitchRoll(Out, Yaw, Pitch, Roll)

(sa,sb,sc) = sin (Roll, Pitch, Yaw)
(ca,cb,cc) = cos (Roll, Pitch, Yaw)

/ca⋅cc+sa⋅sb⋅sc−sa⋅cc+ca⋅sb⋅sccb⋅sc0\
||
|sa⋅cbca⋅cb−sb0|
Out =||
|−ca⋅sc+sa⋅sb⋅ccsa⋅sc+ca⋅sb⋅cccb⋅cc0|
||
\0001/

D3DXMatrixRotationZ(Out, Angle)

s = sin Angle
c = cos Angle

/cs00\
||
|−sc00|
Out =||
|0010|
||
\0001/

D3DXMatrixScaling(Out, x, y, z)

/x000\
||
|0y00|
Out =||
|00z0|
||
\0001/

D3DXMatrixShadow(Out, Light, Plane)

(a,b,c,d) = (Planea,Planeb,Planec,Planed)√(Planea²+Planeb²+Planec²)
(x,y,z,w) = Light
f = Lightx⋅Planea + Lighty⋅Planeb + Lightz⋅Planec + Lightw⋅Planed

/f−xa−ya−za−wa\
||
|−xbf−yb−zb−wb|
Out =||
|−xc−ycf−zc−wc|
||
\−xd−yd−zdf−wd/

D3DXMatrixTransformation(Out, Scenter, Srot, Scaling, Rotcenter, Rot, Trans)

D3DXMatrixTranslation(A, -Scenterx, -Scentery, -Scenterz)
D3DXMatrixScaling(B, Scalingx, Scalingy, Scalingz)
D3DXMatrixRotationQuaternion(CSrot)
u = Scenter − Rotcenter
D3DXMatrixTranslation(D, ux, uy, uz)
D3DXMatrixRotationQuaternion(E, Rot)
v = Rotcenter + Trans
D3DXMatrixTranslation(F, vx, vy, vz)
Out = A×CT×B×C×D×E×F

D3DXMatrixTranslation(Out, x, y, z)

/1000\
||
|0100|
Out =||
|0010|
||
\xyz1/

D3DXMatrixTranspose(Out, M)

Out = MT


Roviny

D3DXPlaneDot(P, V)

Result = (Pa, Pb, Pc, Pd)⋅V

D3DXPlaneDotCoord(P, V)

Result = (Pa, Pb, Pc)⋅V + Pd

D3DXPlaneDotNormal(P, V)

Result = (Pa, Pb, Pc)⋅V

D3DXPlaneIntersectLine(Out, P, U, V)

n = (Planea, Planeb, Planec)
d = V − U
Out = U − d(Pd + nU)(dn) [iff dn ≠ 0]

D3DXPlaneFromPointNormal(Out, P, N)

Planea = Nx
Planeb = Ny
Planec = Nz
Planed = −NP

D3DXPlaneNormalize(Out, P)

q = 1√(Pa² + Pb² + Pc²)
Outa = q⋅Pa
Outb = q⋅Pb
Outc = q⋅Pc
Outd = q⋅Pd

D3DXPlaneFromPoints(Out, A, B, C)

v = (B − A) × (C − A)
n = 1|v| v
Outa = nx
Outb = ny
Outc = nz
Outd = −nA

D3DXPlaneTransform(Out, P, M)

Q = P|P|
u = (Qa, Qb, Qc, 0)
D = Qd
A = (−Dux, −Duy, −Duz, 1)
B = A×M
v = u×M
q = 1|v|
Outa = qvx
Outb = qvy
Outc = qvz
Outd = −qvB


반응형

http://blog.naver.com/likingford/10083668852



반응형



점,벡터 구분의 미묘함을 간략하게 정리한다면


벡터 : 특정 점에서 특정 점까지 상대적 차이 값, 이를 때에따라 단위벡터로 나타낼 수도 있다


점    : 원점에서 시작해 어떤 특정 점까지의 위치



p.s ;;;; 너무 간단한가, 복잡하게 말할것도 없음으로.. ㅎ



BLOG main image

반응형



쿼터니온을 사용해 오브젝트 회전시키기  번역 / Programming 

2006/03/10 14:55

복사http://blog.naver.com/lifeisforu/80022505113


원문 : http://www.gamasutra.com/features/19980703/quaternions_01.htm

 

작년은 하드웨어 가속의 시대로서의 역사에 남겨졌다고 할 수 있다. 폴리곤을 래스터라이즈화하고 텍스처 매핑을 하는 많은 작업들이 전용 하드웨어에 넘겨졌다. 결과적으로 우리 게임 개발자들은 이제 물리적 시뮬레이션 및 다른 기능들을 위해 많은 CPU 사이클을 절약할 수 있게 되었다. 쿼터니온 덕택에 그러한 부가적인 사이클들이 회전 및 애니메이션을 부드럽게 하는 것과 같은 작업을 위해 적용될 수 있게 되었다.

 

많은 게임 프로그래머들은 이미 쿼터니온의 대단한 세계에 대해서 발견했으며, 그것들을 광범위하게 사용하기 시작했다. TOMB RADIDER 타이틀을 포함한 일부 삼인칭 게임들은 그것의 카메라 움직임을 애니메이션하기 위해서 쿼터니온 회전을 사용한다. 모든 삼인칭 게임은 플레이어의 캐릭터의 측면이나 뒤에서 따라가는 가상 카메라를 가지고 있다. 이 카메라는 캐릭터와는 다른 동작을 통해(즉 다른 길이의 호(arc)를 통해서) 움직이기 때문에, 카메라 동작은 (플레이어의) 행동을 따라가기에는 부자연스럽고 플레이어에 비해 너무 "변덕"스러웠다. 이것이 쿼터니온이 해결사로 나서게 된 하나의 영역이다.

쿼터니온의 또다른 일반적 용도는 군용/상업용 비행 시뮬레이터이다. 세 개의 각(roll, pitch, yaw)를 사용하여 비행기의 방향을 조작하는 대신에 상대적으로 x, y, z 축에 대한 회전을 표현하면, 단일 쿼터니온을 사용하는 데 있어 매우 간단해 진다.

올해에 나오는 많은 게임들이 실제적인 물리를 표현하게 될 것이며, 놀라운 게임 플레이와 집중을 가능하게 할 것이다. 만약 쿼터니온으로 방향을 저장한다면, 쿼터니온에 각의 속도(velocities)를 추가하는 것이 행렬에 추가하는 것보다 계산적으로 더 적은 비용을 소비하게 할 것이다.

Tomb Raider

Tomb Raider 타이틀은 카메라 움직임을 애니메이션하기 위해서 쿼터니온 회전을 사용한다. 

 

오브젝트의 방향을 표현하기 위한 많은 방식이 존재한다. 대부분의 프로그래머들은 3x3 회전 행렬이나 세 개의 오일러(Euler) 각을 사용해 이 정보를 저장한다. 이러한 해결책들은 오브젝트의 두 방향 사이를 부드럽게 보간하려고 하기 전에는 잘 동작한다. 사용자가 제어하지 않고 단순히 공간을 자유롭게 회전하는 오브젝트를 상상해 보자(예를 들어 회전문). 만약 당신이 문의 방향을 회전 행렬이나 오일러 각으로 저장하기로 한다면, 당신은 회전 행렬의 값들을 부드럽게 보간하는 것은 계산적으로 비용이 많이 들고 쿼터니온 보간보다는 플레이어의 시점에 대해서 정확하고 부드럽게 보이지 않는다는 것을 알게 될 것이다.

 

이 문제를 행렬이나 오일러 각을 사용해 해결하고자 한다면, 애니메이터는 단순히 기정의된(keyed) 방향의 숫자를 증가시키기만 해야 할 것이다. 그러나 아무도 얼마나 많은 방향이 충분한 것인지 알 수는 없다. 왜냐하면 게임은 서로 다른 컴퓨터 상에서 서로 다른 프레임율로 작동하며, 회전의 부드러움에 영향을 줄 수 있기 때문이다. 이때가 쿼터니온을 사용할 적절한 시점이며, 이 기법은 우리의 회전문과 같은 오브젝트의 단순한 회전을 표현하기 위해서 단지 두/세개의 방향만을 요구한다. 또한 당신은 개별적인 프레임율에 따라서 보간되는 위치의 개수를 동적으로 조정할 수도 있다.

 쿼터니온 이론과 응용프로그램에 대해서 살펴보기 전에 회전이 표현되는 방식에 대해서 살펴보도록 하자. 나는 회전 행렬, 오일러각, 축, 각 표현과 같은 기법에 대해서 다룰 것이며, 그것들의 단점 및 쿼터니온과의 관계에 대해서 설명할 것이다. 만약 이러한 기법들에 대해서 익숙하지 않다면 그래픽 책을 펴서 공부하기를 바란다.


지금까지 나는 4x4 나 3x3 행렬을 사용하는 회전에 대해서 이야기하지 않는 3D 그래픽 책을 본 적이 없다. 결국 나는 대부분의 게임 프로그래머들이 이 기법에 대해 매우 친숙하다고 가정할 것이고, 나는 그것의 단점에 대해서만 이야기하도록 하겠다. 또한 Game Developer 에 1997년 6월에 작성된 Chris Hecker 의 기사("Physics, Part 4 : The Third Dimension," 페이지 15-26)를 다시 읽어볼 것을 강력히 추천한다. 왜냐하면 그것은 3D 오브젝트의 방향설정(orenting)의 문제에 대해서 문제제기하기 때문이다.

 

회전은 단지 x, y, z 좌표축을 중심으로 한 세 개의 자유각(degrees of freedom, DOF)만을 포함한다. 그러나 9 DOF(3x3 행렬이라 가정)는 회전에 제약을 가할 것을 요구한다 - 우리가 필요로하는 것보다 더 많이. 또한 행렬은 "미끄러지는(drifting)" 경향이 있다. 이것은 6개의 제약(constraint) 중 하나가 위반되고 행렬이 상대적인 축을 중심으로 한 회전을 설명할 때 이러한 상황이 발생한다.

 

이 문제와 싸우는 것은 행렬 직교화(orthonormalized)를 유지할 것을 요구한다 - 그것은 제약에 순종하는 것을 보증한다. 그러나 이렇게 하는 것은 계산적인 낭비이다. 행렬 미끄러짐을 해결하기 위한 일반적인 방법은 상대적인 기반(basis)를 직교 기반으로 변환하기 위한 Gram-Schmidt 알고리즘에 의존한다. Gram-Schmidt 알고리즘이나 행렬 미끄러짐을 해결하기 위해서 정확한 행렬을 계산하는 것은 많은 CPU 사이클을 소비하며, 부동 소수점 수학을 사용하고 있음에도 불구하고 매우 자주 수행되어야만 한다.

 

회전 행렬의 또 다른 단점은 그것들이 두 개의 방향 사이의 회전을 보간하기에는 사용하기 너무 어렵다는 것이다. 또한 결과 보간은 가시적으로 매우 변덕스러우며, 이것은 게임에 더 이상 적절치 않음을 의미한다.

당신은 세 좌표축에 대한 회전을 표현하기 위해서 각을 사용할 수도 있다. 이것을 (q, c, f) 식으로 기록할 수 있다; "q 각만큼 z 축 중심으로 반시계 방향으로 회전함으로써 점을 변환한다, 그리고 나서 c 각만큼 y 축 중심으로 회전하고, f 각만큼 x 축 중심으로 회전한다"라는 단순한 상태이다. 여기에는 당신이 오일러 각을 사용하여 회전을 표현하기 위해서 사용할 수 있는 12개의 규약(convention)이 존재한다. 왜냐하면 당신은 회전(XYZ, XYX, XYY...)을 표현하기 위해서 각들의 조합을 사용할 수 있기 때문이다. 우리는 첫 번째 규약 (XYZ)를 제출할 모든 예제를 위한 규약으로 간주한다. 나는 양의(positive) 회전은 모두 반시계 방향이라고 간주할 것이다(Figure 1).

오일러 각 표현은 매우 효율적이다. 왜냐하면 그것은 단지 세 개의 변수만을 사용해 세 개의 DOF 를 표현하기 때문이다. 또한 오일러 각은 모든 제약에 복종할 필요가 없으며, 결국 미끌어지는 경향도 없고 재조정될 필요도 없다.

그러나 연속되는 회전 결합과 관련되어 오일러 각을 사용한 단일 회전을 표현하는 쉬운 방법은 없다. 더우기 두 방향 사이의 부드러운 보간은 수치적 통합(numerical integration)을 포함하는데, 이것은 계산적으로 낭비이다. 또한 오일러 각은 "Gimbal lock" 문제나 a loss of one degree of rotational freedom 이라는 문제를 안고 있다. Gimbal lock 90도로 연속되는 회전이 수행될 때 발생된다; 갑자기 회전이 발생하지 않게 된다. 축에 정렬되어버리기 때문이다.

Figure 1
Figure 1: 오일러 각 표현.

예를 들어 비행 시뮬레이션에 의해서 연속되는 회전이 수행되었다고 상상해 보자. 당신은 첫 번째 회전을 x 축 중심의 Q1 이라고 지정하고, 두 번째 회전을 y 축 중심의 90 도 라고 지정하고, 세 번째 회전을 z 축 중심의 Q3 라고 지정했다고 하자. 만약 지정된 회전이 성공한다면, 당신은 z 축 중심의 Q3 회전이 초기 x 축 중심의 회전과 같은 효과를 가지고 있음을 발견하게 될 것이다. y 축 회전은 x 축과 z 축을 정렬되도록 만들어 버렸으며, 당신은 DOF 를 잃어버리게 되었다. 왜냐하면 한 축을 중심으로 하는 회전이 다른 축을 중심으로 하는 반대 회전과 같기 때문이다. Gimbal lock 문제에 대한 세부적인 논의를 알기 위해서는 Advanced Animation and Rendering Techniques : Theory and Practice by Alan and Mark Watt(Addison Wesley, 1992) 를 읽어볼 것을 강력히 추천한다.

축과 각을 사용하는 표현은 회전 표현의 또 다른 방식이다. 당신은 Figure 2 에서 보이는 것 처럼 상대적 축과 각을 지정한다(만약 반시계방향이라면 양의 회전임).

이것은 회전을 표현하기 위한 효율적인 방식이지만, 그것은 오일러 각 표현을 설명했던 것과 (Gimbal lock 문제를 제외하고는) 같은 문제를 내포한다

Figure 2

18세기에 W.R.Hamilton 은 복잡한 숫자에 대한 4차원 확장으로써 쿼터니온을 고안했다. 이후에 쿼터니온이 회전과 방향을 3차원에서 표현할 수도 있음이 증명되었다. 쿼터니온을 표현하기 위해서 사용할 수 있는 몇 가지 공식이 있다. 두 개의 가장 유명한 공식은 complex number 공식(Eq. 1) 과 4D vector 공식(Eq. 2)이다.

 

w + xi + yj + zk (i2 = j2 = k2 = -1 이며 ij = k = -ji 이고, w, x, y, z 는 실제 값이다.) 
(Eq. 1) 

[w, v] (v = (x, y, z) 는 "벡터" 라 불리며 w 는 "스칼라"라고 불린다) 
(Eq. 2) 

나는 두 번째 공식을 이 기사 전반에서 사용할 것이다. 쿼터니온이 표현되는 방식에 대해서 알게 되었으니, 그것들을 사용하는 기본적인 연산을 배워보자.

 


만약 q 와 q' 가 쿼터니온에 의해 표현되는 두 개의 방향이라고 한다면, 당신은 이들 쿼터니온에 Table 1 에 있는 연산을 정의할 수 있다.

모든 다른 연산들은 이들 기본적인 것들로부터 쉽게 이끌어내질 수 있으며, 그것들은 여기에 동봉된 라이브러리에서 세부적으로 설명해 놓았다. 나는 단지 단위 쿼터니온만을 다룰 것이다. 각 쿼터니온은 4D 공간으로 이동될 수 있으며(왜냐하면 각 쿼터니온은 네 개의 부분으로 구성되기 때문이다) 그 공간은 쿼터니온 공간이라고 불린다. 단위 쿼터니온은 그것들의 크기(magnitude)각 1이고 그것은 쿼터니온 공간의 하위 공간인 S3를 형성한다. 이 하위공간은 4D 구체로서 표현될 수 있다. (그것들은 하나의 단위 법선을 가진다) 이것은 당신이 수행해야만 하는 필수 연산들의 개수를 감소시켜 준다.

단지 단위 쿼터니온들만이 회전을 표현하고, 내가 쿼터니온에 대해서 이야기할 때 다른 것이 아니라 단위 쿼터니온에 대해서 이야기하고 있는 것이라고 생각하는 것은 매우 중요하다.

당신은 다른 기법들이 회전을 표현하는 방식에 대해서 이미 살펴 보았기 대문에, 쿼터니온을 사용해 회전을 지정할 수 있는 방법에 대해서 살펴 보도록 하자. 단위 쿼터니온 q 에 의한 벡터 v 의 회전은 다음과 같이 표현될 수 있다는 것이 증명될 수 있다(그리고 증명은 그렇게 어렵지 않다).

v´ = q v q-1 (v = [0, v]) 
(Eq. 3) 

결과는 회전된 벡터 v' 이며, w 를 위해서 항상 0 스칼라 값을 가지게 될 것이다(이전의 Eq. 2를 재호출). 그래서 당신은 계산을 생략할 수 있다.

Table 1. 쿼터니온을 사용한 기본 연산.

Addition: q + q´ = [w + w´, v + v´] 

Multiplication: qq´ = [ww´ - v · v´, v x v´ + wv´ +w´v] (· 은 벡터 내적이며  x 는 벡터 외적이다); Note: qq´ ? q´q


Conjugate: q* = [w, -v] 

Norm: N(q) = w2 + x2 + y2 + z2 

Inverse: q-1 = q* / N(q) 

Unit Quaternion: qN(q) = 1 이고 q - 1 = q* 일때 q 는 단위 쿼터니온이다

Identity: [1, (0, 0, 0)] (when involving multiplication) and [0, (0, 0, 0)] (when involving addition) 


오늘날 대부분 지원하는 Direct3D Immediate 모드(retained 모드는 쿼터니온 회전의 제한된 집합을 가진다) 와 OpenGL 의 API는 쿼터니온을 직접적으로 지원하지 않는다. 결과적으로 당신은 이 정보를 당신이 선호하는 API 에 넘기기 위해서 쿼터니온 방향을 변환할 필요가 있다. OpenGL 과 Direct3D 모두 당신에게 회전을 행렬로 지정하는 방법을 제공하며, 쿼터니온에서 행렬로 변환하는 루틴이 유용하다. 또한 당신이 회전을 일련의 쿼터니온으로서 저장하지 않는 (NewTek 의 LightWave 와 같은) 그래픽 패키지로부터 씬 정보를 import 하기를 원한다면, 당신은 쿼터니온 공간으로부터 혹은 공간으로 변환하는 방법을 필요로 하게 될 것이다.

각 과 축. 각과 축 공식으로부터 쿼터니온 공식으로 변환하는 것은 두 개의 삼각형(trigonometric) 연산과 함께 몇몇 곱셈과 나눗셈을 포함한다. 그것은 다음과 같이 표현될 수 있다.

q = [cos(Q/2), sin(Q /2)v] (Q 는 각이며 v는 축이다) 
(Eq. 4) 

오일러 각. 오일러 각을 쿼터니온으로 변환하는 것은 유사한 과정이다 - 당신은 단지 정확한 순서로 연산을 수행하는 데 주의하기만 하면 도니다. 예를 들어 비행 시뮬레이션에서 비행기가 yaw, pitch, roll 순으로 작업을 수행했다고 하자. 당신은 이 결합된 쿼터니온 회전을 다음과 같이 표현할 수 있다


q = qyaw qpitch qroll 에서: 
               qroll = [cos (y/2), (sin(y/2), 0, 0)] 
               qpitch = [cos (q/2), (0, sin(q/2), 0)] 
               qyaw = [cos(f /2), (0, 0, sin(f /2)] 
(Eq. 5) 

곱셈을 수행하는 순서는 중요하다. 쿼터니온 곱셈에는 교환법칙이 성립하지 않는다(벡터 내적을 포함하고 있기 때문이다). 다시 말해 당신이 오브젝트를 다양한 각에 대해서 회전하는 순서를 바꾸게 된다면, 그것은 다른 결과 방향을 생성할 수 있으며, 결국 순서가 매우 중요하다.

회전 행렬. 회전 행렬에서 쿼터니온 표현으로 변환하는 것은 일이 좀 더 많으며, 그것의 구현은 Listing 1 에 나와 있다.

단위 쿼터니온과 회전 행렬 사이의 변환은 다음과 같이 지정될 수 있다.

 


(Eq. 6)

 

쿼터니온을 사용해서 회전을 직접 지정하는 것은 어렵다. 당신의 캐릭터나 오브젝트의 방향을 오일러 각으로 젖아하고 그것을 보간 전에 쿼터니온으로 변환하는 것이 최선이다. 사용자의 입력을 받은 이후에 쿼터니온을 직접 재계산하는 것보다는 오일러 각을 사용해 회전을 각으로 증가시키는 것이 더 쉽다(즉 roll = roll + 1).

 

쿼너티온, 회전 행렬, 오일러 각 사이의 변환은 매우 자주 수행되기 때문에, 변환 과정을 최적화하는 것이 매우 중요하다. 단위 쿼터니온과 행렬 사이의 (9개의 곱셈만을 포함하는) 매우 빠른 변환은 Listing 2 에 나와 있다. 그 코드는 행렬이 오른손 좌표계에 있으며 행렬 회전이 열우선 순으로 표현된다고 가정한다는 데 주의하라(예를 들어 OpenGL 호환).

Listing 1: 행렬에서 쿼터니온으로 변환하는 코드.

MatToQuat(float m[4][4], QUAT * quat)
{
  float  tr, s, q[4];
  int    i, j, k;


  int nxt[3] = {1, 2, 0};


  tr = m[0][0] + m[1][1] + m[2][2];


  // check the diagonal
  if (tr > 0.0) {
    s = sqrt (tr + 1.0);
    quat->w = s / 2.0;
    s = 0.5 / s;
    quat->x = (m[1][2] - m[2][1]) * s;
    quat->y = (m[2][0] - m[0][2]) * s;
    quat->z = (m[0][1] - m[1][0]) * s;
} else {  
  // diagonal is negative
       i = 0;
          if (m[1][1] > m[0][0]) i = 1;
      if (m[2][2] > m[i][i]) i = 2;
            j = nxt[i];
            k = nxt[j];


            s = sqrt ((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
      
      q[i] = s * 0.5;
            
            if (s != 0.0) s = 0.5 / s;


     q[3] = (m[j][k] - m[k][j]) * s;
            q[j] = (m[i][j] + m[j][i]) * s;
            q[k] = (m[i][k] + m[k][i]) * s;


   quat->x = q[0];
   quat->y = q[1];
   quat->z = q[2];
   quat->w = q[3];
  }
}

만약 당신이 단위 쿼터니온을 다루고 있지 않다면, 부가적인 곱셈 및 나눗셈이 요구된다. 오일러 각을 쿼터니온으로 변환하는 것은 Listing 3 에 나와 있다. 게임 프로그래머에 있어서 쿼터니온의 가장 강력한 장점 중 하나는 두 개의 쿼터니온 방향 사이의 보간이 매우 쉬우며 부드러운 애니메이션을 생성할 수 있다는 것이다. 이게 왜 그런지 설명하기 위해서 구체 회전을 사용한 예제를 살펴 보자. 구체 회전 보간은 4 차원에서 최단 경로(arc)인 단위 쿼터니온 구체를 따른다. 4D 구체는 상상하기가 어렵다. 나는 3D 구체(Figure 3)를 사용해 쿼터니온 회전과 보간을 가시화하도록 하겠다.


구체의 중심으로부터 애니메이션되고 있는 벡터의 초기 방향은 q1 에 의해서 표현되고 벡터의 최종 방향은 q3 에 의해서 표현된다고 가정하자. q1 과 q3 사이의 호(arc)는 보간이 따라가는 경로이다. Figure 3 은 우리가 중간 위치인 q2 를 가지고 있다면, q1 -> q2 -> q3 의 보간 경로가 q1 -> q3 보간의 경로와 반드시 같지는 않을 것이다. 초기 및 최종 방향은 같지만 경로는 같지 않다.

쿼터니온은 회전 혼합시에 요구되는 계산을 단순화한다. 예를 들어 당신이 행렬로서 표현되는 두 개 이상의 방향을 가지고 있다면, 두 개의 중간 회전을 곱함으로써 그것들을 쉽게 결합할 수 있다.

R = R2R1 (회전 R1 다음에 회전 R2 가 옴) 
(Eq. 7) 


Listing 2: 쿼터니온을 행렬로 변환. ([07.30.02] 역자 노트 : 다음 QuatToMatrix 함수는 초기에는 버그가 있었다 -- 열과 행의 순서가 바뀌어 있었다. 이것은 교정된 버전이다. 이것을 지적해 준 John Ratcliff 과 Eric Haines 에게 감사한다.)

 

QuatToMatrix(QUAT * quat, float m[4][4]){

float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;


// 계수 계산
x2 = quat->x + quat->x; y2 = quat->y + quat->y; 
z2 = quat->z + quat->z;
xx = quat->x * x2; xy = quat->x * y2; xz = quat->x * z2;
yy = quat->y * y2; yz = quat->y * z2; zz = quat->z * z2;
wx = quat->w * x2; wy = quat->w * y2; wz = quat->w * z2;


m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz;
m[2][0] = xz + wy; m[3][0] = 0.0;

m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz);
m[2][1] = yz - wx; m[3][1] = 0.0;


m[0][2] = xz - wy; m[1][2] = yz + wx;
m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0;


m[0][3] = 0; m[1][3] = 0;
m[2][3] = 0; m[3][3] = 1;

}

 

이 결합(composition)은 27 개의 곱셈과 18 개의 덧셈을 포함하며, 3x3 행렬로 간주한다. 다시 말해 쿼터니온 결합은 다음과 같이 표현될 수 있다.


q = q2q1 (회전 q1 다음에 회전 q2 가 온다) 
(Eq. 8) 

이미 살펴 보았듯이 쿼너티온 기법은 행렬 결합과 유사하다. 그러나 쿼터니온 기법은 단지 8 개의 곱셈과 4 개의 나눗셈만을 요구한다(Listing 4). 그래서 쿼터니온을 결합하는 것은 계산적으로 행렬 결합보다 비용이 싸다. 이러한 비용을 아끼는 것은 계층적 오브젝트 표현과 역운동학에 있어서 특히 중요하다.

 

이제 효율적인 곱하기 루틴을 가지게 되었다. 가장 짧은 호를 따라서 두 쿼터니온 회전을 보간하는 방법에 대해서 살펴 보자. 구형 선형 보간(Spherical Linear intERPolation(SLERP)) 가 이를 수행하며 다음과 같이 작성될 수 있다. 


(Eq. 9)

여기에서 pq = cos(q) 와 인자 t 는 0 부터 1 사이의 값이다. 이 공식의 구현은 Listing 5 에 제출되어 있다. 만약 두 개의 방향이 너무 가깝다면, 당신은 0 으로 나누는 것을 막기 위해서 선형 보간을 사용할 수 있다.


Figure 3. 쿼터니온 회전.

 

Listing 3: 오일러각을 쿼터니온으로 변환.

EulerToQuat(float roll, float pitch, float yaw, QUAT * quat)

{

    float cr, cp, cy, sr, sp, sy, cpcy, spsy;

    // calculate trig identities

    cr = cos(roll/2); cp = cos(pitch/2); 

    cy = cos(yaw/2); sr = sin(roll/2); 

    sp = sin(pitch/2); 

    sy = sin(yaw/2); 

    cpcy = cp * cy; 

    spsy = sp * sy; 

    quat->w = cr * cpcy + sr * spsy; 

    quat->x = sr * cpcy - cr * spsy; 

    quat->y = cr * sp * cy + sr * cp * sy; 

    quat->z = cr * cp * sy - sr * sp * cy;

}

 

기본 SLERP 회전 알고리즘은 Listing 6 에 나와 있다. 당신의 회전 표현이 상대적인 회전이 아니라 절대적인 회전이어야만 함에 주의하라. 상대적 회전은 이전의 (중간) 방향으로부터의 회전이라고 생각할 수 있으며, 절대적 회전은 초기 방향으로부터의 회전이라고 생각할 수 있다. 이것은 당신이 Figure 3 의 q2 쿼터니온방향을 상대 회전으로 생각하면 명확해 진다. 왜냐하면 그것은 q1 방향에 대해 상대적으로 움직였기 때문이다. 주어진 쿼터니온의 절대 회전을 획득하기 위해서는 단지 현재 상대 회전에 이전 상대 회전을 곱하기만 하면 된다. 오브젝트의 초기 방향은 단위 곱 [1, (0, 0, 0)]으로서 표현될 수 있다. 이것은 첫 번째 방향이 항상 절대적인 것임을 의미한다. 왜냐하면 

q = qidentity q 
(Eq. 10) 

이기 때문이다.


Listing 4: 효율적인 쿼터니온 곱.

 

QuatMul(QUAT *q1, QUAT *q2, QUAT *res)

    float A, B, C, D, E, F, G, H; 

    A = (q1->w + q1->x)*(q2->w + q2->x); 

    B = (q1->z - q1->y)*(q2->y - q2->z); 

    C = (q1->w - q1->x)*(q2->y + q2->z); 

    D = (q1->y + q1->z)*(q2->w - q2->x); 

    E = (q1->x + q1->z)*(q2->x + q2->y); 

    F = (q1->x - q1->z)*(q2->x - q2->y); 

    G = (q1->w + q1->y)*(q2->w - q2->z); 

    H = (q1->w - q1->y)*(q2->w + q2->z); 

 

    res->w = B + (-E - F + G + H) /2; 

    res->x = A - (E + F + G + H)/2; 

    res->y = C + (E - F + G - H)/2; 

    res->z = D + (E - F - G + H)/2;

}

 

이전에 언급했듯이 쿼터니온의 실제 용도는 삼인칭 게임에서의 카메라 회전을 포함한다. 나는 TOMB RAIDER 에서의 카메라 구현을 본 이후로 나는 비슷한 것을 구현하기를 원했다. 자 삼인칭 카메라를 구현해 보자(Figure 4).

먼저 항상 캐릭터의 머리 위쪽에 위치하고, 캐릭터의 머리 약간 위쪽을  바라보는 카메라를 생성하자. 또한 그 카메라는 메인 캐릭터의 뒤에서 d 단위만큼 떨어져 있다. 또한 x 축 중심으로 회전함으로써 roll (Figure 4 의 각 q)을 변경하도록 구현할 수도 있다.


플레이어가 캐릭터의 방향을 바꾸면, 당신은 캐릭터를 즉시 회전시키고 SLERP 를 사용해 캐릭터의 뒤에서 카메라의 방향을 재설정한다(Figure 5). 이것은 부드러운 카메라 회전을 제공하고 플레이어로 하여금 게임이 그들의 입력에 즉각 반응하는 것처럼 느끼게 만드는 두 가지 이점을 가지고 있다.


Figure 4. Third-person camera. 


Figure 5. Camera from top.

 

당신은 카메라의 회전 중심(pivot point) 을 그것이 따라 움직이는 오브젝트의 중심으로 설정할 수 있다. 이것은 당신이 캐릭터가 게임 월드 안에서 이동할 때 이미 만들어낸 계산을 이용할 수 있도록 해 준다.

 

1인칭 액션 게임에서는 쿼터니온 보간을 이용하지 말라고 하고 싶다. 왜냐하면 이들 게임은 일반적으로 플레이어의 행동에 대한 즉각적인 반응을 요구하며, SLERP 는 시간을 소비하기 때문이다.


그러나 우리는 그것을 특별한 씬에서 사용할 수 있다. 예를 들어 당신이 탱크 시뮬레이션을 만들고 있다고 하자. 모든 탱크는 scope나 targeting 메커니즘을 가지고 있으며, 당신은 그것을 가능한한 실제적으로 시뮬레이션하고 싶을 것이다. scoping 메커니즘과 탱크의 포신은 플레이어가 제어하는 모터 집합에 의해서 제어된다. scope 의 줌(zoom) 능력과 대상 오브젝트의 거리에 의존해, 모터의 작은 움직임이더라도 가시 각에 있어서는 큰 차이를 보일 수 있으며, 개별 프레임 사이에서 약간 끊기거나 큰 움직임을 보일 수 있다. 이러한 원하지 않는 효과를 제거하기 위해서는 줌과 오브젝트의 거리에 관련한 방향 보간을 수행할 수 있다. 몇 프레임 동안 두 위치 사이를 보간하는 것은 빠른 움직임을 완충하고 플레이어가 방향감각을 상실하지 않게 만들어 준다.

쿼터니온을 사용하는 또다른 유용한 응용프로그램은 이미 기록된 (그러나 렌더링되지 않은) 애니메이션이다. (최근의 많은 게임들처럼) 게임을 플레이해 보면서 카메라의 움직임을 기록하는 대신에 Softimage 3D 나 3D Studio MAX 와 같은 상업 패키지를 사용해 카메라의 움직임이나 회전을 미리 기록할 수 있다. 이것은 공간과 렌더링 시간을 절약해 준다. 그리고 나서 당신은 영화같은 씬을 위한 스크립트 호출이 있을 때마다 키프레임 카메라 모션을 재생하기만 하면 된다.

Listing 5: SLERP 구현. 

QuatSlerp(QUAT * from, QUAT * to, float t, QUAT * res)

{

    float to1[4]; 

    double omega, cosom, sinom, scale0, scale1; 

    // calc cosine 

    cosom = from->x * to->x + from->y * to->y + from->z * to->z + from->w * to->w; 

    // adjust signs 

    (if necessary) 

        if ( cosom <0.0 )

        

            cosom = -cosom; 

            to1[0] = - to->x; 

            to1[1] = - to->y; 

            to1[2] = - to->z; 

            to1[3] = - to->w; 

        }

        else 

        

            to1[0] = to->x; 

            to1[1] = to->y; 

            to1[2] = to->z; 

            to1[3] = to->w; 

        }

        // calculate coefficients

        if ( (1.0 - cosom) > DELTA ) 

        

            // standard case

            (slerp) omega = acos(cosom); 

            sinom = sin(omega); 

            scale0 = sin((1.0 - t) * omega ) / sinom; 

            scale1 = sin(t * omega) / sinom; 

        }

        else

        { 

        // "from" and "to" quaternions are very close

        // ... so we can do a linear interpolation 

        scale0 = 1.0 - t; 

        scale1 = t; 

        }

        // calculate final values 

        res->x = scale0 * from->x + scale1 * to1[0]; 

        res->y = scale0 * from->y + scale1 * to1[1]; 

        res->z = scale0 * from->z + scale1 * to1[2]; 

        res->w = scale0 * from->w + scale1 * to1[3];

}

 

작년에 Chris Hecker 의 물리 관련 칼럼을 읽은 후에, 나는 내가 작업하고 있던 게임 엔진에 각속도(angular velocity)를 추가하고 싶어졌다. Chris 는 주로 행렬 수학에 대해 다뤘는데, 나는 쿼터니온 에서 행렬로 행렬에서 쿼터니온으로 변환하는 것을 줄이고자 했기 때문에(우리 게임엔진은 쿼터니온 수학에 기반하고 있다), 나는 약간을 연구를 통해 쿼터니온 방향을 위한 (벡터로 표현된) 각속도를 추가하는게 쉽다는 것을 발견했다. 그 해결책(Eq. 11)은 다음과 같은 미분방정식으로 표현될 수 있다.

 



(Eq. 11)

 

여기에서 quat(angluar) 는 0 스칼라 부분을 가지고 있는 (즉 w = 0) 쿼터니온이며 벡터 부분은 각속도 벡터와 같다. Q 는 원래 쿼터니온 방향이다.

 

위의 쿼터니온 (Q + dQ / dt) 를 통합하기 위해서, 나는 Runge-Kutta order four method을 사용할 것을 추천한다. 만약 당신이 행렬을 사용하고 있다면, Runge-Kutta order five method을 사용해 더 좋은 결과를 산출할 수 있을 것이다. (Runge-Kutta method 는 특별한 공식을 통합하는 방식이다. 이 기법에 대한 자세한 설명은 Numerical Recipes in C 와 같은 모든 기초 수치 알고리즘 책에서 찾아볼 수 있다. 그것은 수치적, 미분 방정식을 주제로한 세부적인 섹션을 포함하고 있다.) 각속도 통합의 완벽한 유도(derivation)을 원한다면 Dave Baraff 의 SIGGRAPH 튜토리얼을 찾아보기 바란다.

쿼터니온은 회전을 저장하고 수행하기 위한 매우 효율적이며 극단적으로 유용한 기법이다. 그리고 그것들은 다른 메서드들에 비해서 많은 이점을 제공한다. 불운하게도 그것들은 가시화될 수 없으며, 매우 직관적이지 못하다. 그러나 만약 당신이 내부적으로는 쿼터니온을 사용해 회전을 표현하고, 직접 표현으로서 약간의 다른 메서드들(예를 들어 각-축 또는 오일러각) 사용한다면, 당신은 그것들을 가시화할 필요가 없어질 것이다. 


Nick Bobick Caged Entertainment Inc 의 게임 개발자이다. 그리고 그는 현재 멋진 3D game 작업을 하고 있다. 그의 메일은  nb@netcom.ca 이다. 저자는 그의 연구와 출판을 위해서 도움을 줌 Ken Shoemake 에게 감사의 인사를 보내길 원한다 그가 없었다면 이 기사는 불가능했을 것이다. 


반응형

Catmull-Rom 스플라인 곡선은 Edwin Catmull 과Raphael Rom에 의해 개발 되었으며 

통과점만으로부터 매끄러운 곡선을 정의하는 방법중에 하나이다


베지어 곡선은 중간중간의 Point를 지나지 않으며 Point의 영향으로 휘어지는 곡선인 반면 

Catmull-Rom 곡선은 모든 Point를 지나도록 되어있다.


Ferguson / Coons 곡선과 같이 속도를 줄 필요 없이 제어점 만으로 곡선을 결정할수 있으므로 

칼의 궤적같은 형태를 만들거나 할때 자주 쓰인다。






그 밖에 AI 캐릭터가 이동경로를 부드럽게 움직이도록 사용하거나 키프레임들 사이에 부드러운 보간을 얻는데 사용한다




Catmull - Rom 스플라인 곡선의 매개 변수 방정식은 다음과 같으며


 P(t) = 0.5 * ((2.0 * P1) + (-P0 + P2) * t + (2.0 * P0 - 5.0 * P1 + 4.0 * P2 - P3) * t^2 +

         (-P0 + 3.0 * P1 - 3.0 * P2 + P3) * t^3); 


위의 그림처럼 P2와 P3 사이의 곡선을 구하고 싶은 경우 초기위치 마지막위치는 이전과 마찬가지로 P2, P3가 된다



초기속도는 P2의 전후 점인 P1, P3에 의해 결정된다.


이 값은 벡터 P1, P3의 절반이다.


최종속도도 마찬가지로 벡터 P2, P4의 절반이다.


이걸로 초기위치 최종 위치, 및 초기속도 최종속도를 알 수 있으므로

Ferguson / Coons 곡선 처럼 해서 풀수 있다



위 그림의 B와 C의 Catmull-Rom 스플라인 곡선을 구한다.

우선 속도를 구한다.


이것을 위에서 설명한 Catmull- Rom 매개변수 방정식에 대입한다

(위의 식과는 약간 변형된 형태)





가 된다. 이걸로 t를 0부터 1까지 움직이면 BC 간에 곡선을 그린다

실제로 그래프에 그려보면 아래와 같이 된다




현재 DirectX 에서는 아래와 같은 함수를 제공하고있다


 D3DXVec2CatmullRom(D3DXVECTOR2* pOut,
                   CONST D3DXVECTOR2* pV1,
                   CONST D3DXVECTOR2* pV2,
                   CONST D3DXVECTOR2* pV3,
                   CONST D3DXVECTOR2* pV4,
                   FLOAT s)

D3DXVec3CatmullRom(D3DXVECTOR3* pOut,
                   CONST D3DXVECTOR3* pV1,
                   CONST D3DXVECTOR3* pV2,
                   CONST D3DXVECTOR3* pV3,
                   CONST D3DXVECTOR3* pV4,
                   FLOAT s)

D3DXVec4CatmullRom(D3DXVECTOR4* pOut,
                   CONST D3DXVECTOR4* pV1,
                   CONST D3DXVECTOR4* pV2,
                   CONST D3DXVECTOR4* pV3,
                   CONST D3DXVECTOR4* pV4,
                   FLOAT s)


위 함수들은 각각 4개의 점과 0~1사이의 하나의 가중치 값(s)을 받으며

pOut에 보간 된 벡터를 반환한다


만약 s 가 0이면 pv2를 리턴하게 되며 1일 경우 pv3를 리턴하게 된다


그외에도 다양한 보간법들이 있을 것이다..


예를들면.. Bicubic 이라던지...


http://en.wikipedia.org/wiki/Bicubic_interpolation

http://scosco.com.ne.kr/Stereo3DHtml/vr_0002_bicubic.htm


http://cafe.naver.com/devrookie/6085

출처블로그>Vanica's Lifelog - 夢が夢で終わらないように | 풍풍풍

원문http://blog.naver.com/sorkelf/40154552485



반응형

분리축 SAT 충돌처리



obb 충돌처리.pdf

반응형


http://www.gingaminga.com/Data/Note/oriented_bounding_boxes/


Object Oriented Bounding Box  이용한 Collision Detection

96419-044

원선

출처; http://mimosa.snu.ac.kr/~rabbit2/

 

<목차>

  1. 소개글
  2. 이론
  3. 코드 다운로드  사용법
  4. 참고 문헌
  5. 웹페이지 다운로드

 

1. 소개글

지금까지 리서치 주제로 BSP tree 라던지 bounding sphere에 의한 collision detection(이하 CD)은 많이 있었는데그에 비해 bounding box에 의한 CD에 대한 글은 없었던 것 같다물론, bounding sphere에 의한 CD의 쓰임새도 많지만(예를 들어 당구공에 의한 CD라던지), 생각해 보면 우리 주위에 있는 물체 중에서 둥근 것보다는 네모난 것이 훨씬 더 많다는 것을 알 수 있다만일 직육면체에 가까운 물체를 bounding sphere로 모델링하게 되면밑에 그림에서 볼 수 있듯이 많은 공간이 남게 되고이 공간을 줄이기 위해서는 depth가 여러 레벨인 sphere tree를 구성할 수 밖에 없다그럼에도 불구하고 bounding sphere가 널리 이용되는 가장 큰 이유는, bounding sphere가 구현하기가 가장 쉽기 때문인 것 같다. Bounding sphere로 일단 모델링하고 나면 CD를 하기 위해서 단순히 두 구 사이의 거리를 측정해서 각 구의 반지름의 합과 비교하기만 하면 된다.
Bounding box
에 의한 모델링은 axis-aligned bounding box(이하 AABB) object-oriented bounding box(이하 OBB) 두 가지 방법이 있다. AABB bounding box를 잡을 때 항상 world coordinate system 3개의 축과 평행한 방향으로만 잡는 것이고이것은 bounding sphere와 마찬가지로 구현하기는 매우 쉬우나역시 물체가 world coordinate system 축과 다른 방향으로 놓이게 되면 많은 빈공간이 생기게 되어 효율이 급격하게 떨어지게 된다당연히 직육면체 모양의 물체를 가장 효율적으로 모델링하기 위해서는 그 물체가 놓여 있는 방향으로 bounding box를 잡는 것인데이것이 바로 OBB이다하지만 OBB는 구현하기가 비교적 난해하므로 지금까지 리서치가 안 되었었던 것 같은데필자는 최대한 잘 설명하려고 노력하겠다 -_-;;;

<bounding sphere>

직육면체의 물체를 모델링하기 위해서는 여러 개의 구가 필요하고구에빈공간이 생겨서 정확히 모델링이 되지 않는다.

 

 

<axis-aligned bounding box>

물체가 world coordinate axis와 다른 방향으로 놓여 있을 때 효율이 급격하게 떨어진다.

 

 

<object-oriented bounding box>

물체의 방향을 중심으로 bounding box를 잡기 때문에직육면체 모양의 물체를 가장 효율적으로 모델링할 수 있다.

anigray09_up.gif 위로

2. 이론

Mesh를 생성할 때 bounding box도 같이 생성하여, mesh transform 할 때 bounding box도 같이 transform을 해 주면 항상 모든 mesh에 대해 OBB를 유지할 수가 있다그렇다면 우리는 이제 mesh가 움직이면서 같이 돌아댕기는 여럿의 OBB를 갖고 있다이 때, OBB가 서로 충돌했는지는 어떻게 감지할 수가 있을까가장 무식한 방법은 두 개의 OBB의 모든 면과 모든 edge에 대해서 면을 통과하는 edge가 있는지 검사하는 방식일 것이다그런데 이 방식은 144번의 비교가 필요하고상당히 비싼 테스트이다여기서는 훨씬 더 효율적인 'axial projection'을 이용한 테스트를 소개한다.

Axial projection 이란 무엇인가?

두 개의 OBB가 서로 분리되어 있는지를 알기 위한 쉬운 방법 중 하나는 OBB를 공간상의 어떤 축(반드시 x,y,z축일 필요는 없다)에 투영하는 것이다이 투영을 'axial projection'이라고 하며이 투영을 통해 각 OBB는 축 상에 어떤 interval을 형성한다.만일 이렇게 형성된 2개의 interval이 서로 겹치지 않으면 2개의 OBB는 서로 분리되어 있는 것이 확실하며이때 이 축을 'separating axis'라고 한다만일 2개의 interval이 서로 겹친다면 2개의 OBB는 서로 분리되어 있을 수도 있고 아닐 수도 있기 때문에 더 많은 검사가 필요하다.

2개의 OBB가 충돌했는지 알기 위해서는 axial projection을 몇 번 해야 하는가?

(공리)
공간상의 2개의 분리된 convex한 다각면체는 1) 두 개의 다각면체 중 하나의 어느 면과 평행인 면또는 2) 두 개의 다각면체 각각에서 하나의 edge와 평행한 면에 의해 분리될 수 있다.

이 공리를 증명한 논문도 있긴 하지만그것은 관심있는 분은 찾아 보시고어쨌든 이 공리의 결과로서우리는 다음을 알 수 있다:
공간상의 2개의 convex한 다각면체가 분리되기 위한 필요충분 조건은, 1) 두 개의 다각면체 중 하나의 어느 면과 수직인 separating axis가 존재하거나, 2) 두 개의 다각면체 각각에서 하나의 edge와 수직인 separating axis가 존재하는 것이다.

 OBB 3개의 unique한 면 방향이 있고, 3개의 unique edge 방향이 있다따라서 위의 조건을 검사하기 위해서는 15개의 separating axis를 검사해야 한다.

(하나의 OBB에서 3개의 면다른 OBB에서 3개의 면, 9개의 2개의 OBB에서 edge들의 조합

(상자  A 의 축들에 대해서 3개, 상자 B 축들에 대해서 3개, 그리고 A 에서 한축 그리고 B 에서 하나를 사용하여 9개의 외적들을 만든것이 총 15개) : [Gottschalk , SIGRAPH 에 실린 내용]

만일 2개의 OBB가 서로 분리되어 있다면(충돌하지 않았다면) separating axis가 반드시 존재해야 하고 위에서 언급한 15개의 axis 중 하나가 그 axis가 되어야 한다만일 OBB들이 충돌했다면 separating axis가 존재하지를 않을 것이다따라서, 2개의 OBB의 충돌 여부를 검사하기 위해서는 15개의 seperating axis의 검사로 충분하다.

Separating axis 검사는 어떤 방식으로 할 수가 있는가?

이 검사를 하는 기본적인 전략은 다음과 같다:
1) 
 OBB의 중심을 해당 axis에 투영한다.
2) 
 OBB가 해당 axis에 투영되었을 interval radius(길이의 반)을 계산한다.
3) 
만일 해당 axis에 투영했을 때 OBB의 중심 사이의 거리가 각 OBB interval radius의 합보다 크면두 개의 OBB는 분리된 것으로 볼 수 있다.

밑에 있는 그림을 보면 이해가 더 쉽게 갈 것이다그림에서 A B는 각각 OBB이고 B A로부터 rotation R translation T만큼 이동한 위치에 있다. A B half dimension(또는 radius) 는 각각 ai, bi로 표기한다(i=1,2,3). A B에서 각 edge와 평행을 이루는 axis의 단위 벡터를 각각 Ai Bi라고 표기한다(i=1,2,3). 이렇게 해서 생긴 6개의 단위 벡터를 box axis라고 하자여기서 주목할 것은 A box axis basis로 사용하면회전 매트릭스 R 3개의 column(x,y,z 단위벡터를 transform 했을 때 나오는 벡터) 3개의 Bi axis 벡터와 같다는 사실이다.





<여기서 A B L에 투영하면 서로 분리된 interval이 되므로 L OBB A B에 대한 separating axis이다.>

보다시피 각 OBB의 중심은 투영된 interval의 중간에 투영된다 box radius axis L에 투영하고 투영된 길이의 합을 구함으로써 우리는 각 OBB의 투영된 interval을 구할 수가 있다위에서 OBB A interval radius는 다음과 같다:



OBB B에 대해서도 비슷한 식을 세울 수가 있다. Seperating axis의 위치는 검사에 아무런 영향을 끼치지 않으므로 우리는 axis가 A의 중심을 통과한다고 가정한다. 이 때, 2개의 interval 사이의 거리는   가 된다(그림 참고). 따라서, 2개의 interval 분리되어 있기 위한 필요충분 조건은 다음과 같다:



이 식은 액면으로는 복잡하지만, 15개의 separating axis에 적용하게 되면 L이 box axis이거나 box axis의 cross product가 되기 때문에 많이 단순화 된다. 예를 들어, 이라고 하자. 



위의 식에서 첫 번째 summation의 두 번째 항은 다음과 같이 단순화 된다.




마지막 단계는 전에 언급했듯이 B의 box axis는 A에 대한 B의 rotation matrix R의 column에 해당한다는 사실을 이용한 것이다. 이런 식으로 모든 항들은 단순화되고 때로는 값이 0이 되어 없어지기도 한다. 이렇게 단순화한 이후의 위의 seperating axis L에 대한 검사는 다음과 같이 된다:





모든 15개의 seperating axis에 대한 검사는 이런 방식으로 단순화되며, 이 검사의 과정에서 matrix R의 각 항은 4번씩 사용이 되므로 모든 검사를 시작하기 전에 matrix R을 미리 계산해 놓는다. 만일 이 검사 도중 식이 만족이 되면, seperating axis를 발견한 것이고, 그렇다면 2개의 OBB는 서로 분리되어 있음을 밝힌 것이 되기 때문에 나머지 검사는 할 필요가 없어진다. 아래의 표는 15개의 seperating axis에 대한 식을 정리한 것이다:






여기서 R0 항목은 OBB A interval radius, R1 항목은 OBB B interval radius, R 항목은 2개의 OBB의 중심 간의 투영된 거리를 나타낸다.
* D 
벡터는 2개의 OBB의 중심을 잇는 벡터를 나타낸다.
Cij 
 rotation matrix R에서의 (i,j항을 나타낸다.

anigray09_up.gif 위로

3. 코드 다운로드 및 사용법

aniapple_red.gif코드 다운로드

aniberry02_red.gif실행파일(exe) 다운로드

<실행방법>
 
그냥 가만히 실행시키고 기다리고 있으면 차가 건물에 가서 쿵.. 하고 박는다 -_- 화살표로 시점을 약간 변화시킬 수 있다.

<코드설명>
circle01_black.gifCBox 
클래스

CBox

Object oriented bounding box를 표현하는 클래스

CBox::center[3]

Bounding box의 중심 좌표

CBox::axis[3][3]

Bounding box 3 방향으로의 axis 벡터

CBox::extent[3]

Bounding box의 각 axis 벡터 방향으로의 radius

circle01_black.gifint BoxBoxIntersectionTest(const CBox& box0,const CBox& box1)
box0 
 box1이 서로 교차하는지 검사를 해서 교차를 하면 1, 그렇지 않으면 0을 리턴한다함수의 동작방식은 위의 표에 있는 15개의 seperating axis를 하나씩 검사하는 방식이다주석을 보고 표를 참고하면 이해하는데 아무런 어려움이 없을 것이다.

circle01_black.gifD3DXMATRIX* GetBoxTransform(D3DXMATRIX *pMatCBoxpBox)
pBox
 transform D3DXMATRIX 형태로 변환시켜 주는 일종의 wrapper 함수이다.

circle01_black.gifvoid SetBoxTransform(const D3DXMATRIX* pMatCBoxpBox)
위 함수와 쌍을 이루는이번에는 pMat transform pBox axis 벡터로 변환을 해 주는 함수이다.

circle01_black.gifvoid initBox(CBox *pBox, const D3DXVECTOR3& vecMin, const D3DXVECTOR3& vecMax)
Mesh
로부터 구해 온 bounding box minimum 좌표, maximum 좌표를 받아서 pBox center extent를 계산하고 axis를 초기화한다.

circle01_black.gifvoid moveBox(CBox *pBox, const D3DXMATRIX& mat)
pBox
 mat에 의해 움직인다일단 3개의 axis들을 변환한 이후에 center를 변화하는 방식으로 되어 있다.

circle01_black.gif이 함수들을 이용해서 코드는 다음 순서로 동작하면 된다:

  1. Mesh를 로드 한 후에 D3DXComputeBoundingBox를 이용하여 bounding box를 계산한다.
  2. Bounding box로부터 얻은 값을 이용하여 initBox CBox 객체를 초기화한다.
  3. 이후에 문제가 움직일 때마다 변환 matrix를 인자로 moveBox를 호출해 CBox 객체를 갱신해 준다.
  4. 움직일 때마다 그 CBox와 다른 CBox들이 충돌이 일어났는지 BoxBoxIntersectionTest로 검사한다.

anigray09_up.gif 위로

4. 참고 문헌

5. 웹페이지 다운로드

aniberry01_red.gif웹페이지 전체 다운로드

anigray09_up.gif 위로



반응형

http://irrlicht.sourceforge.net/forum//viewtopic.php?t=43873#p250538


Simple cloud layer SceneNode

Postby tbw » Mon May 16, 2011 6:50 pm

I want to share a litte experiment with you.
I needed a shifting cloud layer in my scene and decided to encapsulate it in a scene node. Here is the result (source code and example link at the bottom of the post)




The CloudSceneNode is a dome that is spanned between the skybox and the scene




The interface of the SceneNode offers access to the geometry and the color of the SceneNode
  // returns the inner radius
                virtual f32 getInnerRadius() { return InnerRadius; }
                // returns the outer radius
                virtual f32 getOuterRadius() { return OuterRadius; }
                
                // returns the center height
                virtual f32 getCenterHeight() { return CenterHeight; }
                // returns the inner height
                virtual f32 getInnerHeight() { return InnerHeight; }
                // returns the outer height
                virtual f32 getOuterHeight() { return OuterHeight; }
 
                // returns the center color
                virtual video::SColor& getCenterColor() { return CenterColor; }
                // returns the inner color
                virtual video::SColor& getInnerColor() { return InnerColor; }
                // returns the outer color
                virtual video::SColor& getOuterColor() { return OuterColor; }
                
                // sets the cloud radius
                virtual void setCloudRadius(
                        f32 innerRadius, 
                        f32 outerRadius);
                
                // sets the cloud height
                virtual void setCloudHeight(
                        f32 centerHeight, 
                        f32 innerHeight, 
                        f32 outerHeight);
 
                // sets the cloud colors
                virtual void setCloudColor(
                        const video::SColor& centerColor = video::SColor(220,220,220,220), 
                        const video::SColor& innerColor = video::SColor(180,180,180,180),
                        const video::SColor& outerColor = video::SColor(0,0,0,0));


The integration into the scene is done as usual:
  // add 1st cloud layer
        cloudLayer1 = new scene::CCloudSceneNode(smgr->getRootSceneNode(), smgr);
        // set translation (speed of the clouds)
        cloudLayer1->setTranslation(core::vector2d<f32>(0.008f, 0.0f));
        cloudLayer1->getMaterial(0).setTexture(0, driver->getTexture("media/clouds/cloud01.png"));
        // set the geometry     
        cloudLayer1->setCloudHeight(0.5f, 0.1f, -0.05f);

For further details please have a look into the source code.
Here is a small example with the source included (build with a 1.8 svn irrlicht version) with three cloudlayers. You can turn them on or off by pressing the keys 1, 2 or 3.

http://www.van-helsing-band.de/irrlicht ... nenode.zip

I hope you like it
Last edited by tbw on Fri Jan 13, 2012 7:35 pm, edited 2 times in total.
tbw
 
Posts: 58
Joined: Sat Jan 15, 2011 9:51 am
Location: Germany

Postby Virror » Mon May 16, 2011 7:38 pm

One word: AMAZING! 
Looks so good i think i will cry : p 
Btw, is this free to use?
Virror
 
Posts: 191
Joined: Mon May 02, 2011 3:15 pm

Postby Luben » Mon May 16, 2011 7:42 pm

It looks very good, thanks for sharing :)
If you don't have anything nice to say, don't say anything at all.
User avatar
Luben
 
Posts: 568
Joined: Sun Oct 09, 2005 10:12 am
Location: #irrlicht @freenode

Postby tbw » Mon May 16, 2011 8:05 pm

Sorry I forgot: license is zlib. So have fun with it! :D
tbw
 
Posts: 58
Joined: Sat Jan 15, 2011 9:51 am
Location: Germany

Postby Virror » Mon May 16, 2011 8:07 pm

Then i will try it out in my game right now : )
Virror
 
Posts: 191
Joined: Mon May 02, 2011 3:15 pm

Postby shadowslair » Mon May 16, 2011 8:32 pm

Looks good. Thanks. :wink:
Image
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
User avatar
shadowslair
 
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

awesome

Postby tecan » Tue May 17, 2011 5:06 am

amazing demo, thanks much!
Live long and phosphor! 
--Luna - Status 60%
User avatar
tecan
 
Posts: 277
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada

Postby hendu » Tue May 17, 2011 7:14 am

That looks excellent :D 

Note it doesn't build as-is: 
In file included from CloudSceneNode.cpp:20:
CloudSceneNode.h:132:7: warning: no newline at end of file
In file included from main.cpp:7:
CloudSceneNode.h:132:7: warning: no newline at end of file
main.cpp: In function 'int main()':
main.cpp:91: error: no matching function for call to 'irr::scene::CCloudSceneNode::setTranslation(irr::core::vector2d<float>)'
CloudSceneNode.h:85: note: candidates are: virtual void irr::scene::CCloudSceneNode::setTranslation(irr::core::vector2d<float>&)
main.cpp:97: error: no matching function for call to 'irr::scene::CCloudSceneNode::setTranslation(irr::core::vector2d<float>)'
CloudSceneNode.h:85: note: candidates are: virtual void irr::scene::CCloudSceneNode::setTranslation(irr::core::vector2d<float>&)
main.cpp:104: error: no matching function for call to 'irr::scene::CCloudSceneNode::setTranslation(irr::core::vector2d<float>)'
CloudSceneNode.h:85: note: candidates are: virtual void irr::scene::CCloudSceneNode::setTranslation(irr::core::vector2d<float>&)


And the skybox isn't loaded, as they are named .PNG, while you call .png. 

But after fixing those, it does look very nice ;) 


(WTF is VC++ doing with a 650kb exe, it's 46kb here :P)
hendu
 
Posts: 1414
Joined: Sat Dec 18, 2010 12:53 pm

Postby tbw » Tue May 17, 2011 8:20 am

Thank you for the hint! 
As you mentioned I compiled the code on a windows machine with visual studio 2008. The compiler doesn't care about the newline at the end of the header files and the file extension is resolved correctly, but only on windows. 
Looks like I've been a little bit lazy :oops: 

So I will fix the code and reupload the sample! 

EDIT: 

Fixed the issues and updated the download
Last edited by tbw on Tue May 17, 2011 6:28 pm, edited 1 time in total.
tbw
 
Posts: 58
Joined: Sat Jan 15, 2011 9:51 am
Location: Germany

Postby REDDemon » Tue May 17, 2011 8:24 am

Very good work. I will add it immediatly to the snippets folder.
OpenGL is not hard. What you have to do is just explained in specifications. What is hard is dealing with poor OpenGL implementations.
User avatar
REDDemon
 
Posts: 827
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Postby Buck1000 » Tue May 17, 2011 1:49 pm

That looked AWESOME. Good job :D 

Is there any way you could randomly generate the cloud layer textures at runtime?
User avatar
Buck1000
 
Posts: 93
Joined: Sun Dec 14, 2008 8:02 pm
Location: Seattle, WA

Postby Murloc992 » Tue May 17, 2011 3:18 pm

Buck1000 wrote:That looked AWESOME. Good job :D 

Is there any way you could randomly generate the cloud layer textures at runtime?

LibNoise is there to do exactly what you want. :P
User avatar
Murloc992
 
Posts: 272
Joined: Mon Apr 13, 2009 2:45 pm
Location: Utena,Lithuania

Postby greenya » Tue May 17, 2011 3:50 pm

Just wow! 
This looks really really good :!:
User avatar
greenya
 
Posts: 886
Joined: Sun Jan 21, 2007 1:46 pm
Location: Ukraine

Postby serengeor » Tue May 17, 2011 4:01 pm

I was watching this thread for a few days and after all those replies I got tempted to try it out. 
Simply astonishing :wink: 
This could make many games look more pretty/dynamic :)
Working on game: Marrbles (Currently stopped).
User avatar
serengeor
 
Posts: 1676
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Postby Tannz0rz » Tue May 17, 2011 11:27 pm

How nice! Runs quite fluently, might I add.

반응형





-1< ( (2-(8*c^2*t^2)/d^2 +u*t ) )/(u*t+2) <1, t>0 , c>0 , d > 0 for t




BLOG main image




반응형
BLOG main image



d^2 으로 계산하나 2*d^2 으로 계산하나 결과는 유사한데


 2*d^2 의 파동이 좀 더 빨리 줄어들게된다


....



float v=D3DXVec2Length(&_waveInfo._velocity);

float dragF=dampingForce;

float ut=dragF*_waveInfo._curTime;

float dd=distance*distance;

float tt=time*time;


float denominator = (ut+2.0f);




.......


//#define _DD 1


#if _DD

//d^2

maxVelocity=(_waveInfo._distance/(2.0f*_waveInfo._curTime))*sqrt(denominator) ;

if( v >= maxVelocity)

v=maxVelocity-0.01;

#else

//2d^2

maxVelocity=sqrt( (2.0f*dd*ut+2)/tt )/2.0f;

if( v >= maxVelocity)

v=maxVelocity-0.01;

#endif

vv=v*v;

float c1=0.0f;

float c2=0.0f;

float c3=0.0f;


#if _DD

//d^2

c1= (4.0f - 8.0f*vv*tt/dd)/denominator;

c3= (2.0f*vv*tt/dd)/denominator;

#else

//2d^2

c1= (4.0f - 8.0f*vv*tt/(2.0f*dd))/denominator;

c3= (2.0f*vv*tt/(2.0f*dd))/denominator;

#endif


c2= (ut-2.0f)/denominator;




.....





#if _DD

//d^2

maxTime= (dragF +sqrt( dragdragF + 32.0f*vv/dd  ) )/(8.0f*vv/dd);

#else

//2d^2

maxTime= (vv*sqrt(dd*(16.0f*vv+dd*dragdragF)/(vv*vv)) + dd*dragF)/(4.0f*vv);


#endif

if( maxTime> _waveInfo._curTime+tick )

_waveInfo._curTime+=tick;




반응형

BLOG main image




2*d^2 에 대해서 푼 경계식



t에 대해서


-1< ( (2-(8*c^2*t^2)/(2*d^2) +u*t ) )/(u*t+2) <1, t>0 , c>0 , d > 0 for t










c에 대해서



-1<  (2-8*c^2*t^2/(2*d^2) + u*t)/(u*t+2)  < 1 , u>0 , t>0 , c>0 , d > 0 for c






반응형


http://goo.gl/WmouU


베셀의 미분방정식(Bessel's differential equation)


[경고] 아래 글을 읽지 않고 "베셀 미분방정식"을 보면 바보로 느껴질 수 있습니다.
1. 스투름-리우빌 이론
2. 프로베니우스 방법의 적용
3. 천장에 매달린 사슬의 운동방정식


베셀(Friedrich Wilhelm Bessel)이 일반화 시킨 다음 미분방정식을 베셀의 미분방정식(Bessel's differential equation)이라 한다.

                      (1)

                      (2)

재미있는 것은 베셀의 대학원 지도교수가 가우스(Carl Friedrich Gauss)란 것이다. 우리를 힘들게 하는 베셀 함수(Bessel function)를 만든 베셀이지만 대학원 시절에는 깐깐한 지도교수 밑에서 고생을 겁나게 했으리라...
천장에 매단 사슬(hanging chain)의 움직임[3]을 연구하던 베르누이(Daniel Bernoulli)가 1732년에 처음으로 제안하고(베르누이가 제안한 것은 식 (11)에 있는 0차 제1종 베셀 함수) 베셀이 1824년에 일반화시킨 유명한 베셀 함수는 식 (1)이나 (2)의 해로 정의한다[2]. 당연한 말이지만 베셀 함수의 대부분 성질은 식 (1)이나 (2)를 통해 증명할 수 있다.
식 (1)의 베셀 미분방정식은 다음과 같은 프로베니우스 방법을 위한 미분방정식 관점으로 풀 수 있다.

                      (3)

여기서 p(x), q(x)는 발산하지 않는다. 식 (1)과 (3)을 비교하면 p(x) = 1, q(x) = x^2 - n^2이 되어 발산하지 않는다. 식 (4)에 있는 지표방정식(indicial equation)을 이용하면 지표값 r은 다음처럼 결정된다.

                      (4)

                      (5)

[그림 1] 제1종 베셀 함수(출처: wikipedia.org)

r1 = n이라 정하면 베셀 미분방정식의 첫번째 해는 다음식으로 구할 수 있다.

                      (6)

          (7)

식 (7)에 r1 = n을 대입하면 다음 재귀관계(recursion relation)을 얻을 수 있다.

     (8)

그러면 식 (8)의 마지막식을 식 (6)에 대입해 첫번째 해를 구할 수 있다.

            (9)

여기서 !는 계승(階乘, factorial)을 의미한다.
식 (9)와 같은 첫번째 해는 식 (10)처럼 표기하고 제1종 베셀 함수(Bessel function of the first kind)라 부른다. 다음 조건처럼 a0를 정하자. (∵ a0는 임의이므로 아무값이나 넣을 수 있는데 식 (9)를 간단하게 표기할 수 있는 방식으로 a0를 정하자.)

                      (10)

식 (10)의 정의를 식 (9)에 대입하면 제1종 베셀 함수를 완전히 얻을 수 있다.

                      (11)

식 (10)의 정의로 인해 제1종 베셀 함수는 간편하게 표기할 수 있다.

미분방정식 (1)에서 n이 정수가 아닌 실수라면 보통 ν로 표기한다. 계승의 일반화인 감마 함수(gamma function)를 이용하면 식 (11)을 일반화할 수 있다.

                      (12)

                      (13)

식 (13)을 식 (11)에 대입하면 일반화된 제1종 베셀 함수를 정의할 수 있다.

                      (14)

프로베니우스 방법에서 r2 = -n을 대입하면 두번째 해를 얻을 수도 있다. 하지만, 다음 베셀 함수 관계로 인해 첫번째 해와 종속되어버린다. 아래식의 증명은 [여기]에서 볼 수 있다.

                      (15)

하지만, n이 정수가 아니면 J_ν(x) J_(-ν)(x)는 서로 독립적인 관계가 된다. (∵ 식 (14)의 분모에 있는 감마 함수가 무한대가 되는 경우가 생기지 않는다.) 즉, J_(-ν)(x)가 두번째 해가 된다.

[그림 2] 제2종 베셀 함수(출처: wikipedia.org)

식 (15)를 바탕으로 제2종 베셀 함수(Bessel function of the second kind)를 정의해보자[1].

                      (16)

제2종 베셀 함수는 노이만 함수(Neumann function)라고도 한다. J_ν(x) J_(-ν)(x)는 서로 독립이기 때문에 ν ≠ n인 경우 타당한 두번째 해가 된다. 물론 프로베니우스 방법을 이용해 두번째 해를 다음처럼 구할 수도 있다.

                      (17)

하지만, 상미분방정식 해의 존재성과 유일성이 있는데 굳이 식 (17)처럼 어려운 길을 갈 필요는 없다. 2차 상미분방정식의 독립적인 해는 두가지이므로 식 (14)와 (16)의 선형결합으로 식 (17)이 표현된다.
식 (16)처럼 제2종 베셀 함수를 지저분하게 정의하는 이유는 ν = n인 경우에도 써먹기 위해서다. 식 (16)에 극한(limit)을 취하면 정수차수(integer order) 제2종 베셀 함수를 정의할 수 있다[1].

                      (18)

그러면 식 (15)에 의해 식 (18)의 분자와 분모가 0이 되어서 함수값이 존재하게 된다. 로피탈의 정리(L'Hôpital's rule)를 써서 식 (18)을 계산하자.

                      (19)

식 (19)를 계산하기 위해 식 (14)에 있는 베셀 함수를 차수에 대해 미분해보자.

      (20)
여기서 ψ(·)다이감마 함수(digamma function)이다.
식 (20)의 결과를 식 (19)에 대입하자.


                                                                                                    (21)

기가 막힌 방법으로 식 (21)을 얻었지만 식 (21)에는 다소 문제가 있다. m ≤ n-1인 경우 (m-n)!ψ(m-n+1)이 발산하기 때문에 대책이 필요하다. (∵ ψ(m-n+1)이 발산하는 것은 식 (24)를 봐도 자명하다.) 이 문제를 해결하려면 식 (22)에 있는 오일러의 반사공식(Euler's reflection formula)을 이용해야 한다[1].

                      (22)

또한, 식 (21)에서 발산하여 문제가 되는 부분은 다음처럼 바꾼다.

                      (23)

식 (23)의 우변에 식 (22)를 대입하여 미분하면 다음을 얻을 수 있다.

                      (24)

식 (24)를 이용하면 식 (21)에 나오는 무한급수(infinite series)를 단순화시킬 수 있다.

  (25)

그러면 정수차수 제2종 베셀 함수를 아래처럼 표현할 수 있다.

        (26)

참 먼 길을 달려왔다. 식 (26)의 정수차수 제2종 베셀 함수를 유도하는 것은 쉬운 일이 아니다. 오죽 힘들면 약 120년전에 나온 수학논문지[1]에 위 과정이 실렸겠는가! 그래서, 대부분의 공학수학책에는 이 증명을 소개하지 않는다. 위의 유도과정없이 식 (26)을 보면 마법이다. 우리가 근접할 수 없는 무언가를 가지고 있는 것 같다. 하지만, 식 (18)부터 (26)까지 따라가 보면 그냥 수학적 과정을 이어나가서 결과를 얻고 있다.

위의 정의 (14), (16)과는 다르게 식 (1)의 해를 구할 수도 있다. 식 (14)와 (16)을 복소수(complex number)를 이용해 연결하면 다음과 같은 한켈 함수(Hankel function)가 된다.

                      (27)

[참고문헌]
[1] M. Bocher, "On Bessel's functions of the second kind," Ann. Math., vol. 6, no. 4, pp. 85-90, Jan. 1892.
[2] G. N. Watson, A Treatise on the Theory of Bessel Functions, Cambridge University Press, 2nd ed., 1944.
[3] C. Byrne, Notes on Bessel's Equation and the Gamma Function, University of Massachusetts Lowell, April 2009.

[다음 읽을거리]
1. 베셀 함수
2. 베셀 함수의 점근식

반응형


BLOG main image   

http://3dmpengines.tistory.com






 왼손(DX)의 경우  V*A(=행기준 행렬)=V'




이러한 순서가 되며





오른손 (Opengl)의 경우는  A(=열기준 행렬)*V=V'





의 순서가 됩니다


이해하기 쉬우려면  벡터 V 에 대한 좌표변환(회전 또는 위치) 의 각 성분들 중 공통인것끼리만 벡터 V와 곱하면 되는데



왼손의 경우 V가 행렬 A에 의해 변환된다고 할때 =V'의 x 성분은 


각 A축의 x성분, B축의 x성분 C축의 x성분 그리고 pos위치의 x 성분과 각 값을 곱하면 그것이 V'의 x성분이 됩니다


Vx*Ax + Vy*Bx + Vz*Cx + 1*posx = V'x

나머지 V'y, V'z, V'w 성분도 동일합니다



오른손도 마찬가지입니다





그런데 카메라 행렬에서는 이것이 방법과는 약간 미묘한 차이를 보입니다


즉 이동부분과 회전부분에 대해서 각가 다른것을 볼 수 있는데요


회전부분은 월드 위치를 반대로 회전시켜야 하기때문에 A의 회전부분 3x3 부분이 전치가 되어있는 것이고


이동또한 카메라에서 월드세계를 볼때 월드세계의 오브젝트(정점)들이 반대로 이동되게 되면 현실세계에서의


카메라 이동과 동일함으로 이동부분에 - 가 붙게 됩니다




카메라의 경우는 그렇다 치고 일반적인 월드공간 변환과 유사하게


정규직교기저인 벡터 3개만 있다면? 


그렇슴돠~~!!!! 자신이 원하는 공간으로 변환할 수 있게 되는 것이죠!!!




p.s 기초적인것이지만 이 활용도는 생각외로 큽니다




반응형

http://blog.naver.com/oranke?Redirect=Log&logNo=40000788158  에서 일부 내용을 추려옵니다



뷰변환 행렬에 대해 살펴보기 전에 짚고 넘어가야 할 문제가 있습니다. OpenGL과 D3D를 말할 때 가장 큰 차이점으로 오른손 좌표계냐 왼 손 좌표계냐를 따집니다. 그리고 또 하나 얘기하는 것이 바로 행기준 행렬이냐 열기준 행렬이냐는 것이죠...

 

 좌표계 문제는 Z좌표를 뒤집기만 하면 끝납니다. 앞에서 살펴봤던 회전행렬 역시 오른손 좌표계가 오른손 법칙으로 양의 방향을 규정하는 것 처럼 왼손 좌표계는 왼손이 감기는 방향을 양의 방향으로 하기 때문에 회전행렬을 그대로 쓸 수 있습니다. 양의 방향에 해당하는 좌표평면과 축을 2차원에 설정해 그려보면 금방 알 수 있습죠...






OpenGL에서 사용하는 열기준 행렬과 D3D의 행기준 행렬이란 녀석들은 확실하게 그 차이를 이해해 두지 않으면 두고 두고 뒤통수를 맞게 됩니다. 

 참고로 양키들은 행기준 행렬(Row major matrix) 의 곱셈을 프리멀티플리케이션(Pre-multiplication), 열기준 행렬(Column major matrix) 의 곱셈을 포스트멀티플리케이션(Post-multiplication) 이라고 구분해서 쓰더군요.

 

 아무튼 우리가 일반적으로 사용하는 행기준 행렬은 아래처럼 정의되고,

 

  A(Row) = | a00 a01 a02 a03 |
           | a04 a05 a06 a07 |
           | a08 a09 a10 a11 |
           | a12 a13 a14 a15 |

 

 OpenGL 레퍼런스에 따르면 열기준 행렬은 다음과 같이 생겨먹었습니다.

 

  A(Col) = | a00 a04 a08 a12 |
           | a01 a05 a09 a13 |
           | a02 a06 a10 a14 |
           | a03 a07 a11 a15 |





행기준 변환행렬 A에 의해 절점 P(x,y,z,w) 가 새로운 절점 P'(x',y',z',w') 로 변환하는 과정을 살펴보죠. 고등학교 때 배웠듯이 행렬의 곱셈이 성립하려면 행과 열의 갯수가 같아야 하므로 다음과 같이 적어줍니다. (행렬의 어떤 요소끼리 곱하는지 손가락으로 짚으면서 보세요.)

 

  | x' y' z' w' | =

 

  | x  y  z  w  | × | a00 a01 a02 a03 |
                     | a04 a05 a06 a07 |
                     | a08 a09 a10 a11 |
                     | a12 a13 a14 a15 |

 

  x' = x*a00 + y*a04 + z*a08 + w*a12
  y' = x*a01 + y*a05 + z*a09 + w*a13
  z' = x*a02 + y*a06 + z*a10 + w*a14
  w' = x*a03 + y*a07 + z*a11 + w*a15

 

 원래 열기준 행렬은 절점, 또는 벡터를 표현하는 행렬을 세로, 즉 열로 표현하기 위해 사용합니다. 벡터 V(x,y,z,w) 에 변환행렬이 적용된 새로운 벡터 V'를 계산하는 과정을 열기준 행렬로 표현할 때는 다음과 같이 적어 줍니다.

 

  | x' |   | a00 a04 a08 a12 |    | x |
  | y' | = | a01 a05 a09 a13 | × | y |
  | z' |   | a02 a06 a10 a14 |    | z |
  | w' |   | a03 a07 a11 a15 |    | w |

 

 풀어보면 다음과 같습죠. (손가락을 짚으면서 보세요.)

 

  x' = a00*x + a04*y + a08*z + a12*w
  y' = a01*x + a05*y + a09*z + a13*w
  z' = a02*x + a06*y + a10*z + a14*w
  w' = a03*x + a07*y + a11*z + a15*w ... ①

 

 비교해 보나 마나 같은 결과 입니다. 



 OpenGL에서는 ① 에서의 방법으로 행렬을 표시하고 곱해주네요



반응형

http://www.gpgstudy.com/forum/viewtopic.php?topic=7585


Backface Culling에 대한 설명이 좀 부족한듯 싶어서, 설명을 추가해봅니다. 


후면 추리기를 할때 삼각형의 앞면이 어느 방향인지를 알아야 합니다. 


삼각형이 V0, V1, V2 3개의 정점으로 이루어 져있을때, 


삼각형의 법선 벡터를 일반적으로 (V1 - V0) X (V2 - V1) 이렇게 구합니다. 


이 삼각형의 법선 벡터와 카메라 벡터의 사이각이 


90보다 클때 삼각형이 보인다고 판단합니다. (내적의 값이 0보다 작을때) 


그런데 외적의 결과가 왼손 좌표계와 오른손 좌표계에서 서로 반대입니다. 

(Direct3D는 왼손 좌표게를 OpenGL은 오른손 좌표계를 씁니다.) 


삼각형의 법선 벡터가 카메라 벡터와 반대방향이 되면 


왼손 좌표게에서는 카메라에서 봤을때 정점들의 순서가 시계방향이 되고, 


오른손 좌표계에서는 정점들의 순서가 반시계방향이 됩니다. 



반응형

http://mgun.tistory.com/398



이전의 오일러랑 같은역활을 하긴 하지만 
오일러의 단점을 보완하는 쿼터니온이 상당히 중요하다.
오일러의 단점으로 보면
각 축에 대한 회전의 적용순서가 다양하여 순서가 다르면 결과가 달라져 혼란을 야기한다.
- 회전자유도가 3이지만 첫번째 회전축과 세번째 회전축이 거의 일치될 때 회전 자유도가
  하나 감소하는 짐벌락 현상이 발생한다. 
- 회전을 오일러 각도로 표시하면 각 회전에 대한 오일러 각도가 유일하지 않다.
 - 두 오일러각도의 보간이 유일하지 않다.(보간경로의 문제)

이러한 단점을 보완하기 위해 쿼터니온을 사용한다.
사원수는 3차원에 적용하여 공간에서의 방향을 표현한다.

사원수의 장점
- 한 사원수는 하나의 4차원 벡터이고 3차원 공간에서의 한 방향을 표시
- 사원수는 단위벡터
사원수를 행렬로 또는 행렬을 사원수로 쉽게 바꿀 수 있다.
두 사원수를 곱하는 것이 행렬을 곱하는 것보다 더 빠르다
- 두 임의의 방향에 대한 선형보간 또는 구형선형보간이 쉽게 가능하다.

선형보간 
두 벡터들을 선형식으로 보간하여 현재 위치에서 벡터들을 계산.
- 두 점 사이의 최단 직선을 따라 동일한 속도로 이동하는 형태
- 두 점이 사원수라면 단위초구상에 존재, 단위 초구상을 따라 움직이는 두사원수의 최단경로는 
   단위 초구상에서의 두점을 잇는 원호가 된다.

구형선형보간
원호상에서의 등간격 보간.
초구상에는 동일한 회전에 해당하는 사원수가 2개씩 있어 보간시 경로가 가까운 쪽으로의 slerp를 선택하면 된다.
- 짧은경로를 선택하는 방법은 두 벡터를 내적하여 양수면 90도 미만이므로 짧은경로인 것을 알 수 있다.

선형보간과 구형선형보간의 차이
- 한 사원수에서 다른 사원수로 부드럽게 바꾸기 위해 t를 0에서 1로 바꾸면서 보간한다.
  선형보간은 두 사원수를 잇는 직선을 일정 간격으로 진행하면서 사원수들을 구하게 된다.
  구형선형보간은 두 사원수를 잇는 원호를 일정간격으로 진행하면서 사원수들을 구한다.
  그래서 선형보간일 경우 직선상에서는 일정간격이지만 원호상에서는 움직임이 동일간격이 아니며,
  두 점의 중간지점에 가까울수록 이동하는 속도가 빨라지지만 구형선형보간은 이러한 일이 없이 일정한 속도
로 움직인다.

사원수 관련 함수들
D3DXQuaternionIdentity : 단위사원수 만들기 (0,0,0,1)
D3DXQuaternionConjugate : 켤레사원수 만들기
D3DXQuaternionNormalize : 입력사원수를 단위사원수로 만들어 리턴
D3DXQuaternionInverse : 역사원수 만듬(켤레사원수를 정규화한 결과)
D3DXQuaternionMultiply : 두 사원수의 곱
D3DXQuaternionSlerp : 두 사원수를 Slerp 보간
D3DXQuaternionRotationAxis : 벡터 v를 회전으로 하여 사원수 q를 각도 angle만큼 회전.
                                           이 회전에 해당하는 사원수를 구할려면 q를 단위사원수(0,0,0,1)로 지정.
D3DXQuaternionRotationMatrix : 행렬 m에 해당하는 사원수를 만들어 리턴
D3DXMatrixRotationQuaternion : 사원수 q에 해당하는 회전행렬을 만들어 행렬 m 리턴
D3DXQuaternionRotationYawPitchRoll : yaw, pitch, roll로 사원수를 만들어 리턴

뷰행렬
void CameraQuaternion::GetViewMatrix(D3DXMATRIX* vmat)
{
 // 뷰행렬
 if(IsUpdate_)
 {
  // 1. 이동 - 카메라를 원점으로 이동 - 회전방향이 반대가 되도록 켤레사원수를 사용
  D3DXMATRIX matTranslation;
  D3DXMatrixTranslation(&matTranslation, -pos_.x, -pos_.y, -pos_.z);

  // 2. 회전 - 카메라 방향이 월드좌표계의 좌표축에 일치하도록 회전.
  D3DXMATRIX matRotation;
  D3DXMatrixRotationQuaternion(&matRotation, 
   &D3DXQUATERNION(-orientation_.x, -orientation_.y, -orientation_.z, orientation_.w));

  // 3. 회전과 이동을 적용
  D3DXMatrixMultiply(&view_, &matTranslation, &matRotation);
  IsUpdate_ = false;
 }

 (*vmat) = view_;
}

이동
void CameraQuaternion::Walk(float fUnits)
{
 // z축
 D3DXVECTOR3 look;
 look.x = view_._13;
 look.y = view_._23;
 look.z = view_._33;

 if(ECT_WALKER == cameraType_)
  look.y = 0.0f;

 pos_ += look * fUnits * moveSpeed_;
 IsUpdate_ = true;
}

위치
void CameraQuaternion::Pitch(float fAngle)
{
 fAngle *= (rotateSpeed_ / 60);

 // right 방향으로 회전
 D3DXQUATERNION rot;

 // 사원수로 right 벡터를 구해서 주어진 각도만큼 right 벡터방향으로 회전하는 사원수 rot를 구한다.
 D3DXQuaternionRotationAxis(&rot, TransformAxis(&orientation_, &D3DXVECTOR3(1.0f, 0.0f, 0.0f)), fAngle);

 orientation_ *= rot; // 카메라 방향인 orientation 사원수에 rot 사원수를 곱하여 회전효과를 만든다.

 D3DXQuaternionNormalize(&orientation_, &orientation_); // 사원수 정규화.
 IsUpdate_ = true;
}

보간
bool CameraQuaternion::Slerp(D3DXQUATERNION* quatTarget)
{
 // 두 방향 사이를 부드럽게 보간(sphere linear interpolation)
 if(orientation_ == * quatTarget)
  return false;

 // 두 사원수 orientation과 quatTarget을 slerpSpeed(0~1)사이의 값으로 Slerp 보간.
 D3DXQuaternionSlerp(&orientation_, &orientation_, quatTarget, slerpSpeed_);
 D3DXQuaternionNormalize(&orientation_, &orientation_);
 IsUpdate_ = true;
 return true;
}

fx는 동일하다.



반응형

+ Recent posts